diff --git a/.github/actions/install-go-and-deps/action.yml b/.github/actions/install-go-and-deps/action.yml index 7a174cf506..b866c7fa6a 100644 --- a/.github/actions/install-go-and-deps/action.yml +++ b/.github/actions/install-go-and-deps/action.yml @@ -4,7 +4,7 @@ inputs: go-version: description: Go Version required: true - default: "~1.20" + default: "~1.21" runs: using: composite steps: diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 12a9a17cc9..9c0ef2b2d5 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -14,12 +14,12 @@ jobs: id-token: write packages: write pull-requests: write - timeout-minutes: 60 + timeout-minutes: 90 steps: - name: Maximize build space uses: easimon/maximize-build-space@v8 with: - root-reserve-mb: 20480 + root-reserve-mb: 30720 swap-size-mb: 4096 remove-dotnet: true remove-android: true diff --git a/.goreleaser.release.yml b/.goreleaser.release.yml index b42ad6f330..97747764b7 100644 --- a/.goreleaser.release.yml +++ b/.goreleaser.release.yml @@ -120,10 +120,14 @@ snapcrafts: plugs: [home, network, network-bind] command: ttn-lw-stack.wrapper completer: config/completion/bash/ttn-lw-stack + environment: + XDG_CACHE_HOME: $SNAP_USER_COMMON ttn-lw-cli: plugs: [home, network, network-bind] command: ttn-lw-cli.wrapper completer: config/completion/bash/ttn-lw-cli-snap + environment: + XDG_CACHE_HOME: $SNAP_USER_COMMON brews: - name: ttn-lw-stack diff --git a/CHANGELOG.md b/CHANGELOG.md index 528e098353..f23ea50c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,50 @@ with the exception that this project **does not** follow Semantic Versioning. For details about compatibility between different releases, see the **Commitments and Releases** section of our README. -## [3.28.0] - unreleased +## [Unreleased] + +### Added + +- Rate limiting classes for individual HTTP paths. +- Rate limiting keys for HTTP endpoints now contain the caller API key ID when available. The caller IP is still available as a fallback. +- Allow users to set multiple frequency plans only in the same band in the Console. + +### Changed + +- Server side events replaced with single socket connection using the native WebSocket API. +- Gateways now disconnect if the Gateway Server address has changed. + - This enables CUPS-enabled gateways to change their LNS before the periodic CUPS lookup occurs. +- The LoRa Basics Station discovery endpoint now verifies the authorization credentials of the caller. + - This enables the gateways to migrate to another instance gracefully while using CUPS. + +### Deprecated + +### Removed + +### Fixed + +- Batch gateway rights assertions when multiple membership chains are available (for example, both via a user and an organization). + +### Security + +## [3.28.1] - 2023-11-27 + +### Added + +- The `http.client.transport.compression` experimental flag. It controls whether the HTTP clients used by the stack support gzip and zstd decompression of server responses. It is enabled by default. +- The `http.server.transport.compression` experimental flag. It controls whether the HTTP servers used by the stack support gzip compression of the server response. It is enabled by default. + +### Changed + +- The Things Stack is now built with Go 1.21. +- Statistics for gateways are now fetched in a single request. + +### Fixed + +- Resolve scroll jumps when selecting different tabs of a table in the Console. +- `BatchGetGatewayConnectionStats` RPC rights check in certain cases. + +## [3.28.0] - 2023-10-31 ### Added @@ -16,16 +59,18 @@ For details about compatibility between different releases, see the **Commitment - It is now possible to trigger a resending of the email validation email from within the Console. The new action is part of the error screen that users see when they log into the Console without having their contact info validated yet (and the network requires validation before usage). - Updated Japanese translations for the Console and backend. - `--grpc.correlation-ids-ignore-methods` configuration option, which allows certain gRPC methods to be skipped from the correlation ID middleware which adds a correlation ID with the name of the gRPC method. Methods bear the format used by `--grpc.log-ignore-methods`, such as `/ttn.lorawan.v3.GsNs/HandleUplink`. +- Support for setting multiple frequency plans for gateways from the Console. +- The `ns-db purge` command to purge unused data from the Network Server database. ### Changed - Users can now request a new email for the account validation from time to time instead of once per validation, the interval between email requests is determined by `is.user-registration.contact-info-validation.retry-interval` and by default it is an hour. - Traffic related correlation IDs have been simplified. Previously one correlation ID per component was added as traffic passed through different stack components. Now a singular correlation ID relating to the entry point of the message will be added (such as `gs:uplink:xxx` for uplinks, or `as:downlink:xxx` for downlinks), and subsequent components will no longer add any extra correlation IDs (such as `ns:uplink:xxx` or `as:up:xxx`). The uplink entry points are `pba` and `gs`, while the downlink entry points are `pba`, `ns` and `as`. - Packet Broker Agent uplink tokens are now serialized in a more efficient manner. - -### Deprecated - -### Removed +- The Network Server now stores only the most recent uplinks tokens. +- The Application Server webhook health system now records failures only every retry interval while in monitor mode, as opposed to recording every failure. + - Monitor mode in this context refers to situations in which either `--as.webhooks.unhealthy-attempts-threshold` or `--as.webhooks.unhealthy-retry-interval` are less or equal to zero. In such situations, the Application Server will record failures but will not stop the execution of the webhooks. + - Using a retry interval of zero and a non zero attempts threshold restores the previous behavior. ### Fixed @@ -33,8 +78,8 @@ For details about compatibility between different releases, see the **Commitment - Gateway registration without gateway EUI not working. - Listing deleted entities is now fixed for both admin and standard users, which previously returned an `account_not_found` error. - Update to an user's `PrimaryEmailAddress` via a non admin now invalidates the `PrimaryEmailAddressValidatedAt` as it was intended. - -### Security +- Negative number support in Cayenne LPP. +- Fix panic in snapcraft CLI deployment, commands will no longer generate a panic error message when telemetry is enabled. ## [3.27.2] - 2023-09-14 @@ -2688,7 +2733,9 @@ For details about compatibility between different releases, see the **Commitment NOTE: These links should respect backports. See https://github.com/TheThingsNetwork/lorawan-stack/pull/1444/files#r333379706. --> -[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.27.2...v3.27 +[unreleased]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.28.1...v3.28 +[3.28.1]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.28.0...v3.28.1 +[3.28.0]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.27.2...v3.28.0 [3.27.2]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.27.1...v3.27.2 [3.27.1]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.27.0...v3.27.1 [3.27.0]: https://github.com/TheThingsNetwork/lorawan-stack/compare/v3.26.2...v3.27.0 diff --git a/CODEOWNERS b/CODEOWNERS index 51685c5e3a..7db3cff7ca 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,97 +1,97 @@ # Root -/** @johanstokking @adriansmares -/CODEOWNERS @johanstokking -/LICENSE @johanstokking +/** @TheThingsNetwork/stack-reviewers-1 +/CODEOWNERS @TheThingsNetwork/stack-reviewers-2 +/LICENSE @TheThingsNetwork/stack-reviewers-2 /CHANGELOG.md # Clear common folders /pkg # Dependencies -/go.mod @johanstokking @adriansmares -/go.sum @johanstokking @adriansmares -/package.json @kschiffer @ryaplots -/yarn.lock @kschiffer @ryaplots @mjamescompton -/sdk/js/package.json @kschiffer @ryaplots @mjamescompton -/sdk/js/yarn.lock @kschiffer @ryaplots @mjamescompton +/go.mod @TheThingsNetwork/stack-reviewers-1 +/go.sum @TheThingsNetwork/stack-reviewers-1 +/package.json @TheThingsNetwork/stack-reviewers-3 +/yarn.lock @TheThingsNetwork/stack-reviewers-3 +/sdk/js/package.json @TheThingsNetwork/stack-reviewers-3 +/sdk/js/yarn.lock @TheThingsNetwork/stack-reviewers-3 # Build pipeline and tooling -/Makefile @adriansmares -/tools @adriansmares -/.github/workflows @adriansmares -/config @kschiffer @ryaplots @mjamescompton -/config/stack @benolayinka @KrishnaIyer -/cypress @kschiffer @ryaplots @mjamescompton +/Makefile @TheThingsNetwork/stack-reviewers-4 +/tools @TheThingsNetwork/stack-reviewers-4 +/.github/workflows @TheThingsNetwork/stack-reviewers-4 +/config @TheThingsNetwork/stack-reviewers-3 +/config/stack @TheThingsNetwork/stack-reviewers-5 +/cypress @TheThingsNetwork/stack-reviewers-3 # API, configuration, CLI and storage compatibility -/api/*.proto @johanstokking @adriansmares -/cmd @adriansmares -/pkg/**/config.go @adriansmares -/pkg/**/registry.go @adriansmares -/pkg/config/shared.go @adriansmares -/pkg/goproto @johanstokking @adriansmares -/pkg/identityserver/store @johanstokking @adriansmares -/pkg/jsonpb @johanstokking @adriansmares -/pkg/ttnpb @johanstokking @adriansmares +/api/*.proto @TheThingsNetwork/stack-reviewers-1 +/cmd @TheThingsNetwork/stack-reviewers-4 +/pkg/**/config.go @TheThingsNetwork/stack-reviewers-4 +/pkg/**/registry.go @TheThingsNetwork/stack-reviewers-4 +/pkg/config/shared.go @TheThingsNetwork/stack-reviewers-4 +/pkg/goproto @TheThingsNetwork/stack-reviewers-1 +/pkg/identityserver/store @TheThingsNetwork/stack-reviewers-1 +/pkg/jsonpb @TheThingsNetwork/stack-reviewers-1 +/pkg/ttnpb @TheThingsNetwork/stack-reviewers-1 # Security -/pkg/auth @johanstokking @adriansmares -/pkg/crypto @johanstokking @adriansmares +/pkg/auth @TheThingsNetwork/stack-reviewers-1 +/pkg/crypto @TheThingsNetwork/stack-reviewers-1 # Shared components -/pkg/band @johanstokking @KrishnaIyer -/pkg/cluster @johanstokking @adriansmares -/pkg/component @johanstokking @adriansmares -/pkg/errors @johanstokking @adriansmares -/pkg/events @adriansmares -/pkg/frequencyplans @johanstokking @KrishnaIyer -/pkg/interop @johanstokking @adriansmares -/pkg/rpcmiddleware @johanstokking @adriansmares -/pkg/rpcserver @johanstokking @adriansmares -/pkg/types @johanstokking -/pkg/web @kschiffer @ryaplots @mjamescompton -/pkg/webmiddleware @KrishnaIyer @kschiffer -/pkg/webui @kschiffer @ryaplots @mjamescompton -/pkg/ratelimit @johanstokking @KrishnaIyer +/pkg/band @TheThingsNetwork/stack-reviewers-7 +/pkg/cluster @TheThingsNetwork/stack-reviewers-1 +/pkg/component @TheThingsNetwork/stack-reviewers-1 +/pkg/errors @TheThingsNetwork/stack-reviewers-1 +/pkg/events @TheThingsNetwork/stack-reviewers-4 +/pkg/frequencyplans @TheThingsNetwork/stack-reviewers-7 +/pkg/interop @TheThingsNetwork/stack-reviewers-1 +/pkg/rpcmiddleware @TheThingsNetwork/stack-reviewers-1 +/pkg/rpcserver @TheThingsNetwork/stack-reviewers-1 +/pkg/types @TheThingsNetwork/stack-reviewers-2 +/pkg/web @TheThingsNetwork/stack-reviewers-3 +/pkg/webmiddleware @TheThingsNetwork/stack-reviewers-8 +/pkg/webui @TheThingsNetwork/stack-reviewers-3 +/pkg/ratelimit @TheThingsNetwork/stack-reviewers-7 # Subsystems -/pkg/identityserver @adriansmares @nicholaspcr -/pkg/email @kschiffer @nicholaspcr -/pkg/oauth @kschiffer @nicholaspcr -/pkg/account @kschiffer @nicholaspcr -/pkg/web/oauthclient @kschiffer @nicholaspcr +/pkg/identityserver @TheThingsNetwork/stack-reviewers-9 +/pkg/email @TheThingsNetwork/stack-reviewers-10 +/pkg/oauth @TheThingsNetwork/stack-reviewers-10 +/pkg/account @TheThingsNetwork/stack-reviewers-10 +/pkg/web/oauthclient @TheThingsNetwork/stack-reviewers-10 -/pkg/gatewayserver @johanstokking @KrishnaIyer @adriansmares -/pkg/gatewayconfigurationserver @KrishnaIyer @adriansmares -/pkg/pfconfig @KrishnaIyer @adriansmares -/pkg/basicstation @KrishnaIyer @adriansmares +/pkg/gatewayserver @TheThingsNetwork/stack-reviewers-11 +/pkg/gatewayconfigurationserver @TheThingsNetwork/stack-reviewers-12 +/pkg/pfconfig @TheThingsNetwork/stack-reviewers-12 +/pkg/basicstation @TheThingsNetwork/stack-reviewers-12 -/pkg/networkserver @johanstokking @adriansmares -/pkg/specification/macspec @johanstokking @adriansmares -/pkg/encoding/lorawan @johanstokking @adriansmares +/pkg/networkserver @TheThingsNetwork/stack-reviewers-1 +/pkg/specification/macspec @TheThingsNetwork/stack-reviewers-1 +/pkg/encoding/lorawan @TheThingsNetwork/stack-reviewers-1 -/pkg/applicationserver @johanstokking @adriansmares @KrishnaIyer -/pkg/messageprocessors @johanstokking @adriansmares @KrishnaIyer -/pkg/scripting @johanstokking @adriansmares @KrishnaIyer +/pkg/applicationserver @TheThingsNetwork/stack-reviewers-11 +/pkg/messageprocessors @TheThingsNetwork/stack-reviewers-11 +/pkg/scripting @TheThingsNetwork/stack-reviewers-11 -/pkg/joinserver @johanstokking @adriansmares +/pkg/joinserver @TheThingsNetwork/stack-reviewers-1 -/pkg/console @kschiffer @ryaplots @mjamescompton +/pkg/console @TheThingsNetwork/stack-reviewers-3 -/pkg/packetbrokeragent @johanstokking @adriansmares +/pkg/packetbrokeragent @TheThingsNetwork/stack-reviewers-1 -/pkg/devicetemplateconverter @adriansmares @KrishnaIyer -/pkg/devicetemplates @adriansmares @KrishnaIyer -/pkg/qrcode @adriansmares @KrishnaIyer -/pkg/qrcodegenerator @adriansmares @KrishnaIyer +/pkg/devicetemplateconverter @TheThingsNetwork/stack-reviewers-12 +/pkg/devicetemplates @TheThingsNetwork/stack-reviewers-12 +/pkg/qrcode @TheThingsNetwork/stack-reviewers-12 +/pkg/qrcodegenerator @TheThingsNetwork/stack-reviewers-12 -/pkg/deviceclaimingserver @nicholaspcr @KrishnaIyer +/pkg/deviceclaimingserver @TheThingsNetwork/stack-reviewers-13 -/pkg/devicerepository @adriansmares @KrishnaIyer +/pkg/devicerepository @TheThingsNetwork/stack-reviewers-12 # SDKs -/sdk/js @kschiffer @ryaplots @mjamescompton +/sdk/js @TheThingsNetwork/stack-reviewers-3 # Clear generated code /api/api.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51aaa51558..3b59b591f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,11 +2,11 @@ Thank you for your interest in building this thing together with us. We're really happy with our active community and are glad that you're a part of it. There are many ways to contribute to our project, but given the fact that you're on Github looking at the code for The Things Stack for LoRaWAN, you're probably here for one of the following reasons: -- **Asking a question**: If you have questions, please use the [forum](https://www.thethingsnetwork.org/forum/). We have a special [category for The Things Stack](https://www.thethingsnetwork.org/forum/c/network-and-routing/v3). +- **Asking a question**: If you have questions, please use the [forum](https://www.thethingsnetwork.org/forum/). We have a special [category for The Things Stack](https://www.thethingsnetwork.org/forum/c/ttn-network/v3/90). - **Requesting a new feature**: If you have a great idea or think some functionality is missing, we want to know! The only thing you have to do for that is to [create an issue](https://github.com/TheThingsNetwork/lorawan-stack/issues) if it doesn't exist yet. Please use the issue template and fill out all sections. - **Reporting an issue**: If you notice that a component of The Things Stack is not behaving as it should, there may be a bug in our systems. In this case you should [create an issue](https://github.com/TheThingsNetwork/lorawan-stack/issues) if it doesn't exist yet. Please use the issue template and fill out all sections. For sensitive (security) issues, you can [contact us directly](#security-issues). - **Implementing a new feature or fixing a bug**: If you see an [open issue](https://github.com/TheThingsNetwork/lorawan-stack/issues) that you would like to work on, let the other contributors know by commenting in the issue. -- **Writing documentation**: If you see that our documentation is lacking or incorrect, it would be great if you could help us improve it. This will help users and fellow contributors understand how to better work with our stack. Better documentation helps prevent making mistakes and introducing new bugs. Our documentation is spread across a number of places. Code documentation obviously lives together with the code, and is therefore probably in this repository. User documentation for The Things Stack that is published on [thethingsstack.io](https://thethingsstack.io), is built from the [`lorawan-stack-docs` repository]https://github.com/TheThingsIndustries/lorawan-stack-docs. More general documentation can be found on [The Things Network's official documentation pages](https://www.thethingsnetwork.org/docs). The source files for that documentation can be found in [the `docs` repository](https://github.com/TheThingsNetwork/docs). +- **Writing documentation**: If you see that our documentation is lacking or incorrect, it would be great if you could help us improve it. This will help users and fellow contributors understand how to better work with our stack. Better documentation helps prevent making mistakes and introducing new bugs. Our documentation is spread across a number of places. Code documentation obviously lives together with the code, and is therefore probably in this repository. User documentation that is published on [the official The Things Stack documentation page](https://thethingsstack.io), is built from the [`lorawan-stack-docs` repository](https://github.com/TheThingsIndustries/lorawan-stack-docs). More general documentation can be found on [The Things Network's official documentation pages](https://www.thethingsnetwork.org/docs). The source files for that documentation can be found in [the `docs` repository](https://github.com/TheThingsNetwork/docs). If you'd like to contribute by writing code, you'll find [here](DEVELOPMENT.md) how to set up your development environment. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 203f295ed0..da49a6094b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -675,7 +675,7 @@ To decide whether a component is a container component, ask yourself: - Is this component more concerned with how things work, rather than how things look? - Does this component connect to the store? - Does this component fetch or send data? -- Is the component generated by higher order components (e.g. `withFeatureRequirement`)? +- Is the component generated by higher order components? - Does this component render simple nodes, like a single presentational component? If you can answer more than 2 questions with yes, then you likely have a container component. @@ -692,7 +692,6 @@ View components always represent a single view of the application, represented b - Fetching necessary data (via `withRequest` HOC), if not done by a container - Unavailable "catch-all"-routes are caught by `` component, including subviews - Errors should be caught by the `` error boundary component -- `withFeatureRequirement` HOC is used to prevent access to routes that the user has no rights for - Ensured responsiveness and usage of the grid system #### Utility components diff --git a/api/ttn/lorawan/v3/api.md b/api/ttn/lorawan/v3/api.md index 37477641cc..05beb4b4f7 100644 --- a/api/ttn/lorawan/v3/api.md +++ b/api/ttn/lorawan/v3/api.md @@ -273,8 +273,14 @@ - [Message `MACState.UplinkMessage`](#ttn.lorawan.v3.MACState.UplinkMessage) - [Message `MACState.UplinkMessage.RxMetadata`](#ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata) - [Message `MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata`](#ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata) + - [Message `MACState.UplinkMessage.RxMetadata.RelayMetadata`](#ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.RelayMetadata) - [Message `MACState.UplinkMessage.TxSettings`](#ttn.lorawan.v3.MACState.UplinkMessage.TxSettings) + - [Message `RelayParameters`](#ttn.lorawan.v3.RelayParameters) + - [Message `RelayUplinkForwardingRule`](#ttn.lorawan.v3.RelayUplinkForwardingRule) - [Message `ResetAndGetEndDeviceRequest`](#ttn.lorawan.v3.ResetAndGetEndDeviceRequest) + - [Message `ServedRelayParameters`](#ttn.lorawan.v3.ServedRelayParameters) + - [Message `ServingRelayForwardingLimits`](#ttn.lorawan.v3.ServingRelayForwardingLimits) + - [Message `ServingRelayParameters`](#ttn.lorawan.v3.ServingRelayParameters) - [Message `Session`](#ttn.lorawan.v3.Session) - [Message `SetEndDeviceRequest`](#ttn.lorawan.v3.SetEndDeviceRequest) - [Message `UpdateEndDeviceRequest`](#ttn.lorawan.v3.UpdateEndDeviceRequest) @@ -472,6 +478,19 @@ - [Message `MACCommand.RejoinParamSetupReq`](#ttn.lorawan.v3.MACCommand.RejoinParamSetupReq) - [Message `MACCommand.RekeyConf`](#ttn.lorawan.v3.MACCommand.RekeyConf) - [Message `MACCommand.RekeyInd`](#ttn.lorawan.v3.MACCommand.RekeyInd) + - [Message `MACCommand.RelayConfAns`](#ttn.lorawan.v3.MACCommand.RelayConfAns) + - [Message `MACCommand.RelayConfReq`](#ttn.lorawan.v3.MACCommand.RelayConfReq) + - [Message `MACCommand.RelayConfReq.Configuration`](#ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration) + - [Message `MACCommand.RelayConfigureFwdLimitAns`](#ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitAns) + - [Message `MACCommand.RelayConfigureFwdLimitReq`](#ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq) + - [Message `MACCommand.RelayCtrlUplinkListAns`](#ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListAns) + - [Message `MACCommand.RelayCtrlUplinkListReq`](#ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListReq) + - [Message `MACCommand.RelayEndDeviceConfAns`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfAns) + - [Message `MACCommand.RelayEndDeviceConfReq`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq) + - [Message `MACCommand.RelayEndDeviceConfReq.Configuration`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration) + - [Message `MACCommand.RelayNotifyNewEndDeviceReq`](#ttn.lorawan.v3.MACCommand.RelayNotifyNewEndDeviceReq) + - [Message `MACCommand.RelayUpdateUplinkListAns`](#ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListAns) + - [Message `MACCommand.RelayUpdateUplinkListReq`](#ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListReq) - [Message `MACCommand.ResetConf`](#ttn.lorawan.v3.MACCommand.ResetConf) - [Message `MACCommand.ResetInd`](#ttn.lorawan.v3.MACCommand.ResetInd) - [Message `MACCommand.RxParamSetupAns`](#ttn.lorawan.v3.MACCommand.RxParamSetupAns) @@ -484,6 +503,15 @@ - [Message `Message`](#ttn.lorawan.v3.Message) - [Message `PingSlotPeriodValue`](#ttn.lorawan.v3.PingSlotPeriodValue) - [Message `RejoinRequestPayload`](#ttn.lorawan.v3.RejoinRequestPayload) + - [Message `RelayEndDeviceAlwaysMode`](#ttn.lorawan.v3.RelayEndDeviceAlwaysMode) + - [Message `RelayEndDeviceControlledMode`](#ttn.lorawan.v3.RelayEndDeviceControlledMode) + - [Message `RelayEndDeviceDynamicMode`](#ttn.lorawan.v3.RelayEndDeviceDynamicMode) + - [Message `RelayForwardDownlinkReq`](#ttn.lorawan.v3.RelayForwardDownlinkReq) + - [Message `RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) + - [Message `RelayForwardUplinkReq`](#ttn.lorawan.v3.RelayForwardUplinkReq) + - [Message `RelaySecondChannel`](#ttn.lorawan.v3.RelaySecondChannel) + - [Message `RelayUplinkForwardLimits`](#ttn.lorawan.v3.RelayUplinkForwardLimits) + - [Message `RelayUplinkToken`](#ttn.lorawan.v3.RelayUplinkToken) - [Message `RxDelayValue`](#ttn.lorawan.v3.RxDelayValue) - [Message `TxRequest`](#ttn.lorawan.v3.TxRequest) - [Message `TxSettings`](#ttn.lorawan.v3.TxSettings) @@ -510,6 +538,13 @@ - [Enum `RejoinPeriodExponent`](#ttn.lorawan.v3.RejoinPeriodExponent) - [Enum `RejoinRequestType`](#ttn.lorawan.v3.RejoinRequestType) - [Enum `RejoinTimeExponent`](#ttn.lorawan.v3.RejoinTimeExponent) + - [Enum `RelayCADPeriodicity`](#ttn.lorawan.v3.RelayCADPeriodicity) + - [Enum `RelayCtrlUplinkListAction`](#ttn.lorawan.v3.RelayCtrlUplinkListAction) + - [Enum `RelayLimitBucketSize`](#ttn.lorawan.v3.RelayLimitBucketSize) + - [Enum `RelayResetLimitCounter`](#ttn.lorawan.v3.RelayResetLimitCounter) + - [Enum `RelaySecondChAckOffset`](#ttn.lorawan.v3.RelaySecondChAckOffset) + - [Enum `RelaySmartEnableLevel`](#ttn.lorawan.v3.RelaySmartEnableLevel) + - [Enum `RelayWORChannel`](#ttn.lorawan.v3.RelayWORChannel) - [Enum `RxDelay`](#ttn.lorawan.v3.RxDelay) - [Enum `TxSchedulePriority`](#ttn.lorawan.v3.TxSchedulePriority) - [File `ttn/lorawan/v3/messages.proto`](#ttn/lorawan/v3/messages.proto) @@ -542,6 +577,7 @@ - [Message `Location`](#ttn.lorawan.v3.Location) - [Message `PacketBrokerMetadata`](#ttn.lorawan.v3.PacketBrokerMetadata) - [Message `PacketBrokerRouteHop`](#ttn.lorawan.v3.PacketBrokerRouteHop) + - [Message `RelayMetadata`](#ttn.lorawan.v3.RelayMetadata) - [Message `RxMetadata`](#ttn.lorawan.v3.RxMetadata) - [Enum `LocationSource`](#ttn.lorawan.v3.LocationSource) - [File `ttn/lorawan/v3/mqtt.proto`](#ttn/lorawan/v3/mqtt.proto) @@ -2532,6 +2568,8 @@ PeerInfo | `max_retransmit_timeout` | [`google.protobuf.Duration`](#google.protobuf.Duration) | | | | `tx_offset` | [`float`](#float) | repeated | | | `max_adr_data_rate_index` | [`DataRateIndex`](#ttn.lorawan.v3.DataRateIndex) | | | +| `relay_forward_delay` | [`google.protobuf.Duration`](#google.protobuf.Duration) | | | +| `relay_receive_delay` | [`google.protobuf.Duration`](#google.protobuf.Duration) | | | | `tx_param_setup_req_support` | [`bool`](#bool) | | | | `default_max_eirp` | [`float`](#float) | | | | `default_rx2_parameters` | [`BandDescription.Rx2Parameters`](#ttn.lorawan.v3.BandDescription.Rx2Parameters) | | | @@ -2612,6 +2650,7 @@ PeerInfo | `base_id` | [`string`](#string) | | The ID of the frequency that the current frequency plan is based on. | | `name` | [`string`](#string) | | | | `base_frequency` | [`uint32`](#uint32) | | Base frequency in MHz for hardware support (433, 470, 868 or 915) | +| `band_id` | [`string`](#string) | | | ### Message `GetPhyVersionsRequest` @@ -2676,6 +2715,7 @@ PeerInfo | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `base_frequency` | [`uint32`](#uint32) | | Optional base frequency in MHz for hardware support (433, 470, 868 or 915) | +| `band_id` | [`string`](#string) | | Optional Band ID to filter the results. | ### Message `ListFrequencyPlansResponse` @@ -4005,11 +4045,12 @@ This is used internally by the Network Server. | `ping_slot_data_rate_index` | [`DataRateIndex`](#ttn.lorawan.v3.DataRateIndex) | | Data rate index of the class B ping slot. This field is deprecated, use ping_slot_data_rate_index_value instead. | | `beacon_frequency` | [`uint64`](#uint64) | | Frequency of the class B beacon (Hz). | | `channels` | [`MACParameters.Channel`](#ttn.lorawan.v3.MACParameters.Channel) | repeated | Configured uplink channels and optionally Rx1 frequency. | -| `uplink_dwell_time` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether uplink dwell time is set (400ms). If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). | -| `downlink_dwell_time` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether downlink dwell time is set (400ms). If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). | +| `uplink_dwell_time` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether uplink dwell time is set (400ms). If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). | +| `downlink_dwell_time` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether downlink dwell time is set (400ms). If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). | | `adr_ack_limit_exponent` | [`ADRAckLimitExponentValue`](#ttn.lorawan.v3.ADRAckLimitExponentValue) | | ADR: number of messages to wait before setting ADRAckReq. | | `adr_ack_delay_exponent` | [`ADRAckDelayExponentValue`](#ttn.lorawan.v3.ADRAckDelayExponentValue) | | ADR: number of messages to wait after setting ADRAckReq and before changing TxPower or DataRate. | | `ping_slot_data_rate_index_value` | [`DataRateIndexValue`](#ttn.lorawan.v3.DataRateIndexValue) | | Data rate index of the class B ping slot. | +| `relay` | [`RelayParameters`](#ttn.lorawan.v3.RelayParameters) | | Relay parameters. | #### Field Rules @@ -4086,6 +4127,8 @@ This is used internally by the Network Server. | `downlink_dwell_time` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether downlink dwell time is set (400ms). If unset, the default value from Network Server configuration or regional parameters specification will be used. | | `adr` | [`ADRSettings`](#ttn.lorawan.v3.ADRSettings) | | Adaptive Data Rate settings. If unset, the default value from Network Server configuration or regional parameters specification will be used. | | `schedule_downlinks` | [`BoolValue`](#ttn.lorawan.v3.BoolValue) | | Whether or not downlink messages should be scheduled. This option can be used in order to disable any downlink interaction with the end device. It will affect all types of downlink messages: data and MAC downlinks, and join accepts. | +| `relay` | [`RelayParameters`](#ttn.lorawan.v3.RelayParameters) | | The relay parameters the end device is using. If unset, the default value from Network Server configuration or regional parameters specification will be used. | +| `desired_relay` | [`RelayParameters`](#ttn.lorawan.v3.RelayParameters) | | The relay parameters the Network Server should configure device to use via MAC commands. If unset, the default value from Network Server configuration or regional parameters specification will be used. | #### Field Rules @@ -4124,6 +4167,7 @@ This is used internally by the Network Server. | `rejected_data_rate_ranges` | [`MACState.RejectedDataRateRangesEntry`](#ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry) | repeated | Data rate ranges rejected by the device per frequency. | | `last_adr_change_f_cnt_up` | [`uint32`](#uint32) | | Frame counter of uplink, which confirmed the last ADR parameter change. | | `recent_mac_command_identifiers` | [`MACCommandIdentifier`](#ttn.lorawan.v3.MACCommandIdentifier) | repeated | MAC command identifiers sent by the end device in the last received uplink. The Network Server may choose to store only certain types of MAC command identifiers in the underlying implementation. | +| `pending_relay_downlink` | [`RelayForwardDownlinkReq`](#ttn.lorawan.v3.RelayForwardDownlinkReq) | | Pending relay downlink contents. The pending downlink will be scheduled to the relay in either Rx1 or Rx2. The pending downlink will be cleared after the scheduling attempt. | #### Field Rules @@ -4294,6 +4338,7 @@ Used for type safe recent uplink storage. | `downlink_path_constraint` | [`DownlinkPathConstraint`](#ttn.lorawan.v3.DownlinkPathConstraint) | | | | `uplink_token` | [`bytes`](#bytes) | | | | `packet_broker` | [`MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata`](#ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata) | | | +| `relay` | [`MACState.UplinkMessage.RxMetadata.RelayMetadata`](#ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.RelayMetadata) | | | #### Field Rules @@ -4304,6 +4349,8 @@ Used for type safe recent uplink storage. ### Message `MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata` +### Message `MACState.UplinkMessage.RxMetadata.RelayMetadata` + ### Message `MACState.UplinkMessage.TxSettings` | Field | Type | Label | Description | @@ -4316,6 +4363,31 @@ Used for type safe recent uplink storage. | ----- | ----------- | | `data_rate` |

`message.required`: `true`

| +### Message `RelayParameters` + +RelayParameters represent the parameters of a relay. +This is used internally by the Network Server. + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `serving` | [`ServingRelayParameters`](#ttn.lorawan.v3.ServingRelayParameters) | | Parameters related to a relay which is serving end devices. | +| `served` | [`ServedRelayParameters`](#ttn.lorawan.v3.ServedRelayParameters) | | Parameters related to an end device served by a relay. | + +### Message `RelayUplinkForwardingRule` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `limits` | [`RelayUplinkForwardLimits`](#ttn.lorawan.v3.RelayUplinkForwardLimits) | | Bucket configuration for the served end device. If unset, no individual limits will apply to the end device, but the relay global limitations will apply. | +| `last_w_f_cnt` | [`uint32`](#uint32) | | Last wake on radio frame counter used by the served end device. | +| `device_id` | [`string`](#string) | | End device identifier of the served end device. | +| `session_key_id` | [`bytes`](#bytes) | | Session key ID of the session keys used to derive the root relay session key. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `device_id` |

`string.max_len`: `36`

`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

| + ### Message `ResetAndGetEndDeviceRequest` | Field | Type | Label | Description | @@ -4329,6 +4401,52 @@ Used for type safe recent uplink storage. | ----- | ----------- | | `end_device_ids` |

`message.required`: `true`

| +### Message `ServedRelayParameters` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `always` | [`RelayEndDeviceAlwaysMode`](#ttn.lorawan.v3.RelayEndDeviceAlwaysMode) | | The end device will always attempt to use the relay mode in order to send uplink messages. | +| `dynamic` | [`RelayEndDeviceDynamicMode`](#ttn.lorawan.v3.RelayEndDeviceDynamicMode) | | The end device will attempt to use relay mode only after a number of uplink messages have been sent without receiving a valid a downlink message. | +| `end_device_controlled` | [`RelayEndDeviceControlledMode`](#ttn.lorawan.v3.RelayEndDeviceControlledMode) | | The end device will control when it uses the relay mode. This is the default mode. | +| `backoff` | [`uint32`](#uint32) | | Number of uplinks to be sent without a wake on radio frame. | +| `second_channel` | [`RelaySecondChannel`](#ttn.lorawan.v3.RelaySecondChannel) | | Second wake on radio channel configuration. | +| `serving_device_id` | [`string`](#string) | | End device identifier of the serving end device. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `backoff` |

`uint32.lte`: `63`

| +| `serving_device_id` |

`string.max_len`: `36`

`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

| + +### Message `ServingRelayForwardingLimits` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `reset_behavior` | [`RelayResetLimitCounter`](#ttn.lorawan.v3.RelayResetLimitCounter) | | Reset behavior of the buckets upon limit update. | +| `join_requests` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | Bucket configuration for join requests. If unset, no individual limits will apply to join requests, but the relay overall limitations will apply. | +| `notifications` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | Bucket configuration for unknown device notifications. If unset, no individual limits will apply to unknown end device notifications, but the relay overall limitations will still apply. | +| `uplink_messages` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | Bucket configuration for uplink messages across all served end devices. If unset, no individual limits will apply to uplink messages across all served end devices, but the relay overall limitations will still apply. | +| `overall` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | Bucket configuration for all relay messages. If unset, no overall limits will apply to the relay, but individual limitations will still apply. | + +### Message `ServingRelayParameters` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `second_channel` | [`RelaySecondChannel`](#ttn.lorawan.v3.RelaySecondChannel) | | Second wake on radio channel configuration. | +| `default_channel_index` | [`uint32`](#uint32) | | Index of the default wake on radio channel. | +| `cad_periodicity` | [`RelayCADPeriodicity`](#ttn.lorawan.v3.RelayCADPeriodicity) | | Channel activity detection periodicity. | +| `uplink_forwarding_rules` | [`RelayUplinkForwardingRule`](#ttn.lorawan.v3.RelayUplinkForwardingRule) | repeated | Configured uplink forwarding rules. | +| `limits` | [`ServingRelayForwardingLimits`](#ttn.lorawan.v3.ServingRelayForwardingLimits) | | Configured forwarding limits. If unset, the default value from Network Server configuration will be used. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `default_channel_index` |

`uint32.lte`: `255`

| +| `cad_periodicity` |

`enum.defined_only`: `true`

| +| `uplink_forwarding_rules` |

`repeated.max_items`: `16`

| + ### Message `Session` | Field | Type | Label | Description | @@ -5124,7 +5242,7 @@ Identifies an end device model with version information. | Field | Validations | | ----- | ----------- | -| `gateway_ids` |

`repeated.min_items`: `1`

`repeated.max_items`: `20`

| +| `gateway_ids` |

`repeated.min_items`: `1`

`repeated.max_items`: `100`

| | `required` |

`message.required`: `true`

| ### Message `BatchDeleteGatewaysRequest` @@ -6459,6 +6577,17 @@ Only the components for which the keys were meant, will have the key-encryption- | `beacon_freq_ans` | [`MACCommand.BeaconFreqAns`](#ttn.lorawan.v3.MACCommand.BeaconFreqAns) | | | | `device_mode_ind` | [`MACCommand.DeviceModeInd`](#ttn.lorawan.v3.MACCommand.DeviceModeInd) | | | | `device_mode_conf` | [`MACCommand.DeviceModeConf`](#ttn.lorawan.v3.MACCommand.DeviceModeConf) | | | +| `relay_conf_req` | [`MACCommand.RelayConfReq`](#ttn.lorawan.v3.MACCommand.RelayConfReq) | | | +| `relay_conf_ans` | [`MACCommand.RelayConfAns`](#ttn.lorawan.v3.MACCommand.RelayConfAns) | | | +| `relay_end_device_conf_req` | [`MACCommand.RelayEndDeviceConfReq`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq) | | | +| `relay_end_device_conf_ans` | [`MACCommand.RelayEndDeviceConfAns`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfAns) | | | +| `relay_update_uplink_list_req` | [`MACCommand.RelayUpdateUplinkListReq`](#ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListReq) | | | +| `relay_update_uplink_list_ans` | [`MACCommand.RelayUpdateUplinkListAns`](#ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListAns) | | | +| `relay_ctrl_uplink_list_req` | [`MACCommand.RelayCtrlUplinkListReq`](#ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListReq) | | | +| `relay_ctrl_uplink_list_ans` | [`MACCommand.RelayCtrlUplinkListAns`](#ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListAns) | | | +| `relay_configure_fwd_limit_req` | [`MACCommand.RelayConfigureFwdLimitReq`](#ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq) | | | +| `relay_configure_fwd_limit_ans` | [`MACCommand.RelayConfigureFwdLimitAns`](#ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitAns) | | | +| `relay_notify_new_end_device_req` | [`MACCommand.RelayNotifyNewEndDeviceReq`](#ttn.lorawan.v3.MACCommand.RelayNotifyNewEndDeviceReq) | | | #### Field Rules @@ -6757,6 +6886,142 @@ Only the components for which the keys were meant, will have the key-encryption- | ----- | ----------- | | `minor_version` |

`enum.defined_only`: `true`

| +### Message `MACCommand.RelayConfAns` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `second_channel_frequency_ack` | [`bool`](#bool) | | | +| `second_channel_ack_offset_ack` | [`bool`](#bool) | | | +| `second_channel_data_rate_index_ack` | [`bool`](#bool) | | | +| `second_channel_index_ack` | [`bool`](#bool) | | | +| `default_channel_index_ack` | [`bool`](#bool) | | | +| `cad_periodicity_ack` | [`bool`](#bool) | | | + +### Message `MACCommand.RelayConfReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `configuration` | [`MACCommand.RelayConfReq.Configuration`](#ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration) | | | + +### Message `MACCommand.RelayConfReq.Configuration` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `second_channel` | [`RelaySecondChannel`](#ttn.lorawan.v3.RelaySecondChannel) | | | +| `default_channel_index` | [`uint32`](#uint32) | | | +| `cad_periodicity` | [`RelayCADPeriodicity`](#ttn.lorawan.v3.RelayCADPeriodicity) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `default_channel_index` |

`uint32.lte`: `255`

| +| `cad_periodicity` |

`enum.defined_only`: `true`

| + +### Message `MACCommand.RelayConfigureFwdLimitAns` + +### Message `MACCommand.RelayConfigureFwdLimitReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `reset_limit_counter` | [`RelayResetLimitCounter`](#ttn.lorawan.v3.RelayResetLimitCounter) | | | +| `join_request_limits` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | | +| `notify_limits` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | | +| `global_uplink_limits` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | | +| `overall_limits` | [`RelayForwardLimits`](#ttn.lorawan.v3.RelayForwardLimits) | | | + +### Message `MACCommand.RelayCtrlUplinkListAns` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `rule_index_ack` | [`bool`](#bool) | | | +| `w_f_cnt` | [`uint32`](#uint32) | | | + +### Message `MACCommand.RelayCtrlUplinkListReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `rule_index` | [`uint32`](#uint32) | | | +| `action` | [`RelayCtrlUplinkListAction`](#ttn.lorawan.v3.RelayCtrlUplinkListAction) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `rule_index` |

`uint32.lte`: `15`

| + +### Message `MACCommand.RelayEndDeviceConfAns` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `second_channel_frequency_ack` | [`bool`](#bool) | | | +| `second_channel_data_rate_index_ack` | [`bool`](#bool) | | | +| `second_channel_index_ack` | [`bool`](#bool) | | | +| `backoff_ack` | [`bool`](#bool) | | | + +### Message `MACCommand.RelayEndDeviceConfReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `configuration` | [`MACCommand.RelayEndDeviceConfReq.Configuration`](#ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration) | | | + +### Message `MACCommand.RelayEndDeviceConfReq.Configuration` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `always` | [`RelayEndDeviceAlwaysMode`](#ttn.lorawan.v3.RelayEndDeviceAlwaysMode) | | | +| `dynamic` | [`RelayEndDeviceDynamicMode`](#ttn.lorawan.v3.RelayEndDeviceDynamicMode) | | | +| `end_device_controlled` | [`RelayEndDeviceControlledMode`](#ttn.lorawan.v3.RelayEndDeviceControlledMode) | | | +| `backoff` | [`uint32`](#uint32) | | | +| `second_channel` | [`RelaySecondChannel`](#ttn.lorawan.v3.RelaySecondChannel) | | | +| `serving_device_id` | [`string`](#string) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `backoff` |

`uint32.lte`: `63`

| +| `serving_device_id` |

`string.max_len`: `36`

`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

| + +### Message `MACCommand.RelayNotifyNewEndDeviceReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `dev_addr` | [`bytes`](#bytes) | | | +| `snr` | [`int32`](#int32) | | | +| `rssi` | [`int32`](#int32) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `dev_addr` |

`bytes.len`: `4`

| +| `snr` |

`int32.lte`: `11`

`int32.gte`: `-20`

| +| `rssi` |

`int32.lte`: `-15`

`int32.gte`: `-142`

| + +### Message `MACCommand.RelayUpdateUplinkListAns` + +### Message `MACCommand.RelayUpdateUplinkListReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `rule_index` | [`uint32`](#uint32) | | | +| `forward_limits` | [`RelayUplinkForwardLimits`](#ttn.lorawan.v3.RelayUplinkForwardLimits) | | | +| `dev_addr` | [`bytes`](#bytes) | | | +| `w_f_cnt` | [`uint32`](#uint32) | | | +| `root_wor_s_key` | [`bytes`](#bytes) | | | +| `device_id` | [`string`](#string) | | | +| `session_key_id` | [`bytes`](#bytes) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `rule_index` |

`uint32.lte`: `15`

| +| `dev_addr` |

`bytes.len`: `4`

| +| `root_wor_s_key` |

`bytes.len`: `16`

| +| `device_id` |

`string.max_len`: `36`

`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

| + ### Message `MACCommand.ResetConf` | Field | Type | Label | Description | @@ -6919,6 +7184,107 @@ Message represents a LoRaWAN message | `join_eui` |

`bytes.len`: `8`

| | `dev_eui` |

`bytes.len`: `8`

| +### Message `RelayEndDeviceAlwaysMode` + +### Message `RelayEndDeviceControlledMode` + +### Message `RelayEndDeviceDynamicMode` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `smart_enable_level` | [`RelaySmartEnableLevel`](#ttn.lorawan.v3.RelaySmartEnableLevel) | | The number of consecutive uplinks without a valid downlink before the end device attempts to use the relay mode to transmit messages. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `smart_enable_level` |

`enum.defined_only`: `true`

| + +### Message `RelayForwardDownlinkReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `raw_payload` | [`bytes`](#bytes) | | | + +### Message `RelayForwardLimits` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `bucket_size` | [`RelayLimitBucketSize`](#ttn.lorawan.v3.RelayLimitBucketSize) | | The multiplier used to compute the total bucket size for the limits. The multiplier is multiplied by the reload rate in order to compute the total bucket size. | +| `reload_rate` | [`uint32`](#uint32) | | The number of tokens which are replenished in the bucket every hour. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `bucket_size` |

`enum.defined_only`: `true`

| +| `reload_rate` |

`uint32.lte`: `126`

| + +### Message `RelayForwardUplinkReq` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `data_rate` | [`DataRate`](#ttn.lorawan.v3.DataRate) | | | +| `snr` | [`int32`](#int32) | | | +| `rssi` | [`int32`](#int32) | | | +| `wor_channel` | [`RelayWORChannel`](#ttn.lorawan.v3.RelayWORChannel) | | | +| `frequency` | [`uint64`](#uint64) | | Uplink channel frequency (Hz). | +| `raw_payload` | [`bytes`](#bytes) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `data_rate` |

`message.required`: `true`

| +| `snr` |

`int32.lte`: `11`

`int32.gte`: `-20`

| +| `rssi` |

`int32.lte`: `-15`

`int32.gte`: `-142`

| +| `wor_channel` |

`enum.defined_only`: `true`

| +| `frequency` |

`uint64.gte`: `100000`

| + +### Message `RelaySecondChannel` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `ack_offset` | [`RelaySecondChAckOffset`](#ttn.lorawan.v3.RelaySecondChAckOffset) | | The frequency (Hz) offset used for the WOR acknowledgement. | +| `data_rate_index` | [`DataRateIndex`](#ttn.lorawan.v3.DataRateIndex) | | The data rate index used by the WOR and WOR acknowledgement. | +| `frequency` | [`uint64`](#uint64) | | The frequency (Hz) used by the wake on radio message. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `ack_offset` |

`enum.defined_only`: `true`

| +| `data_rate_index` |

`enum.defined_only`: `true`

| +| `frequency` |

`uint64.gte`: `100000`

| + +### Message `RelayUplinkForwardLimits` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `bucket_size` | [`RelayLimitBucketSize`](#ttn.lorawan.v3.RelayLimitBucketSize) | | The multiplier used to compute the total bucket size for the limits. The multiplier is multiplied by the reload rate in order to compute the total bucket size. | +| `reload_rate` | [`uint32`](#uint32) | | The number of tokens which are replenished in the bucket every hour. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `bucket_size` |

`enum.defined_only`: `true`

| +| `reload_rate` |

`uint32.lte`: `62`

| + +### Message `RelayUplinkToken` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `ids` | [`EndDeviceIdentifiers`](#ttn.lorawan.v3.EndDeviceIdentifiers) | | | +| `session_key_id` | [`bytes`](#bytes) | | | +| `full_f_cnt` | [`uint32`](#uint32) | | | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `ids` |

`message.required`: `true`

| + ### Message `RxDelayValue` | Field | Type | Label | Description | @@ -7188,6 +7554,13 @@ Transmission settings for downlink. | `CID_BEACON_TIMING` | 18 | Deprecated | | `CID_BEACON_FREQ` | 19 | | | `CID_DEVICE_MODE` | 32 | | +| `CID_RELAY_CONF` | 64 | | +| `CID_RELAY_END_DEVICE_CONF` | 65 | | +| `CID_RELAY_FILTER_LIST` | 66 | | +| `CID_RELAY_UPDATE_UPLINK_LIST` | 67 | | +| `CID_RELAY_CTRL_UPLINK_LIST` | 68 | | +| `CID_RELAY_CONFIGURE_FWD_LIMIT` | 69 | | +| `CID_RELAY_NOTIFY_NEW_END_DEVICE` | 70 | | ### Enum `MACVersion` @@ -7342,6 +7715,69 @@ Transmission settings for downlink. | `REJOIN_TIME_14` | 14 | Every ~6.4 months. | | `REJOIN_TIME_15` | 15 | Every ~1.1 year. | +### Enum `RelayCADPeriodicity` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_CAD_PERIODICITY_1_SECOND` | 0 | | +| `RELAY_CAD_PERIODICITY_500_MILLISECONDS` | 1 | | +| `RELAY_CAD_PERIODICITY_250_MILLISECONDS` | 2 | | +| `RELAY_CAD_PERIODICITY_100_MILLISECONDS` | 3 | | +| `RELAY_CAD_PERIODICITY_50_MILLISECONDS` | 4 | | +| `RELAY_CAD_PERIODICITY_20_MILLISECONDS` | 5 | sic | + +### Enum `RelayCtrlUplinkListAction` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT` | 0 | | +| `RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE` | 1 | | + +### Enum `RelayLimitBucketSize` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_LIMIT_BUCKET_SIZE_1` | 0 | | +| `RELAY_LIMIT_BUCKET_SIZE_2` | 1 | | +| `RELAY_LIMIT_BUCKET_SIZE_4` | 2 | | +| `RELAY_LIMIT_BUCKET_SIZE_12` | 3 | sic | + +### Enum `RelayResetLimitCounter` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_RESET_LIMIT_COUNTER_ZERO` | 0 | | +| `RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE` | 1 | | +| `RELAY_RESET_LIMIT_COUNTER_MAX_VALUE` | 2 | | +| `RELAY_RESET_LIMIT_COUNTER_NO_RESET` | 3 | | + +### Enum `RelaySecondChAckOffset` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_SECOND_CH_ACK_OFFSET_0` | 0 | 0 kHz | +| `RELAY_SECOND_CH_ACK_OFFSET_200` | 1 | 200 kHz | +| `RELAY_SECOND_CH_ACK_OFFSET_400` | 2 | 400 kHz | +| `RELAY_SECOND_CH_ACK_OFFSET_800` | 3 | 800 kHz | +| `RELAY_SECOND_CH_ACK_OFFSET_1600` | 4 | 1.6 MHz | +| `RELAY_SECOND_CH_ACK_OFFSET_3200` | 5 | 3.2 MHz | + +### Enum `RelaySmartEnableLevel` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_SMART_ENABLE_LEVEL_8` | 0 | | +| `RELAY_SMART_ENABLE_LEVEL_16` | 1 | | +| `RELAY_SMART_ENABLE_LEVEL_32` | 2 | | +| `RELAY_SMART_ENABLE_LEVEL_64` | 3 | | + +### Enum `RelayWORChannel` + +| Name | Number | Description | +| ---- | ------ | ----------- | +| `RELAY_WOR_CHANNEL_DEFAULT` | 0 | | +| `RELAY_WOR_CHANNEL_SECONDARY` | 1 | | + ### Enum `RxDelay` | Name | Number | Description | @@ -7848,6 +8284,20 @@ Mapping from UDP message (other fields can be set in "advanced"): | `receiver_name` | [`string`](#string) | | Receiver of the message. | | `receiver_agent` | [`string`](#string) | | Receiver agent. | +### Message `RelayMetadata` + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `device_id` | [`string`](#string) | | End device identifiers of the relay. | +| `wor_channel` | [`RelayWORChannel`](#ttn.lorawan.v3.RelayWORChannel) | | Wake on radio channel. | + +#### Field Rules + +| Field | Validations | +| ----- | ----------- | +| `device_id` |

`string.max_len`: `36`

`string.pattern`: `^[a-z0-9](?:[-]?[a-z0-9]){2,}$`

| +| `wor_channel` |

`enum.defined_only`: `true`

| + ### Message `RxMetadata` Contains metadata for a received message. Each antenna that receives @@ -7857,6 +8307,7 @@ a message corresponds to one RxMetadata. | ----- | ---- | ----- | ----------- | | `gateway_ids` | [`GatewayIdentifiers`](#ttn.lorawan.v3.GatewayIdentifiers) | | | | `packet_broker` | [`PacketBrokerMetadata`](#ttn.lorawan.v3.PacketBrokerMetadata) | | | +| `relay` | [`RelayMetadata`](#ttn.lorawan.v3.RelayMetadata) | | | | `antenna_index` | [`uint32`](#uint32) | | | | `time` | [`google.protobuf.Timestamp`](#google.protobuf.Timestamp) | | Timestamp at the end of the transmission, provided by the gateway. The accuracy is undefined. | | `timestamp` | [`uint32`](#uint32) | | Gateway concentrator timestamp when the Rx finished (microseconds). | diff --git a/api/ttn/lorawan/v3/api.swagger.json b/api/ttn/lorawan/v3/api.swagger.json index 60b91dda6f..cf2e11fef8 100644 --- a/api/ttn/lorawan/v3/api.swagger.json +++ b/api/ttn/lorawan/v3/api.swagger.json @@ -6707,6 +6707,13 @@ "required": false, "type": "integer", "format": "int64" + }, + { + "name": "band_id", + "description": "Optional Band ID to filter the results.", + "in": "query", + "required": false, + "type": "string" } ], "tags": [ @@ -17919,15 +17926,19 @@ } } }, - "BandDescriptionRelayParameters": { + "BandDescriptionRelayParametersRelayWORChannel": { "type": "object", "properties": { - "wor_channels": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/RelayParametersRelayWORChannel" - } + "frequency": { + "type": "string", + "format": "uint64" + }, + "ack_frequency": { + "type": "string", + "format": "uint64" + }, + "data_rate_index": { + "$ref": "#/definitions/v3DataRateIndex" } } }, @@ -18841,6 +18852,202 @@ } } }, + "MACCommandRelayConfAns": { + "type": "object", + "properties": { + "second_channel_frequency_ack": { + "type": "boolean" + }, + "second_channel_ack_offset_ack": { + "type": "boolean" + }, + "second_channel_data_rate_index_ack": { + "type": "boolean" + }, + "second_channel_index_ack": { + "type": "boolean" + }, + "default_channel_index_ack": { + "type": "boolean" + }, + "cad_periodicity_ack": { + "type": "boolean" + } + } + }, + "MACCommandRelayConfReq": { + "type": "object", + "properties": { + "configuration": { + "$ref": "#/definitions/MACCommandRelayConfReqConfiguration" + } + } + }, + "MACCommandRelayConfReqConfiguration": { + "type": "object", + "properties": { + "second_channel": { + "$ref": "#/definitions/v3RelaySecondChannel" + }, + "default_channel_index": { + "type": "integer", + "format": "int64" + }, + "cad_periodicity": { + "$ref": "#/definitions/v3RelayCADPeriodicity" + } + } + }, + "MACCommandRelayConfigureFwdLimitAns": { + "type": "object" + }, + "MACCommandRelayConfigureFwdLimitReq": { + "type": "object", + "properties": { + "reset_limit_counter": { + "$ref": "#/definitions/v3RelayResetLimitCounter" + }, + "join_request_limits": { + "$ref": "#/definitions/v3RelayForwardLimits" + }, + "notify_limits": { + "$ref": "#/definitions/v3RelayForwardLimits" + }, + "global_uplink_limits": { + "$ref": "#/definitions/v3RelayForwardLimits" + }, + "overall_limits": { + "$ref": "#/definitions/v3RelayForwardLimits" + } + } + }, + "MACCommandRelayCtrlUplinkListAns": { + "type": "object", + "properties": { + "rule_index_ack": { + "type": "boolean" + }, + "w_f_cnt": { + "type": "integer", + "format": "int64" + } + } + }, + "MACCommandRelayCtrlUplinkListReq": { + "type": "object", + "properties": { + "rule_index": { + "type": "integer", + "format": "int64" + }, + "action": { + "$ref": "#/definitions/v3RelayCtrlUplinkListAction" + } + } + }, + "MACCommandRelayEndDeviceConfAns": { + "type": "object", + "properties": { + "second_channel_frequency_ack": { + "type": "boolean" + }, + "second_channel_data_rate_index_ack": { + "type": "boolean" + }, + "second_channel_index_ack": { + "type": "boolean" + }, + "backoff_ack": { + "type": "boolean" + } + } + }, + "MACCommandRelayEndDeviceConfReq": { + "type": "object", + "properties": { + "configuration": { + "$ref": "#/definitions/MACCommandRelayEndDeviceConfReqConfiguration" + } + } + }, + "MACCommandRelayEndDeviceConfReqConfiguration": { + "type": "object", + "properties": { + "always": { + "$ref": "#/definitions/v3RelayEndDeviceAlwaysMode" + }, + "dynamic": { + "$ref": "#/definitions/v3RelayEndDeviceDynamicMode" + }, + "end_device_controlled": { + "$ref": "#/definitions/v3RelayEndDeviceControlledMode" + }, + "backoff": { + "type": "integer", + "format": "int64" + }, + "second_channel": { + "$ref": "#/definitions/v3RelaySecondChannel" + }, + "serving_device_id": { + "type": "string" + } + } + }, + "MACCommandRelayNotifyNewEndDeviceReq": { + "type": "object", + "properties": { + "dev_addr": { + "type": "string", + "format": "string", + "example": "2600ABCD" + }, + "snr": { + "type": "integer", + "format": "int32" + }, + "rssi": { + "type": "integer", + "format": "int32" + } + } + }, + "MACCommandRelayUpdateUplinkListAns": { + "type": "object" + }, + "MACCommandRelayUpdateUplinkListReq": { + "type": "object", + "properties": { + "rule_index": { + "type": "integer", + "format": "int64" + }, + "forward_limits": { + "$ref": "#/definitions/v3RelayUplinkForwardLimits" + }, + "dev_addr": { + "type": "string", + "format": "string", + "example": "2600ABCD" + }, + "w_f_cnt": { + "type": "integer", + "format": "int64" + }, + "root_wor_s_key": { + "type": "string", + "format": "string", + "example": "0123456789ABCDEF0123456789ABCDEF" + }, + "device_id": { + "type": "string" + }, + "session_key_id": { + "type": "string", + "format": "byte" + } + } + }, "MACCommandResetConf": { "type": "object", "properties": { @@ -19000,6 +19207,9 @@ }, "packet_broker": { "$ref": "#/definitions/UplinkMessageRxMetadataPacketBrokerMetadata" + }, + "relay": { + "$ref": "#/definitions/UplinkMessageRxMetadataRelayMetadata" } } }, @@ -19113,22 +19323,6 @@ "default": "ENABLED", "description": " - ENABLED: No restrictions are in place.\n - WARNING: Warnings are being emitted that the provider will be deprecated in the future.\n - DISABLED: New integrations cannot be set up, and old ones do not start." }, - "RelayParametersRelayWORChannel": { - "type": "object", - "properties": { - "frequency": { - "type": "string", - "format": "uint64" - }, - "ack_frequency": { - "type": "string", - "format": "uint64" - }, - "data_rate_index": { - "$ref": "#/definitions/v3DataRateIndex" - } - } - }, "TxAcknowledgmentResult": { "type": "string", "enum": [ @@ -19167,6 +19361,9 @@ "UplinkMessageRxMetadataPacketBrokerMetadata": { "type": "object" }, + "UplinkMessageRxMetadataRelayMetadata": { + "type": "object" + }, "UserRegistrationAdminApproval": { "type": "object", "properties": { @@ -19481,6 +19678,41 @@ } } }, + "lorawanv3RelayMetadata": { + "type": "object", + "properties": { + "device_id": { + "type": "string", + "description": "End device identifiers of the relay." + }, + "wor_channel": { + "$ref": "#/definitions/lorawanv3RelayWORChannel", + "description": "Wake on radio channel." + } + } + }, + "lorawanv3RelayParameters": { + "type": "object", + "properties": { + "serving": { + "$ref": "#/definitions/v3ServingRelayParameters", + "description": "Parameters related to a relay which is serving end devices." + }, + "served": { + "$ref": "#/definitions/v3ServedRelayParameters", + "description": "Parameters related to an end device served by a relay." + } + }, + "description": "RelayParameters represent the parameters of a relay.\nThis is used internally by the Network Server." + }, + "lorawanv3RelayWORChannel": { + "type": "string", + "enum": [ + "RELAY_WOR_CHANNEL_DEFAULT", + "RELAY_WOR_CHANNEL_SECONDARY" + ], + "default": "RELAY_WOR_CHANNEL_DEFAULT" + }, "lorawanv3RxMetadata": { "type": "object", "properties": { @@ -19490,6 +19722,9 @@ "packet_broker": { "$ref": "#/definitions/lorawanv3PacketBrokerMetadata" }, + "relay": { + "$ref": "#/definitions/lorawanv3RelayMetadata" + }, "antenna_index": { "type": "integer", "format": "int64" @@ -21058,6 +21293,12 @@ "max_adr_data_rate_index": { "$ref": "#/definitions/v3DataRateIndex" }, + "relay_forward_delay": { + "type": "string" + }, + "relay_receive_delay": { + "type": "string" + }, "tx_param_setup_req_support": { "type": "boolean" }, @@ -21072,7 +21313,7 @@ "$ref": "#/definitions/BandDescriptionDwellTime" }, "relay": { - "$ref": "#/definitions/BandDescriptionRelayParameters" + "$ref": "#/definitions/v3BandDescriptionRelayParameters" } } }, @@ -21091,6 +21332,18 @@ } } }, + "v3BandDescriptionRelayParameters": { + "type": "object", + "properties": { + "wor_channels": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/BandDescriptionRelayParametersRelayWORChannel" + } + } + } + }, "v3BatchGetGatewayConnectionStatsRequest": { "type": "object", "properties": { @@ -22575,6 +22828,9 @@ "type": "integer", "format": "int64", "title": "Base frequency in MHz for hardware support (433, 470, 868 or 915)" + }, + "band_id": { + "type": "string" } } }, @@ -23638,6 +23894,39 @@ }, "device_mode_conf": { "$ref": "#/definitions/MACCommandDeviceModeConf" + }, + "relay_conf_req": { + "$ref": "#/definitions/MACCommandRelayConfReq" + }, + "relay_conf_ans": { + "$ref": "#/definitions/MACCommandRelayConfAns" + }, + "relay_end_device_conf_req": { + "$ref": "#/definitions/MACCommandRelayEndDeviceConfReq" + }, + "relay_end_device_conf_ans": { + "$ref": "#/definitions/MACCommandRelayEndDeviceConfAns" + }, + "relay_update_uplink_list_req": { + "$ref": "#/definitions/MACCommandRelayUpdateUplinkListReq" + }, + "relay_update_uplink_list_ans": { + "$ref": "#/definitions/MACCommandRelayUpdateUplinkListAns" + }, + "relay_ctrl_uplink_list_req": { + "$ref": "#/definitions/MACCommandRelayCtrlUplinkListReq" + }, + "relay_ctrl_uplink_list_ans": { + "$ref": "#/definitions/MACCommandRelayCtrlUplinkListAns" + }, + "relay_configure_fwd_limit_req": { + "$ref": "#/definitions/MACCommandRelayConfigureFwdLimitReq" + }, + "relay_configure_fwd_limit_ans": { + "$ref": "#/definitions/MACCommandRelayConfigureFwdLimitAns" + }, + "relay_notify_new_end_device_req": { + "$ref": "#/definitions/MACCommandRelayNotifyNewEndDeviceReq" } } }, @@ -23664,7 +23953,14 @@ "CID_PING_SLOT_CHANNEL", "CID_BEACON_TIMING", "CID_BEACON_FREQ", - "CID_DEVICE_MODE" + "CID_DEVICE_MODE", + "CID_RELAY_CONF", + "CID_RELAY_END_DEVICE_CONF", + "CID_RELAY_FILTER_LIST", + "CID_RELAY_UPDATE_UPLINK_LIST", + "CID_RELAY_CTRL_UPLINK_LIST", + "CID_RELAY_CONFIGURE_FWD_LIMIT", + "CID_RELAY_NOTIFY_NEW_END_DEVICE" ], "default": "CID_RFU_0", "title": "- CID_BEACON_TIMING: Deprecated" @@ -23754,11 +24050,11 @@ }, "uplink_dwell_time": { "$ref": "#/definitions/lorawanv3BoolValue", - "description": "Whether uplink dwell time is set (400ms).\nIf this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it)." + "description": "Whether uplink dwell time is set (400ms).\nIf unset, then the value is either unknown or irrelevant(Network Server cannot modify it)." }, "downlink_dwell_time": { "$ref": "#/definitions/lorawanv3BoolValue", - "description": "Whether downlink dwell time is set (400ms).\nIf this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it)." + "description": "Whether downlink dwell time is set (400ms).\nIf unset, then the value is either unknown or irrelevant(Network Server cannot modify it)." }, "adr_ack_limit_exponent": { "$ref": "#/definitions/v3ADRAckLimitExponentValue", @@ -23771,6 +24067,10 @@ "ping_slot_data_rate_index_value": { "$ref": "#/definitions/v3DataRateIndexValue", "description": "Data rate index of the class B ping slot." + }, + "relay": { + "$ref": "#/definitions/lorawanv3RelayParameters", + "description": "Relay parameters." } }, "description": "MACParameters represent the parameters of the device's MAC layer (active or desired).\nThis is used internally by the Network Server." @@ -23946,6 +24246,14 @@ "schedule_downlinks": { "$ref": "#/definitions/lorawanv3BoolValue", "description": "Whether or not downlink messages should be scheduled.\nThis option can be used in order to disable any downlink interaction with the end device. It will affect all types\nof downlink messages: data and MAC downlinks, and join accepts." + }, + "relay": { + "$ref": "#/definitions/lorawanv3RelayParameters", + "description": "The relay parameters the end device is using.\nIf unset, the default value from Network Server configuration or regional parameters specification will be used." + }, + "desired_relay": { + "$ref": "#/definitions/lorawanv3RelayParameters", + "description": "The relay parameters the Network Server should configure device to use via MAC commands.\nIf unset, the default value from Network Server configuration or regional parameters specification will be used." } } }, @@ -24081,6 +24389,10 @@ "$ref": "#/definitions/v3MACCommandIdentifier" }, "description": "MAC command identifiers sent by the end device in the last received uplink.\nThe Network Server may choose to store only certain types of MAC\ncommand identifiers in the underlying implementation." + }, + "pending_relay_downlink": { + "$ref": "#/definitions/v3RelayForwardDownlinkReq", + "description": "Pending relay downlink contents.\nThe pending downlink will be scheduled to the relay in either Rx1 or Rx2.\nThe pending downlink will be cleared after the scheduling attempt." } }, "description": "MACState represents the state of MAC layer of the device.\nMACState is reset on each join for OTAA or ResetInd for ABP devices.\nThis is used internally by the Network Server." @@ -25198,6 +25510,164 @@ "default": "REJOIN_TIME_0", "description": " - REJOIN_TIME_0: Every ~17.1 minutes.\n - REJOIN_TIME_1: Every ~34.1 minutes.\n - REJOIN_TIME_2: Every ~1.1 hours.\n - REJOIN_TIME_3: Every ~2.3 hours.\n - REJOIN_TIME_4: Every ~4.6 hours.\n - REJOIN_TIME_5: Every ~9.1 hours.\n - REJOIN_TIME_6: Every ~18.2 hours.\n - REJOIN_TIME_7: Every ~1.5 days.\n - REJOIN_TIME_8: Every ~3.0 days.\n - REJOIN_TIME_9: Every ~6.1 days.\n - REJOIN_TIME_10: Every ~12.1 days.\n - REJOIN_TIME_11: Every ~3.5 weeks.\n - REJOIN_TIME_12: Every ~1.6 months.\n - REJOIN_TIME_13: Every ~3.2 months.\n - REJOIN_TIME_14: Every ~6.4 months.\n - REJOIN_TIME_15: Every ~1.1 year." }, + "v3RelayCADPeriodicity": { + "type": "string", + "enum": [ + "RELAY_CAD_PERIODICITY_1_SECOND", + "RELAY_CAD_PERIODICITY_500_MILLISECONDS", + "RELAY_CAD_PERIODICITY_250_MILLISECONDS", + "RELAY_CAD_PERIODICITY_100_MILLISECONDS", + "RELAY_CAD_PERIODICITY_50_MILLISECONDS", + "RELAY_CAD_PERIODICITY_20_MILLISECONDS" + ], + "default": "RELAY_CAD_PERIODICITY_1_SECOND", + "title": "- RELAY_CAD_PERIODICITY_20_MILLISECONDS: sic" + }, + "v3RelayCtrlUplinkListAction": { + "type": "string", + "enum": [ + "RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT", + "RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE" + ], + "default": "RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT" + }, + "v3RelayEndDeviceAlwaysMode": { + "type": "object" + }, + "v3RelayEndDeviceControlledMode": { + "type": "object" + }, + "v3RelayEndDeviceDynamicMode": { + "type": "object", + "properties": { + "smart_enable_level": { + "$ref": "#/definitions/v3RelaySmartEnableLevel", + "description": "The number of consecutive uplinks without a valid downlink before the end device attempts\nto use the relay mode to transmit messages." + } + } + }, + "v3RelayForwardDownlinkReq": { + "type": "object", + "properties": { + "raw_payload": { + "type": "string", + "format": "byte" + } + } + }, + "v3RelayForwardLimits": { + "type": "object", + "properties": { + "bucket_size": { + "$ref": "#/definitions/v3RelayLimitBucketSize", + "description": "The multiplier used to compute the total bucket size for the limits.\nThe multiplier is multiplied by the reload rate in order to compute the total bucket size." + }, + "reload_rate": { + "type": "integer", + "format": "int64", + "description": "The number of tokens which are replenished in the bucket every hour." + } + } + }, + "v3RelayLimitBucketSize": { + "type": "string", + "enum": [ + "RELAY_LIMIT_BUCKET_SIZE_1", + "RELAY_LIMIT_BUCKET_SIZE_2", + "RELAY_LIMIT_BUCKET_SIZE_4", + "RELAY_LIMIT_BUCKET_SIZE_12" + ], + "default": "RELAY_LIMIT_BUCKET_SIZE_1", + "title": "- RELAY_LIMIT_BUCKET_SIZE_12: sic" + }, + "v3RelayResetLimitCounter": { + "type": "string", + "enum": [ + "RELAY_RESET_LIMIT_COUNTER_ZERO", + "RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE", + "RELAY_RESET_LIMIT_COUNTER_MAX_VALUE", + "RELAY_RESET_LIMIT_COUNTER_NO_RESET" + ], + "default": "RELAY_RESET_LIMIT_COUNTER_ZERO" + }, + "v3RelaySecondChAckOffset": { + "type": "string", + "enum": [ + "RELAY_SECOND_CH_ACK_OFFSET_0", + "RELAY_SECOND_CH_ACK_OFFSET_200", + "RELAY_SECOND_CH_ACK_OFFSET_400", + "RELAY_SECOND_CH_ACK_OFFSET_800", + "RELAY_SECOND_CH_ACK_OFFSET_1600", + "RELAY_SECOND_CH_ACK_OFFSET_3200" + ], + "default": "RELAY_SECOND_CH_ACK_OFFSET_0", + "title": "- RELAY_SECOND_CH_ACK_OFFSET_0: 0 kHz\n - RELAY_SECOND_CH_ACK_OFFSET_200: 200 kHz\n - RELAY_SECOND_CH_ACK_OFFSET_400: 400 kHz\n - RELAY_SECOND_CH_ACK_OFFSET_800: 800 kHz\n - RELAY_SECOND_CH_ACK_OFFSET_1600: 1.6 MHz\n - RELAY_SECOND_CH_ACK_OFFSET_3200: 3.2 MHz" + }, + "v3RelaySecondChannel": { + "type": "object", + "properties": { + "ack_offset": { + "$ref": "#/definitions/v3RelaySecondChAckOffset", + "description": "The frequency (Hz) offset used for the WOR acknowledgement." + }, + "data_rate_index": { + "$ref": "#/definitions/v3DataRateIndex", + "description": "The data rate index used by the WOR and WOR acknowledgement." + }, + "frequency": { + "type": "string", + "format": "uint64", + "description": "The frequency (Hz) used by the wake on radio message." + } + } + }, + "v3RelaySmartEnableLevel": { + "type": "string", + "enum": [ + "RELAY_SMART_ENABLE_LEVEL_8", + "RELAY_SMART_ENABLE_LEVEL_16", + "RELAY_SMART_ENABLE_LEVEL_32", + "RELAY_SMART_ENABLE_LEVEL_64" + ], + "default": "RELAY_SMART_ENABLE_LEVEL_8" + }, + "v3RelayUplinkForwardLimits": { + "type": "object", + "properties": { + "bucket_size": { + "$ref": "#/definitions/v3RelayLimitBucketSize", + "description": "The multiplier used to compute the total bucket size for the limits.\nThe multiplier is multiplied by the reload rate in order to compute the total bucket size." + }, + "reload_rate": { + "type": "integer", + "format": "int64", + "description": "The number of tokens which are replenished in the bucket every hour." + } + } + }, + "v3RelayUplinkForwardingRule": { + "type": "object", + "properties": { + "limits": { + "$ref": "#/definitions/v3RelayUplinkForwardLimits", + "description": "Bucket configuration for the served end device.\nIf unset, no individual limits will apply to the end device, but the relay global limitations will apply." + }, + "last_w_f_cnt": { + "type": "integer", + "format": "int64", + "description": "Last wake on radio frame counter used by the served end device." + }, + "device_id": { + "type": "string", + "description": "End device identifier of the served end device." + }, + "session_key_id": { + "type": "string", + "format": "byte", + "description": "Session key ID of the session keys used to derive the root relay session key." + } + } + }, "v3Right": { "type": "string", "enum": [ @@ -25384,6 +25854,91 @@ } } }, + "v3ServedRelayParameters": { + "type": "object", + "properties": { + "always": { + "$ref": "#/definitions/v3RelayEndDeviceAlwaysMode", + "description": "The end device will always attempt to use the relay mode in order to send uplink messages." + }, + "dynamic": { + "$ref": "#/definitions/v3RelayEndDeviceDynamicMode", + "description": "The end device will attempt to use relay mode only after a number of uplink messages have been sent without\nreceiving a valid a downlink message." + }, + "end_device_controlled": { + "$ref": "#/definitions/v3RelayEndDeviceControlledMode", + "description": "The end device will control when it uses the relay mode. This is the default mode." + }, + "backoff": { + "type": "integer", + "format": "int64", + "description": "Number of uplinks to be sent without a wake on radio frame." + }, + "second_channel": { + "$ref": "#/definitions/v3RelaySecondChannel", + "description": "Second wake on radio channel configuration." + }, + "serving_device_id": { + "type": "string", + "description": "End device identifier of the serving end device." + } + } + }, + "v3ServingRelayForwardingLimits": { + "type": "object", + "properties": { + "reset_behavior": { + "$ref": "#/definitions/v3RelayResetLimitCounter", + "description": "Reset behavior of the buckets upon limit update." + }, + "join_requests": { + "$ref": "#/definitions/v3RelayForwardLimits", + "description": "Bucket configuration for join requests.\nIf unset, no individual limits will apply to join requests, but the relay overall limitations will apply." + }, + "notifications": { + "$ref": "#/definitions/v3RelayForwardLimits", + "description": "Bucket configuration for unknown device notifications.\nIf unset, no individual limits will apply to unknown end device notifications, but the relay overall\nlimitations will still apply." + }, + "uplink_messages": { + "$ref": "#/definitions/v3RelayForwardLimits", + "description": "Bucket configuration for uplink messages across all served end devices.\nIf unset, no individual limits will apply to uplink messages across all served end devices, but the relay\noverall limitations will still apply." + }, + "overall": { + "$ref": "#/definitions/v3RelayForwardLimits", + "description": "Bucket configuration for all relay messages.\nIf unset, no overall limits will apply to the relay, but individual limitations will still apply." + } + } + }, + "v3ServingRelayParameters": { + "type": "object", + "properties": { + "second_channel": { + "$ref": "#/definitions/v3RelaySecondChannel", + "description": "Second wake on radio channel configuration." + }, + "default_channel_index": { + "type": "integer", + "format": "int64", + "description": "Index of the default wake on radio channel." + }, + "cad_periodicity": { + "$ref": "#/definitions/v3RelayCADPeriodicity", + "description": "Channel activity detection periodicity." + }, + "uplink_forwarding_rules": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v3RelayUplinkForwardingRule" + }, + "description": "Configured uplink forwarding rules." + }, + "limits": { + "$ref": "#/definitions/v3ServingRelayForwardingLimits", + "description": "Configured forwarding limits.\nIf unset, the default value from Network Server configuration will be used." + } + } + }, "v3Session": { "type": "object", "properties": { diff --git a/api/ttn/lorawan/v3/configuration_services.proto b/api/ttn/lorawan/v3/configuration_services.proto index 13afebd7c1..a6423b8928 100644 --- a/api/ttn/lorawan/v3/configuration_services.proto +++ b/api/ttn/lorawan/v3/configuration_services.proto @@ -32,6 +32,8 @@ message ListFrequencyPlansRequest { }; // Optional base frequency in MHz for hardware support (433, 470, 868 or 915) uint32 base_frequency = 1; + // Optional Band ID to filter the results. + string band_id = 2; } message FrequencyPlanDescription { @@ -41,6 +43,7 @@ message FrequencyPlanDescription { string name = 3; // Base frequency in MHz for hardware support (433, 470, 868 or 915) uint32 base_frequency = 4; + string band_id = 5; } message ListFrequencyPlansResponse { @@ -135,6 +138,8 @@ message BandDescription { google.protobuf.Duration max_retransmit_timeout = 21; repeated float tx_offset = 22; DataRateIndex max_adr_data_rate_index = 23; + google.protobuf.Duration relay_forward_delay = 34; + google.protobuf.Duration relay_receive_delay = 35; bool tx_param_setup_req_support = 24; float default_max_eirp = 25; diff --git a/api/ttn/lorawan/v3/end_device.proto b/api/ttn/lorawan/v3/end_device.proto index 0526c46b07..e762a67aeb 100644 --- a/api/ttn/lorawan/v3/end_device.proto +++ b/api/ttn/lorawan/v3/end_device.proto @@ -88,6 +88,120 @@ message BoolValue { bool value = 1; } +message ServingRelayForwardingLimits { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // Reset behavior of the buckets upon limit update. + RelayResetLimitCounter reset_behavior = 1; + // Bucket configuration for join requests. + // If unset, no individual limits will apply to join requests, but the relay overall limitations will apply. + RelayForwardLimits join_requests = 2; + // Bucket configuration for unknown device notifications. + // If unset, no individual limits will apply to unknown end device notifications, but the relay overall + // limitations will still apply. + RelayForwardLimits notifications = 3; + // Bucket configuration for uplink messages across all served end devices. + // If unset, no individual limits will apply to uplink messages across all served end devices, but the relay + // overall limitations will still apply. + RelayForwardLimits uplink_messages = 4; + // Bucket configuration for all relay messages. + // If unset, no overall limits will apply to the relay, but individual limitations will still apply. + RelayForwardLimits overall = 5; +} + +message RelayUplinkForwardingRule { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // Bucket configuration for the served end device. + // If unset, no individual limits will apply to the end device, but the relay global limitations will apply. + RelayUplinkForwardLimits limits = 1; + // Last wake on radio frame counter used by the served end device. + uint32 last_w_f_cnt = 2; + + // End device identifier of the served end device. + string device_id = 3 [(validate.rules).string = { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36, + ignore_empty: true + }]; + // Session key ID of the session keys used to derive the root relay session key. + bytes session_key_id = 4; +} + +message ServingRelayParameters { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // Second wake on radio channel configuration. + RelaySecondChannel second_channel = 1; + // Index of the default wake on radio channel. + uint32 default_channel_index = 2 [(validate.rules).uint32.lte = 255]; + // Channel activity detection periodicity. + RelayCADPeriodicity cad_periodicity = 3 [(validate.rules).enum.defined_only = true]; + // Configured uplink forwarding rules. + repeated RelayUplinkForwardingRule uplink_forwarding_rules = 4 [(validate.rules).repeated.max_items = 16]; + // Configured forwarding limits. + // If unset, the default value from Network Server configuration will be used. + ServingRelayForwardingLimits limits = 5; +} + +message ServedRelayParameters { + option (thethings.flags.message) = { + select: true, + set: true, + semantical: true + }; + + oneof mode { + option (validate.required) = true; + + // The end device will always attempt to use the relay mode in order to send uplink messages. + RelayEndDeviceAlwaysMode always = 1; + // The end device will attempt to use relay mode only after a number of uplink messages have been sent without + // receiving a valid a downlink message. + RelayEndDeviceDynamicMode dynamic = 2; + // The end device will control when it uses the relay mode. This is the default mode. + RelayEndDeviceControlledMode end_device_controlled = 3; + } + // Number of uplinks to be sent without a wake on radio frame. + uint32 backoff = 4 [(validate.rules).uint32.lte = 63]; + // Second wake on radio channel configuration. + RelaySecondChannel second_channel = 5; + + // End device identifier of the serving end device. + string serving_device_id = 6 [(validate.rules).string = { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + }]; +} + +// RelayParameters represent the parameters of a relay. +// This is used internally by the Network Server. +message RelayParameters { + option (thethings.flags.message) = { + select: true, + set: true, + semantical: true + }; + + oneof mode { + option (validate.required) = true; + + // Parameters related to a relay which is serving end devices. + ServingRelayParameters serving = 25; + // Parameters related to an end device served by a relay. + ServedRelayParameters served = 26; + } +} + // MACParameters represent the parameters of the device's MAC layer (active or desired). // This is used internally by the Network Server. message MACParameters { @@ -162,10 +276,10 @@ message MACParameters { repeated Channel channels = 19 [(validate.rules).repeated.min_items = 1]; // Whether uplink dwell time is set (400ms). - // If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). + // If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). BoolValue uplink_dwell_time = 20; // Whether downlink dwell time is set (400ms). - // If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). + // If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). BoolValue downlink_dwell_time = 21; // ADR: number of messages to wait before setting ADRAckReq. @@ -174,6 +288,9 @@ message MACParameters { ADRAckDelayExponentValue adr_ack_delay_exponent = 23; // Data rate index of the class B ping slot. DataRateIndexValue ping_slot_data_rate_index_value = 24; + + // Relay parameters. + RelayParameters relay = 25; } // Template for creating end devices. @@ -443,6 +560,14 @@ message MACSettings { // This option can be used in order to disable any downlink interaction with the end device. It will affect all types // of downlink messages: data and MAC downlinks, and join accepts. BoolValue schedule_downlinks = 35; + + // The relay parameters the end device is using. + // If unset, the default value from Network Server configuration or regional parameters specification will be used. + RelayParameters relay = 36; + + // The relay parameters the Network Server should configure device to use via MAC commands. + // If unset, the default value from Network Server configuration or regional parameters specification will be used. + RelayParameters desired_relay = 37; } // MACState represents the state of MAC layer of the device. @@ -574,7 +699,11 @@ message MACState { reserved 1 to 10; } PacketBrokerMetadata packet_broker = 18; - reserved 2 to 8, 10, 12, 13, 16, 17, 19, 20, 99; + message RelayMetadata { + reserved 1 to 3; + } + RelayMetadata relay = 23; + reserved 2 to 8, 10, 12, 13, 16, 17, 19, 20, 21, 22, 99; } repeated RxMetadata rx_metadata = 5; google.protobuf.Timestamp received_at = 6; @@ -665,6 +794,11 @@ message MACState { // The Network Server may choose to store only certain types of MAC // command identifiers in the underlying implementation. repeated MACCommandIdentifier recent_mac_command_identifiers = 23; + + // Pending relay downlink contents. + // The pending downlink will be scheduled to the relay in either Rx1 or Rx2. + // The pending downlink will be cleared after the scheduling attempt. + RelayForwardDownlinkReq pending_relay_downlink = 24; } // Power state of the device. diff --git a/api/ttn/lorawan/v3/gateway_services.proto b/api/ttn/lorawan/v3/gateway_services.proto index dc2a082ed9..907bd30e79 100644 --- a/api/ttn/lorawan/v3/gateway_services.proto +++ b/api/ttn/lorawan/v3/gateway_services.proto @@ -181,7 +181,7 @@ service GatewayConfigurator { message AssertGatewayRightsRequest { repeated GatewayIdentifiers gateway_ids = 1 [ (validate.rules).repeated.min_items = 1, - (validate.rules).repeated.max_items = 20 + (validate.rules).repeated.max_items = 100 ]; Rights required = 2 [(validate.rules).message.required = true]; } diff --git a/api/ttn/lorawan/v3/identifiers.proto b/api/ttn/lorawan/v3/identifiers.proto index 4d32b24d20..0e17fc72a3 100644 --- a/api/ttn/lorawan/v3/identifiers.proto +++ b/api/ttn/lorawan/v3/identifiers.proto @@ -228,7 +228,7 @@ message EndDeviceVersionIdentifiers { message NetworkIdentifiers { option (thethings.flags.message) = { select: true, - set: false + set: true }; // LoRa Alliance NetID. bytes net_id = 1 [ diff --git a/api/ttn/lorawan/v3/lorawan.proto b/api/ttn/lorawan/v3/lorawan.proto index 245e7de7ec..b5fd0824cd 100644 --- a/api/ttn/lorawan/v3/lorawan.proto +++ b/api/ttn/lorawan/v3/lorawan.proto @@ -530,7 +530,7 @@ enum TxSchedulePriority { message LoRaDataRate { option (thethings.flags.message) = { select: true, - set: false + set: true }; // Bandwidth (Hz). uint32 bandwidth = 1; @@ -541,7 +541,7 @@ message LoRaDataRate { message FSKDataRate { option (thethings.flags.message) = { select: true, - set: false + set: true }; // Bit rate (bps). uint32 bit_rate = 1; @@ -550,7 +550,7 @@ message FSKDataRate { message LRFHSSDataRate { option (thethings.flags.message) = { select: true, - set: false + set: true }; uint32 modulation_type = 1; // Operating Channel Width (Hz). @@ -561,7 +561,7 @@ message LRFHSSDataRate { message DataRate { option (thethings.flags.message) = { select: true, - set: false + set: true }; oneof modulation { option (validate.required) = true; @@ -578,13 +578,13 @@ message DataRate { message TxSettings { option (thethings.flags.message) = { select: true, - set: false + set: true }; // Transmission settings for downlink. message Downlink { option (thethings.flags.message) = { select: true, - set: false + set: true }; // Index of the antenna on which the uplink was received and/or downlink must be sent. uint32 antenna_index = 1; @@ -720,6 +720,161 @@ enum MACCommandIdentifier { CID_BEACON_TIMING = 18; // Deprecated CID_BEACON_FREQ = 19; CID_DEVICE_MODE = 32; + + CID_RELAY_CONF = 64; + CID_RELAY_END_DEVICE_CONF = 65; + CID_RELAY_FILTER_LIST = 66; + CID_RELAY_UPDATE_UPLINK_LIST = 67; + CID_RELAY_CTRL_UPLINK_LIST = 68; + CID_RELAY_CONFIGURE_FWD_LIMIT = 69; + CID_RELAY_NOTIFY_NEW_END_DEVICE = 70; +} + +enum RelayCADPeriodicity { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_CAD_PERIODICITY" + }; + + RELAY_CAD_PERIODICITY_1_SECOND = 0; + RELAY_CAD_PERIODICITY_500_MILLISECONDS = 1; + RELAY_CAD_PERIODICITY_250_MILLISECONDS = 2; + RELAY_CAD_PERIODICITY_100_MILLISECONDS = 3; + RELAY_CAD_PERIODICITY_50_MILLISECONDS = 4; + RELAY_CAD_PERIODICITY_20_MILLISECONDS = 5; // sic +} + +enum RelaySecondChAckOffset { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_SECOND_CH_ACK_OFFSET" + }; + + RELAY_SECOND_CH_ACK_OFFSET_0 = 0; // 0 kHz + RELAY_SECOND_CH_ACK_OFFSET_200 = 1; // 200 kHz + RELAY_SECOND_CH_ACK_OFFSET_400 = 2; // 400 kHz + RELAY_SECOND_CH_ACK_OFFSET_800 = 3; // 800 kHz + RELAY_SECOND_CH_ACK_OFFSET_1600 = 4; // 1.6 MHz + RELAY_SECOND_CH_ACK_OFFSET_3200 = 5; // 3.2 MHz +} + +enum RelayLimitBucketSize { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_LIMIT_BUCKET_SIZE" + }; + + RELAY_LIMIT_BUCKET_SIZE_1 = 0; + RELAY_LIMIT_BUCKET_SIZE_2 = 1; + RELAY_LIMIT_BUCKET_SIZE_4 = 2; + RELAY_LIMIT_BUCKET_SIZE_12 = 3; // sic +} + +enum RelaySmartEnableLevel { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_SMART_ENABLE_LEVEL" + }; + + RELAY_SMART_ENABLE_LEVEL_8 = 0; + RELAY_SMART_ENABLE_LEVEL_16 = 1; + RELAY_SMART_ENABLE_LEVEL_32 = 2; + RELAY_SMART_ENABLE_LEVEL_64 = 3; +} + +enum RelayWORChannel { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_WOR_CHANNEL" + }; + + RELAY_WOR_CHANNEL_DEFAULT = 0; + RELAY_WOR_CHANNEL_SECONDARY = 1; +} + +enum RelayResetLimitCounter { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_RESET_LIMIT_COUNTER" + }; + + RELAY_RESET_LIMIT_COUNTER_ZERO = 0; + RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE = 1; + RELAY_RESET_LIMIT_COUNTER_MAX_VALUE = 2; + RELAY_RESET_LIMIT_COUNTER_NO_RESET = 3; +} + +enum RelayCtrlUplinkListAction { + option (thethings.json.enum) = { + marshal_as_string: true, + prefix: "RELAY_CTRL_UPLINK_LIST_ACTION" + }; + + RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT = 0; + RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE = 1; +} + +message RelaySecondChannel { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // The frequency (Hz) offset used for the WOR acknowledgement. + RelaySecondChAckOffset ack_offset = 1 [(validate.rules).enum.defined_only = true]; + // The data rate index used by the WOR and WOR acknowledgement. + DataRateIndex data_rate_index = 2 [(validate.rules).enum.defined_only = true]; + // The frequency (Hz) used by the wake on radio message. + uint64 frequency = 3 [(validate.rules).uint64.gte = 100000]; +} + +message RelayUplinkForwardLimits { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // The multiplier used to compute the total bucket size for the limits. + // The multiplier is multiplied by the reload rate in order to compute the total bucket size. + RelayLimitBucketSize bucket_size = 1 [(validate.rules).enum.defined_only = true]; + // The number of tokens which are replenished in the bucket every hour. + uint32 reload_rate = 2 [(validate.rules).uint32.lte = 62]; +} + +message RelayForwardLimits { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // The multiplier used to compute the total bucket size for the limits. + // The multiplier is multiplied by the reload rate in order to compute the total bucket size. + RelayLimitBucketSize bucket_size = 1 [(validate.rules).enum.defined_only = true]; + // The number of tokens which are replenished in the bucket every hour. + uint32 reload_rate = 2 [(validate.rules).uint32.lte = 126]; +} + +message RelayEndDeviceAlwaysMode { + option (thethings.flags.message) = { + select: true, + set: true + }; +} +message RelayEndDeviceDynamicMode { + option (thethings.flags.message) = { + select: true, + set: true + }; + + // The number of consecutive uplinks without a valid downlink before the end device attempts + // to use the relay mode to transmit messages. + RelaySmartEnableLevel smart_enable_level = 1 [(validate.rules).enum.defined_only = true]; +} +message RelayEndDeviceControlledMode { + option (thethings.flags.message) = { + select: true, + set: true + }; } message MACCommand { @@ -760,8 +915,25 @@ message MACCommand { BeaconFreqAns beacon_freq_ans = 30; DeviceModeInd device_mode_ind = 31; DeviceModeConf device_mode_conf = 32; + + RelayConfReq relay_conf_req = 33; + RelayConfAns relay_conf_ans = 34; + RelayEndDeviceConfReq relay_end_device_conf_req = 35; + RelayEndDeviceConfAns relay_end_device_conf_ans = 36; + RelayUpdateUplinkListReq relay_update_uplink_list_req = 39; + RelayUpdateUplinkListAns relay_update_uplink_list_ans = 40; + RelayCtrlUplinkListReq relay_ctrl_uplink_list_req = 41; + RelayCtrlUplinkListAns relay_ctrl_uplink_list_ans = 42; + RelayConfigureFwdLimitReq relay_configure_fwd_limit_req = 43; + RelayConfigureFwdLimitAns relay_configure_fwd_limit_ans = 44; + RelayNotifyNewEndDeviceReq relay_notify_new_end_device_req = 45; } + reserved 37; + reserved "relay_filter_list_req"; + reserved 38; + reserved "relay_filter_list_ans"; + message ResetInd { Minor minor_version = 1 [(validate.rules).enum = { defined_only: true, @@ -912,6 +1084,145 @@ message MACCommand { message DeviceModeConf { Class class = 1 [(validate.rules).enum.defined_only = true]; } + + message RelayConfReq { + message Configuration { + RelaySecondChannel second_channel = 1; + uint32 default_channel_index = 2 [(validate.rules).uint32.lte = 255]; + RelayCADPeriodicity cad_periodicity = 3 [(validate.rules).enum.defined_only = true]; + } + Configuration configuration = 1; + } + message RelayConfAns { + bool second_channel_frequency_ack = 1; + bool second_channel_ack_offset_ack = 2; + bool second_channel_data_rate_index_ack = 3; + bool second_channel_index_ack = 4; + bool default_channel_index_ack = 5; + bool cad_periodicity_ack = 6; + } + message RelayEndDeviceConfReq { + message Configuration { + oneof mode { + option (validate.required) = true; + + RelayEndDeviceAlwaysMode always = 1; + RelayEndDeviceDynamicMode dynamic = 2; + RelayEndDeviceControlledMode end_device_controlled = 3; + } + uint32 backoff = 4 [(validate.rules).uint32.lte = 63]; + RelaySecondChannel second_channel = 5; + + string serving_device_id = 6 [(validate.rules).string = { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + }]; + } + Configuration configuration = 1; + } + message RelayEndDeviceConfAns { + bool second_channel_frequency_ack = 1; + reserved 2; // second_channel_ack_offset_ack does not exist in the relay specification. + reserved "second_channel_ack_offset_ack"; + bool second_channel_data_rate_index_ack = 3; + bool second_channel_index_ack = 4; + bool backoff_ack = 5; + } + message RelayUpdateUplinkListReq { + uint32 rule_index = 1 [(validate.rules).uint32.lte = 15]; + RelayUplinkForwardLimits forward_limits = 2; + bytes dev_addr = 3 [ + (validate.rules).bytes = { + len: 4, + ignore_empty: true + }, + (thethings.json.field) = { + marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes", + unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal4Bytes" + }, + (thethings.flags.field) = { + set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New4BytesFlag", + set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes" + }, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + type: STRING, + format: "string", + example: "\"2600ABCD\"" + } + ]; + uint32 w_f_cnt = 4; + bytes root_wor_s_key = 5 [ + (validate.rules).bytes = { + len: 16, + ignore_empty: true + }, + (thethings.json.field) = { + marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes", + unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal16Bytes" + }, + (thethings.flags.field) = { + set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New16BytesFlag", + set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes" + }, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + type: STRING, + format: "string", + example: "\"0123456789ABCDEF0123456789ABCDEF\"" + } + ]; + + string device_id = 6 [(validate.rules).string = { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + }]; + bytes session_key_id = 7; + } + message RelayUpdateUplinkListAns {} + message RelayCtrlUplinkListReq { + uint32 rule_index = 1 [(validate.rules).uint32.lte = 15]; + RelayCtrlUplinkListAction action = 2; + } + message RelayCtrlUplinkListAns { + bool rule_index_ack = 1; + uint32 w_f_cnt = 2; + } + message RelayConfigureFwdLimitReq { + RelayResetLimitCounter reset_limit_counter = 1; + RelayForwardLimits join_request_limits = 2; + RelayForwardLimits notify_limits = 3; + RelayForwardLimits global_uplink_limits = 4; + RelayForwardLimits overall_limits = 5; + } + message RelayConfigureFwdLimitAns {} + message RelayNotifyNewEndDeviceReq { + bytes dev_addr = 1 [ + (validate.rules).bytes = { + len: 4, + ignore_empty: true + }, + (thethings.json.field) = { + marshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.MarshalHEXBytes", + unmarshaler_func: "go.thethings.network/lorawan-stack/v3/pkg/types.Unmarshal4Bytes" + }, + (thethings.flags.field) = { + set_flag_new_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.New4BytesFlag", + set_flag_getter_func: "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags.GetExactBytes" + }, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + type: STRING, + format: "string", + example: "\"2600ABCD\"" + } + ]; + int32 snr = 2 [(validate.rules).int32 = { + lte: 11, + gte: -20 + }]; + int32 rssi = 3 [(validate.rules).int32 = { + lte: -15, + gte: -142 + }]; + } } message MACCommands { @@ -1240,3 +1551,38 @@ message DeviceEIRPValue { option (thethings.json.message) = {wrapper: true}; DeviceEIRP value = 1 [(validate.rules).enum.defined_only = true]; } + +message RelayForwardUplinkReq { + option (thethings.flags.message) = { + select: true, + set: true + }; + + DataRate data_rate = 1 [(validate.rules).message.required = true]; + int32 snr = 2 [(validate.rules).int32 = { + lte: 11, + gte: -20 + }]; + int32 rssi = 3 [(validate.rules).int32 = { + lte: -15, + gte: -142 + }]; + RelayWORChannel wor_channel = 4 [(validate.rules).enum.defined_only = true]; + uint64 frequency = 5 [(validate.rules).uint64.gte = 100000]; // Uplink channel frequency (Hz). + bytes raw_payload = 6; +} + +message RelayForwardDownlinkReq { + option (thethings.flags.message) = { + select: true, + set: true + }; + + bytes raw_payload = 1; +} + +message RelayUplinkToken { + EndDeviceIdentifiers ids = 1 [(validate.rules).message.required = true]; + bytes session_key_id = 2; + uint32 full_f_cnt = 3; +} diff --git a/api/ttn/lorawan/v3/metadata.proto b/api/ttn/lorawan/v3/metadata.proto index 141fab453a..fd9f16e9a8 100644 --- a/api/ttn/lorawan/v3/metadata.proto +++ b/api/ttn/lorawan/v3/metadata.proto @@ -24,6 +24,7 @@ import "thethings/flags/annotations.proto"; import "thethings/json/annotations.proto"; import "ttn/lorawan/v3/enums.proto"; import "ttn/lorawan/v3/identifiers.proto"; +import "ttn/lorawan/v3/lorawan.proto"; import "validate/validate.proto"; option go_package = "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"; @@ -33,6 +34,7 @@ option go_package = "go.thethings.network/lorawan-stack/v3/pkg/ttnpb"; message RxMetadata { GatewayIdentifiers gateway_ids = 1 [(validate.rules).message.required = true]; PacketBrokerMetadata packet_broker = 18; + RelayMetadata relay = 23; uint32 antenna_index = 2; // Timestamp at the end of the transmission, provided by the gateway. The accuracy is undefined. @@ -79,7 +81,7 @@ message RxMetadata { // - field names are written in snake_case google.protobuf.Struct advanced = 99; - // next: 23 + // next: 24 } message Location { @@ -213,3 +215,13 @@ message PacketBrokerRouteHop { // Receiver agent. string receiver_agent = 5; } + +message RelayMetadata { + // End device identifiers of the relay. + string device_id = 1 [(validate.rules).string = { + pattern: "^[a-z0-9](?:[-]?[a-z0-9]){2,}$", + max_len: 36 + }]; + // Wake on radio channel. + RelayWORChannel wor_channel = 2 [(validate.rules).enum.defined_only = true]; +} diff --git a/cmd/ttn-lw-stack/commands/ns_db.go b/cmd/ttn-lw-stack/commands/ns_db.go index aac3270f3f..f5d5bbfefe 100644 --- a/cmd/ttn-lw-stack/commands/ns_db.go +++ b/cmd/ttn-lw-stack/commands/ns_db.go @@ -211,6 +211,54 @@ var ( return nil }, } + nsDBPurgeCommand = &cobra.Command{ + Use: "purge", + Short: "Purge Network Server application data", + RunE: func(cmd *cobra.Command, args []string) error { + if config.Redis.IsZero() { + panic("Only Redis is supported by this command") + } + + logger.Info("Connecting to Redis database...") + cl := NewNetworkServerApplicationUplinkQueueRedis(config) + defer cl.Close() + + var purged uint64 + + genericUIDKeys := nsredis.ApplicationUplinkQueueUIDGenericUplinkKey(cl, "*") + invalidationUIDKeys := ttnredis.Key(genericUIDKeys, "invalidation") + joinAcceptUIDKeys := ttnredis.Key(genericUIDKeys, "join-accept") + taskQueueKeys := ttnredis.Key(cl.Key("application"), "*") + + targets := []string{ + genericUIDKeys, + invalidationUIDKeys, + joinAcceptUIDKeys, + taskQueueKeys, + } + + pipeliner := cl.Pipeline() + for _, target := range targets { + err := ttnredis.RangeRedisKeys(ctx, cl, target, ttnredis.DefaultRangeCount, + func(k string) (bool, error) { + pipeliner.Del(ctx, k) + purged++ + return true, nil + }) + if err != nil { + logger.WithError(err).Error("Failed to purge Network Server application data") + return err + } + } + if _, err := pipeliner.Exec(ctx); err != nil { + logger.WithError(err).Error("Failed to purge Network Server application data") + return err + } + + logger.WithField("records_purged_count", purged).Info("Purged Network Server application data") + return nil + }, + } ) func init() { @@ -221,4 +269,5 @@ func init() { nsDBCleanupCommand.Flags().Bool("dry-run", false, "Dry run") nsDBCleanupCommand.Flags().Duration("pagination-delay", 100, "Delay between batch requests") nsDBCommand.AddCommand(nsDBCleanupCommand) + nsDBCommand.AddCommand(nsDBPurgeCommand) } diff --git a/cmd/ttn-lw-stack/commands/start.go b/cmd/ttn-lw-stack/commands/start.go index 9b9db5e6e1..a6f16c559b 100644 --- a/cmd/ttn-lw-stack/commands/start.go +++ b/cmd/ttn-lw-stack/commands/start.go @@ -302,7 +302,6 @@ var startCommand = &cobra.Command{ int64(applicationUplinkQueueSize), redisConsumerGroup, time.Minute, - redis.DefaultStreamBlockLimit, ) if err := applicationUplinkQueue.Init(ctx); err != nil { return shared.ErrInitializeNetworkServer.WithCause(err) diff --git a/config/messages.json b/config/messages.json index f699103652..7e578d2124 100644 --- a/config/messages.json +++ b/config/messages.json @@ -152,6 +152,69 @@ "file": "i18n.go" } }, + "enum:CID_RELAY_CONF": { + "translations": { + "en": "relay configuration" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_CONFIGURE_FWD_LIMIT": { + "translations": { + "en": "manage uplink forwarding limits" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_CTRL_UPLINK_LIST": { + "translations": { + "en": "manage uplink forwarding rules" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_END_DEVICE_CONF": { + "translations": { + "en": "end device relay configuration" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_FILTER_LIST": { + "translations": { + "en": "manage join request forwarding rules" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_NOTIFY_NEW_END_DEVICE": { + "translations": { + "en": "new end device under relay" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, + "enum:CID_RELAY_UPDATE_UPLINK_LIST": { + "translations": { + "en": "update uplink forwarding rules" + }, + "description": { + "package": "pkg/ttnpb", + "file": "i18n.go" + } + }, "enum:CID_RESET": { "translations": { "en": "reset" @@ -3509,6 +3572,60 @@ "file": "shared.go" } }, + "error:pkg/console/internal/events/protocol:message_type": { + "translations": { + "en": "invalid message type `{type}`" + }, + "description": { + "package": "pkg/console/internal/events/protocol", + "file": "protocol.go" + } + }, + "error:pkg/console/internal/events/subscriptions:already_subscribed": { + "translations": { + "en": "already subscribed with ID `{id}`" + }, + "description": { + "package": "pkg/console/internal/events/subscriptions", + "file": "subscriptions.go" + } + }, + "error:pkg/console/internal/events/subscriptions:no_identifiers": { + "translations": { + "en": "no identifiers" + }, + "description": { + "package": "pkg/console/internal/events/subscriptions", + "file": "subscriptions.go" + } + }, + "error:pkg/console/internal/events/subscriptions:not_subscribed": { + "translations": { + "en": "not subscribed with ID `{id}`" + }, + "description": { + "package": "pkg/console/internal/events/subscriptions", + "file": "subscriptions.go" + } + }, + "error:pkg/console/internal/events:rate_exceeded": { + "translations": { + "en": "request rate exceeded" + }, + "description": { + "package": "pkg/console/internal/events", + "file": "ratelimit.go" + } + }, + "error:pkg/console/internal/events:unknown_caller": { + "translations": { + "en": "unknown caller type `{type}`" + }, + "description": { + "package": "pkg/console/internal/events", + "file": "ratelimit.go" + } + }, "error:pkg/crypto/cryptoservices:no_app_key": { "translations": { "en": "no AppKey specified" @@ -4382,67 +4499,67 @@ "file": "conversion.go" } }, - "error:pkg/events/grpc:invalid_regexp": { + "error:pkg/events/grpc:no_identifiers": { "translations": { - "en": "invalid regexp" + "en": "no identifiers" }, "description": { "package": "pkg/events/grpc", "file": "grpc.go" } }, - "error:pkg/events/grpc:no_identifiers": { + "error:pkg/events/grpc:storage_disabled": { "translations": { - "en": "no identifiers" + "en": "events storage is not not enabled" }, "description": { "package": "pkg/events/grpc", "file": "grpc.go" } }, - "error:pkg/events/grpc:no_matching_events": { + "error:pkg/events/redis:channel_closed": { "translations": { - "en": "no matching events for regexp `{regexp}`" + "en": "channel closed" }, "description": { - "package": "pkg/events/grpc", - "file": "grpc.go" + "package": "pkg/events/redis", + "file": "redis.go" } }, - "error:pkg/events/grpc:storage_disabled": { + "error:pkg/events/redis:unknown_encoding": { "translations": { - "en": "events storage is not not enabled" + "en": "unknown encoding" }, "description": { - "package": "pkg/events/grpc", - "file": "grpc.go" + "package": "pkg/events/redis", + "file": "codec.go" } }, - "error:pkg/events/grpc:unknown_event_name": { + "error:pkg/events:invalid_regexp": { "translations": { - "en": "unknown event `{name}`" + "en": "invalid regexp" }, "description": { - "package": "pkg/events/grpc", - "file": "grpc.go" + "package": "pkg/events", + "file": "pattern.go" } }, - "error:pkg/events/redis:channel_closed": { + "error:pkg/events:no_matching_events": { "translations": { - "en": "channel closed" + "en": "no matching events for regexp `{regexp}`" }, "description": { - "package": "pkg/events/redis", - "file": "redis.go" + "package": "pkg/events", + "file": "pattern.go" } }, - "error:pkg/events/redis:unknown_encoding": { + "error:pkg/events:unknown_event_name": { "translations": { - "en": "unknown encoding" + "en": "unknown event `{name}`" }, "description": { - "package": "pkg/events/redis", - "file": "codec.go" + "package": "pkg/events", + "file": "pattern.go" } }, "error:pkg/fetch:fetch_file": { @@ -7082,6 +7199,15 @@ "file": "javascript.go" } }, + "error:pkg/messageprocessors/javascript:output_encoding": { + "translations": { + "en": "{errors}" + }, + "description": { + "package": "pkg/messageprocessors/javascript", + "file": "javascript.go" + } + }, "error:pkg/messageprocessors/javascript:output_errors": { "translations": { "en": "{errors}" @@ -7361,6 +7487,15 @@ "file": "application_uplink_queue.go" } }, + "error:pkg/networkserver/redis:invalid_uid": { + "translations": { + "en": "invalid UID" + }, + "description": { + "package": "pkg/networkserver/redis", + "file": "application_uplink_queue.go" + } + }, "error:pkg/networkserver/redis:missing_downlink_correlation_id": { "translations": { "en": "missing identifier correlation ID on downlink message" @@ -7388,6 +7523,15 @@ "file": "registry.go" } }, + "error:pkg/networkserver/redis:missing_uid": { + "translations": { + "en": "missing UID" + }, + "description": { + "package": "pkg/networkserver/redis", + "file": "application_uplink_queue.go" + } + }, "error:pkg/networkserver/redis:no_uplink_match": { "translations": { "en": "no device matches uplink" @@ -7406,6 +7550,15 @@ "file": "registry.go" } }, + "error:pkg/networkserver/redis:relay_served": { + "translations": { + "en": "`{served}` is already served by `{serving}`" + }, + "description": { + "package": "pkg/networkserver/redis", + "file": "registry.go" + } + }, "error:pkg/networkserver:abp_join_request": { "translations": { "en": "received a join-request from ABP device" @@ -7721,6 +7874,87 @@ "file": "grpc_gsns.go" } }, + "error:pkg/networkserver:relay_full_f_cnt": { + "translations": { + "en": "invalid full FCnt" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_m_type": { + "translations": { + "en": "invalid MType" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_recent_uplinks": { + "translations": { + "en": "recent uplinks not found" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_rx_windows_available": { + "translations": { + "en": "no RX windows available" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_schedule": { + "translations": { + "en": "relay schedule" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_serving": { + "translations": { + "en": "relay not serving" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_session": { + "translations": { + "en": "relay session not found" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_session_key_id": { + "translations": { + "en": "relay session key ID not found" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, + "error:pkg/networkserver:relay_uplink_token": { + "translations": { + "en": "invalid relay uplink token" + }, + "description": { + "package": "pkg/networkserver", + "file": "relay.go" + } + }, "error:pkg/networkserver:schedule": { "translations": { "en": "all downlink scheduling attempts failed" @@ -10601,6 +10835,132 @@ "file": "rekey.go" } }, + "event:ns.mac.relay_conf.answer.accept": { + "translations": { + "en": "relay configuration accept received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_conf.go" + } + }, + "event:ns.mac.relay_conf.answer.reject": { + "translations": { + "en": "relay configuration rejection received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_conf.go" + } + }, + "event:ns.mac.relay_conf.request": { + "translations": { + "en": "relay configuration request enqueued" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_conf.go" + } + }, + "event:ns.mac.relay_configure_fwd_limit.answer": { + "translations": { + "en": "relay configure forward limit answer received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_configure_fwd_limit.go" + } + }, + "event:ns.mac.relay_configure_fwd_limit.request": { + "translations": { + "en": "relay configure forward limit request enqueued" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_configure_fwd_limit.go" + } + }, + "event:ns.mac.relay_ctrl_uplink_list.answer.accept": { + "translations": { + "en": "relay control uplink list accept received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_ctrl_uplink_list.go" + } + }, + "event:ns.mac.relay_ctrl_uplink_list.answer.reject": { + "translations": { + "en": "relay control uplink list rejection received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_ctrl_uplink_list.go" + } + }, + "event:ns.mac.relay_ctrl_uplink_list.request": { + "translations": { + "en": "relay control uplink list request enqueued" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_ctrl_uplink_list.go" + } + }, + "event:ns.mac.relay_end_device_conf.answer.accept": { + "translations": { + "en": "relay end device configuration accept received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_end_device_conf.go" + } + }, + "event:ns.mac.relay_end_device_conf.answer.reject": { + "translations": { + "en": "relay end device configuration rejection received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_end_device_conf.go" + } + }, + "event:ns.mac.relay_end_device_conf.request": { + "translations": { + "en": "relay end device configuration request enqueued" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_end_device_conf.go" + } + }, + "event:ns.mac.relay_notify_new_end_device.indication": { + "translations": { + "en": "relay notify new end device indication received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_notify_new_end_device.go" + } + }, + "event:ns.mac.relay_update_uplink_list.answer": { + "translations": { + "en": "relay update uplink list answer received" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_update_uplink_list.go" + } + }, + "event:ns.mac.relay_update_uplink_list.request": { + "translations": { + "en": "relay update uplink list request enqueued" + }, + "description": { + "package": "pkg/networkserver/mac", + "file": "relay_update_uplink_list.go" + } + }, "event:ns.mac.reset.confirmation": { "translations": { "en": "device reset confirmation enqueued" @@ -10808,6 +11168,24 @@ "file": "observability.go" } }, + "event:ns.up.relay.drop": { + "translations": { + "en": "drop relay message" + }, + "description": { + "package": "pkg/networkserver", + "file": "observability.go" + } + }, + "event:ns.up.relay.process": { + "translations": { + "en": "successfully processed relay message" + }, + "description": { + "package": "pkg/networkserver", + "file": "observability.go" + } + }, "event:oauth.authorize": { "translations": { "en": "authorize OAuth client" diff --git a/config/storybook/preview.js b/config/storybook/preview.js index 6233b087ed..4483cb7cff 100644 --- a/config/storybook/preview.js +++ b/config/storybook/preview.js @@ -23,27 +23,22 @@ import { createMemoryHistory } from 'history' import messages from '@ttn-lw/locales/en.json' import backendMessages from '@ttn-lw/locales/.backend/en.json' -import { EnvProvider } from '@ttn-lw/lib/components/env' - import '../../pkg/webui/styles/main.styl' import 'focus-visible/dist/focus-visible' import createStore from './store' import Center from './center' -import env from './env' const history = createMemoryHistory() const store = createStore(history) export const decorators = [ Story => ( - - - - -
{Story()}
-
-
-
-
+ + + +
{Story()}
+
+
+
), ] diff --git a/config/webpack.config.babel.js b/config/webpack.config.babel.js index 2281c7e473..4530e40b95 100644 --- a/config/webpack.config.babel.js +++ b/config/webpack.config.babel.js @@ -175,6 +175,7 @@ export default { target: WEBPACK_DEV_SERVER_USE_TLS ? 'https://localhost:8885' : 'http://localhost:1885', changeOrigin: true, secure: false, + ws: true, }, ], historyApiFallback: true, diff --git a/cypress/e2e/console/admin-panel/packet-broker/networks.spec.js b/cypress/e2e/console/admin-panel/packet-broker/networks.spec.js index db702ac160..e3a83f2526 100644 --- a/cypress/e2e/console/admin-panel/packet-broker/networks.spec.js +++ b/cypress/e2e/console/admin-panel/packet-broker/networks.spec.js @@ -45,7 +45,12 @@ describe('Packet Broker networks', () => { cy.intercept('/api/v3/pba/home-networks/policies*', { fixture: 'console/packet-broker/policies-home-network.json', }) - cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker/networks`) + cy.visit( + `${Cypress.config( + 'consoleRootPath', + )}/admin-panel/packet-broker/routing-configuration/networks`, + ) + cy.findByLabelText('Use custom routing policies').check() const { networks } = this.networks const networksFiltered = networks.filter( @@ -73,7 +78,11 @@ describe('Packet Broker networks', () => { n => n.forwarder_id.net_id === 19 && n.forwarder_id.tenant_id === 'johan', ) - cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker/networks/19/johan`) + cy.visit( + `${Cypress.config( + 'consoleRootPath', + )}/admin-panel/packet-broker/routing-configuration/networks/19/johan`, + ) cy.findAllByText(`${network.id.net_id.toString(16).padStart(6, '0')}/${network.id.tenant_id}`) cy.findByText( diff --git a/cypress/e2e/console/admin-panel/packet-broker/registration.spec.js b/cypress/e2e/console/admin-panel/packet-broker/registration.spec.js index 5f4afc5366..4bfd68d939 100644 --- a/cypress/e2e/console/admin-panel/packet-broker/registration.spec.js +++ b/cypress/e2e/console/admin-panel/packet-broker/registration.spec.js @@ -61,15 +61,15 @@ describe('Packet Broker registration', () => { cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) cy.findByText('Packet Broker', { selector: 'h1' }).should('be.visible') - cy.findByText(/Packet Broker can be used to exchange traffic/).should('be.visible') - cy.findByText('Packet Broker documentation', { selector: 'a' }).should('be.visible') + cy.findByText(/Packet Broker is a service by The Things Industries/).should('be.visible') + cy.findByText('Packet Broker', { selector: 'a' }).should('be.visible') cy.findByText('Packet Broker website', { selector: 'a' }).should('be.visible') - cy.findByText('Register network', { selector: 'span' }).should('be.visible') + cy.findByText('Enable Packet Broker', { selector: 'span' }).should('be.visible') cy.findByTestId('switch') .should('be.visible') .and('not.be.checked') .and('not.have.attr', 'disabled') - cy.findByText(/To enable peering/).should('be.visible') + cy.findByText(/Enabling will allow/).should('be.visible') cy.findByText('Default routing policy').should('not.exist') cy.findByText('Networks').should('not.exist') @@ -89,18 +89,20 @@ describe('Packet Broker registration', () => { cy.loginConsole({ user_id: 'admin', password: 'admin' }) cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) - cy.findByText('Register network').click() - cy.findByText('Register network').next().findByTestId('switch').should('be.checked') - cy.findByText('List network publicly') + cy.findByText('Enable Packet Broker').click() + cy.findByText('Enable Packet Broker').next().findByTestId('switch').should('be.checked') + cy.findByText('List my network in Packet Broker publicly') .should('be.visible') .next() .findByTestId('switch') .should('be.checked') - cy.findByTestId('feature-info-forwarder-enabled').should('be.visible') - cy.findByTestId('feature-info-home-network-enabled').should('be.visible') - cy.findByTestId('tabs').findByText('Default routing policy').should('be.visible') - cy.findByTestId('tabs').findByText('Networks').should('be.visible') - cy.findByLabelText('Do not use a default routing policy for this network').should('be.checked') + cy.findByLabelText('Forward traffic to all networks registered in Packet Broker').should( + 'exist', + ) + cy.findByLabelText( + 'Forward traffic to The Things Stack Sandbox (community network) only', + ).should('exist') + cy.findByLabelText('Use custom routing policies').should('exist') cy.findByTestId('error-notification').should('not.exist') }) diff --git a/cypress/e2e/console/admin-panel/packet-broker/routing-policies.spec.js b/cypress/e2e/console/admin-panel/packet-broker/routing-policies.spec.js index 9b9f519f12..be0fee18a5 100644 --- a/cypress/e2e/console/admin-panel/packet-broker/routing-policies.spec.js +++ b/cypress/e2e/console/admin-panel/packet-broker/routing-policies.spec.js @@ -32,12 +32,63 @@ describe('Packet Broker routing policies', () => { cy.loginConsole({ user_id: 'admin', password: 'admin' }) }) - it('succeeds setting a default routing policy', () => { + it('succeeds setting a "traffic to all networks" routing configuration', () => { cy.intercept('GET', '/api/v3/pba/home-networks/policies/default', { statusCode: 404 }) cy.intercept('PUT', '/api/v3/pba/home-networks/policies/default', {}) + cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19', {}) + cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19/johan', {}) + cy.intercept('/api/v3/pba/networks*', { fixture: 'console/packet-broker/networks.json' }) + cy.intercept('/api/v3/pba/home-networks/policies*', { + fixture: 'console/packet-broker/policies-home-network.json', + }) cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) - cy.findByLabelText('Use default routing policy for this network').check() + cy.findByLabelText('Forward traffic to all networks registered in Packet Broker').check() + cy.findByRole('button', { name: 'Save routing configuration' }).click() + + cy.findByTestId('error-notification').should('not.exist') + cy.findByTestId('toast-notification') + .should('be.visible') + .findByText('Default routing configuration set') + .should('be.visible') + }) + + it('succeeds setting a "only ttn" routing configuration', () => { + cy.intercept('GET', '/api/v3/pba/home-networks/policies/default', { statusCode: 404 }) + cy.intercept('/api/v3/pba/networks*', { fixture: 'console/packet-broker/networks.json' }) + cy.intercept('/api/v3/pba/home-networks/policies*', { + fixture: 'console/packet-broker/policies-home-network.json', + }) + cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/default', {}) + cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19', {}) + cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19/johan', {}) + cy.intercept('PUT', '/api/v3/pba/home-networks/policies/19/ttn', {}) + cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) + + cy.findByLabelText( + 'Forward traffic to The Things Stack Sandbox (community network) only', + ).check() + cy.findByRole('button', { name: 'Save routing configuration' }).click() + + cy.findByTestId('error-notification').should('not.exist') + cy.findByTestId('toast-notification') + .should('be.visible') + .findByText('Default routing configuration set') + .should('be.visible') + }) + + it('succeeds setting a custom routing configuration with a default routing policy', () => { + cy.intercept('GET', '/api/v3/pba/home-networks/policies/default', { + fixture: 'console/packet-broker/default-policy.json', + }) + cy.intercept('PUT', '/api/v3/pba/home-networks/policies/default', {}) + cy.intercept('/api/v3/pba/networks*', { fixture: 'console/packet-broker/networks.json' }) + cy.intercept('/api/v3/pba/home-networks/policies*', { + fixture: 'console/packet-broker/policies-home-network.json', + }) + cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) + + cy.findByLabelText('Use custom routing policies').check() // Check routing policy form checkboxes. cy.findByText('Uplink') @@ -56,30 +107,35 @@ describe('Packet Broker routing policies', () => { cy.findByLabelText('MAC data').check() cy.findByLabelText('Application data').check() }) - cy.findByRole('button', { name: 'Save default policy' }).click() + cy.findByRole('button', { name: 'Save routing configuration' }).click() cy.findByTestId('error-notification').should('not.exist') cy.findByTestId('toast-notification') .should('be.visible') - .findByText('Default routing policy set') + .findByText('Default routing configuration set') .should('be.visible') }) it('succeeds unsetting a default routing policy', () => { + cy.intercept('PUT', '/api/v3/pba/home-networks/policies/default', {}) + cy.intercept('/api/v3/pba/networks*', { fixture: 'console/packet-broker/networks.json' }) + cy.intercept('/api/v3/pba/home-networks/policies*', { + fixture: 'console/packet-broker/policies-home-network.json', + }) cy.intercept('GET', '/api/v3/pba/home-networks/policies/default', { - fixture: 'console/packet-broker/default-policy.json', + fixture: 'console/packet-broker/default-custom-policy.json', }) cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/default', {}) cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker`) cy.findByLabelText('Do not use a default routing policy for this network').check() - cy.findByRole('button', { name: 'Save default policy' }).click() + cy.findByRole('button', { name: 'Save routing configuration' }).click() cy.findByTestId('error-notification').should('not.exist') cy.findByTestId('toast-notification') .should('be.visible') - .findByText('Default routing policy set') + .findByText('Default routing configuration set') .should('be.visible') }) @@ -93,7 +149,11 @@ describe('Packet Broker routing policies', () => { }) cy.intercept('PUT', '/api/v3/pba/home-networks/policies/19', {}) - cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker/networks/19`) + cy.visit( + `${Cypress.config( + 'consoleRootPath', + )}/admin-panel/packet-broker/routing-configuration/networks/19`, + ) // Check routing policy form checkboxes. cy.findByLabelText('Use network specific routing policy').check() @@ -138,7 +198,11 @@ describe('Packet Broker routing policies', () => { }) cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19', {}) - cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker/networks/19`) + cy.visit( + `${Cypress.config( + 'consoleRootPath', + )}/admin-panel/packet-broker/routing-configuration/networks/19`, + ) cy.findByLabelText('Do not use a routing policy for this network').check() cy.findByRole('button', { name: 'Save routing policy' }).click() @@ -161,7 +225,11 @@ describe('Packet Broker routing policies', () => { }) cy.intercept('DELETE', '/api/v3/pba/home-networks/policies/19', {}) - cy.visit(`${Cypress.config('consoleRootPath')}/admin-panel/packet-broker/networks/19`) + cy.visit( + `${Cypress.config( + 'consoleRootPath', + )}/admin-panel/packet-broker/routing-configuration/networks/19`, + ) cy.findByLabelText('Use default routing policy for this network').check() cy.findByRole('button', { name: 'Save routing policy' }).click() diff --git a/cypress/e2e/console/gateways/create.spec.js b/cypress/e2e/console/gateways/create.spec.js index e2769d5cbb..bc9ca5843d 100644 --- a/cypress/e2e/console/gateways/create.spec.js +++ b/cypress/e2e/console/gateways/create.spec.js @@ -38,7 +38,7 @@ describe('Gateway create', () => { cy.findByLabelText('Gateway EUI').should('be.visible') cy.findByLabelText('Gateway ID').should('be.visible') cy.findByLabelText('Gateway name').should('be.visible') - cy.findByLabelText('Frequency plan').should('be.visible') + cy.findByTestId('key-value-map').should('be.visible') cy.findByLabelText(/Require authenticated connection/).should('exist') cy.findByLabelText(/Share status within network/).should('exist') cy.findByLabelText(/Share location within network/).should('exist') @@ -54,7 +54,11 @@ describe('Gateway create', () => { cy.findByLabelText('Gateway EUI').blur() cy.findByLabelText('Gateway ID').should('have.value', `eui-${gateway.eui}`) cy.findByLabelText('Gateway name').type('Test Gateway') - cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan) + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(gateway.frequency_plan) cy.findByRole('button', { name: 'Register gateway' }).click() cy.location('pathname').should( @@ -87,7 +91,11 @@ describe('Gateway create', () => { cy.findByLabelText('Gateway EUI').blur() cy.findByLabelText('Gateway ID').should('have.value', `eui-${gateway.eui}`) cy.findByLabelText('Gateway name').type('Test Gateway') - cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan) + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(gateway.frequency_plan) cy.findByLabelText(/Require authenticated connection/).check() cy.findByLabelText(/Generate API key for CUPS/).check() cy.findByLabelText(/Generate API key for LNS/).check() @@ -121,7 +129,11 @@ describe('Gateway create', () => { } cy.findByLabelText('Gateway EUI').type(gateway.eui) - cy.findByLabelText('Frequency plan').selectOption('no-frequency-plan') + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption('no-frequency-plan') cy.findByText(/Without choosing a frequency plan/) cy.findByRole('button', { name: 'Register gateway' }).click() @@ -134,6 +146,38 @@ describe('Gateway create', () => { cy.findByTestId('error-notification').should('not.exist') }) + it('succeeds adding gateway with multiple frequency plans', () => { + const gateway = { + frequency_plan: 'EU_863_870', + eui: generateHexValue(16), + } + + cy.findByLabelText('Gateway EUI').type(gateway.eui) + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(gateway.frequency_plan) + cy.findByRole('button', { name: /Add frequency plan/ }).click() + cy.findByText('Frequency plan') + .parent() + .parent() + .find('input') + .eq(2) + .selectOption('EU_863_870_TTN') + cy.findByRole('button', { name: 'Register gateway' }).click() + + cy.findByTestId('error-notification').should('not.exist') + cy.location('pathname').should( + 'eq', + `${Cypress.config('consoleRootPath')}/gateways/eui-${gateway.eui}`, + ) + cy.findByRole('heading', { name: `eui-${gateway.eui}` }) + cy.findByText('Frequency plan') + cy.findByText('EU_863_870 , EU_863_870_TTN').should('be.visible') + cy.findByTestId('error-notification').should('not.exist') + }) + describe('Gateway Server disabled', () => { beforeEach(() => { cy.augmentStackConfig(disableGatewayServer) @@ -149,7 +193,7 @@ describe('Gateway create', () => { cy.findByLabelText('Gateway EUI').type(gateway.eui) - cy.findByLabelText('Frequency plan').should('not.exist') + cy.findByTestId('key-value-map').should('not.exist') cy.findByRole('button', { name: 'Register gateway' }).click() cy.location('pathname').should( diff --git a/cypress/e2e/console/gateways/edit.spec.js b/cypress/e2e/console/gateways/edit.spec.js index cf896cc3c1..4a6eba6a3e 100644 --- a/cypress/e2e/console/gateways/edit.spec.js +++ b/cypress/e2e/console/gateways/edit.spec.js @@ -17,6 +17,7 @@ import { generateCollaborator } from '../../../support/utils' describe('Gateway general settings', () => { let user let gateway + let gateway2 const collabUserId = 'test-collab-user' const collabUser = { ids: { user_id: collabUserId }, @@ -46,7 +47,20 @@ describe('Gateway general settings', () => { key: 'value', }, } + gateway2 = { + ids: { gateway_id: 'test-gateway-frequency-plans', eui: '0000000000000001' }, + name: 'Test Gateway Frequency Plans', + description: 'Gateway for testing multiple frequency plans', + schedule_anytime_delay: '523ms', + enforce_duty_cycle: true, + gateway_server_address: 'localhost', + attributes: { + key: 'value', + }, + frequency_plan_ids: ['EU_863_870', 'US_902_928_FSB_1'], + } cy.createGateway(gateway, user.ids.user_id) + cy.createGateway(gateway2, user.ids.user_id) }) it('displays newly created gateway values', () => { @@ -122,9 +136,9 @@ describe('Gateway general settings', () => { cy.findByRole('button', { name: 'Save changes' }).should('be.visible') cy.findByRole('button', { name: /Delete gateway/ }).should('be.visible') cy.findByRole('heading', { name: 'LoRaWAN options' }).should('be.visible') - cy.findByLabelText('Frequency plan').should('not.exist') + cy.findByText('Frequency plan').should('not.exist') cy.findByRole('button', { name: 'Expand' }).click() - cy.findByLabelText('Frequency plan').should('be.visible') + cy.findByText('Frequency plan').should('be.visible') cy.findByLabelText(/Enforce duty cycle/) .should('exist') .and('have.attr', 'value', 'true') @@ -192,7 +206,11 @@ describe('Gateway general settings', () => { cy.findByLabelText(/Enforce duty cycle/).uncheck() cy.findByLabelText('Schedule any time delay').clear() cy.findByLabelText('Schedule any time delay').type('1') - cy.findByLabelText('Frequency plan').type(`${newFrequencyPlan}{enter}`) + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(newFrequencyPlan) cy.findByRole('button', { name: 'Save changes' }).click() }) @@ -275,6 +293,38 @@ describe('Gateway general settings', () => { }) }) + it('succeeds editing multiple frequency plans', () => { + const newFrequencyPlan = 'Europe 863-870 MHz, 6 channels for roaming (Draft)' + cy.loginConsole({ user_id: user.ids.user_id, password: user.password }) + cy.visit( + `${Cypress.config('consoleRootPath')}/gateways/${gateway2.ids.gateway_id}/general-settings`, + ) + + cy.findByText('LoRaWAN options', { selector: 'h3' }) + .closest('[data-test-id="collapsible-section"]') + .within(() => { + cy.findByRole('button', { name: 'Expand' }).click() + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(newFrequencyPlan) + cy.findByRole('button', { name: 'Save changes' }).click() + }) + + cy.findByTestId('error-notification').should('not.exist') + cy.findByTestId('toast-notification').findByText('Gateway updated').should('be.visible') + cy.reload() + + cy.findByText('LoRaWAN options', { selector: 'h3' }) + .closest('[data-test-id="collapsible-section"]') + .within(() => { + cy.findByRole('button', { name: 'Expand' }).click() + cy.findByText('Frequency plan') + cy.findByText(newFrequencyPlan) + }) + }) + it('succeeds deleting the gateway', () => { cy.loginConsole({ user_id: user.ids.user_id, password: user.password }) cy.visit( diff --git a/cypress/e2e/console/integrations/pub-subs/create.spec.js b/cypress/e2e/console/integrations/pub-subs/create.spec.js index 3d8983ffb6..78f4616d4e 100644 --- a/cypress/e2e/console/integrations/pub-subs/create.spec.js +++ b/cypress/e2e/console/integrations/pub-subs/create.spec.js @@ -323,4 +323,85 @@ describe('Application Pub/Sub create', () => { }) }) }) + + describe('Disabled Providers', () => { + const description = 'Changing the Pub/Sub provider has been disabled by an administrator' + + describe('NATS disabled', () => { + const response = { + configuration: { + pubsub: { + providers: { + nats: 'DISABLED', + }, + }, + }, + } + + beforeEach(() => { + cy.loginConsole({ user_id: userId, password: user.password }) + cy.visit( + `${Cypress.config('consoleRootPath')}/applications/${appId}/integrations/pubsubs/add`, + ) + + cy.intercept('GET', `/api/v3/as/configuration`, response) + }) + it('succeeds setting MQTT as default provider', () => { + cy.findByLabelText('NATS').should('be.disabled') + cy.findByText(description).should('be.visible') + }) + }) + + describe('MQTT disabled', () => { + const description = 'Changing the Pub/Sub provider has been disabled by an administrator' + const response = { + configuration: { + pubsub: { + providers: { + mqtt: 'DISABLED', + }, + }, + }, + } + + beforeEach(() => { + cy.loginConsole({ user_id: userId, password: user.password }) + cy.visit( + `${Cypress.config('consoleRootPath')}/applications/${appId}/integrations/pubsubs/add`, + ) + cy.intercept('GET', `/api/v3/as/configuration`, response) + }) + + it('succeeds setting NATS as default provider', () => { + cy.findByLabelText('MQTT').should('be.disabled') + cy.findByText(description).should('be.visible') + }) + }) + + describe('MQTT and NATS disabled', () => { + const response = { + configuration: { + pubsub: { + providers: { + mqtt: 'DISABLED', + nats: 'DISABLED', + }, + }, + }, + } + + beforeEach(() => { + cy.loginConsole({ user_id: userId, password: user.password }) + cy.on('uncaught:exception', () => false) + cy.visit( + `${Cypress.config('consoleRootPath')}/applications/${appId}/integrations/pubsubs/add`, + ) + cy.intercept('GET', `/api/v3/as/configuration`, response) + }) + + it('succeeds showing not found page', () => { + cy.findByRole('heading', { name: /Not found/ }).should('be.visible') + }) + }) + }) }) diff --git a/cypress/e2e/smoke/gateways/create.js b/cypress/e2e/smoke/gateways/create.js index 00d35cb506..250b0b8465 100644 --- a/cypress/e2e/smoke/gateways/create.js +++ b/cypress/e2e/smoke/gateways/create.js @@ -40,7 +40,11 @@ const gatewayCreate = defineSmokeTest('succeeds creating gateway', () => { cy.findByRole('link', { name: /Register gateway/ }).click() cy.findByLabelText('Gateway EUI').type(gateway.eui) cy.findByLabelText('Gateway name').type(gateway.name) - cy.findByLabelText('Frequency plan').selectOption(gateway.frequency_plan_id) + cy.findByText('Frequency plan') + .parents('div[data-test-id="form-field"]') + .find('input') + .first() + .selectOption(gateway.frequency_plan_id) cy.findByRole('button', { name: 'Register gateway' }).click() cy.location('pathname').should( diff --git a/cypress/e2e/smoke/gateways/subpages.js b/cypress/e2e/smoke/gateways/subpages.js index 5eac3c98fa..a05f6922ea 100644 --- a/cypress/e2e/smoke/gateways/subpages.js +++ b/cypress/e2e/smoke/gateways/subpages.js @@ -69,7 +69,7 @@ const gatewaySubpages = defineSmokeTest('check all gateway sub-pages', () => { .closest('[data-test-id="collapsible-section"]') .within(() => { cy.findByRole('button', { name: 'Expand' }).click() - cy.findByLabelText('Frequency plan').should('be.visible') + cy.findByText('Frequency plan').should('be.visible') cy.findByRole('button', { name: /Save changes/ }).should('be.visible') cy.findByTestId('error-notification').should('not.exist') cy.findByRole('button', { name: 'Collapse' }).click() diff --git a/cypress/fixtures/console/packet-broker/default-custom-policy.json b/cypress/fixtures/console/packet-broker/default-custom-policy.json new file mode 100644 index 0000000000..edd8728179 --- /dev/null +++ b/cypress/fixtures/console/packet-broker/default-custom-policy.json @@ -0,0 +1,11 @@ +{ + "updated_at": "2021-06-21T12:09:26.810087Z", + "uplink": { + "join_request": true, + "mac_data": false, + "application_data": true, + "signal_quality": false, + "localization": false + }, + "downlink": { "join_accept": true, "mac_data": false, "application_data": true } +} diff --git a/data/lorawan-devices b/data/lorawan-devices index 844d631c05..4c8ea2f54c 160000 --- a/data/lorawan-devices +++ b/data/lorawan-devices @@ -1 +1 @@ -Subproject commit 844d631c05cd29476b3619061cbddd59037020b4 +Subproject commit 4c8ea2f54cc0575a1c0f508e7a2ac9f272be4b4c diff --git a/data/lorawan-webhook-templates b/data/lorawan-webhook-templates index 62f572e227..2c03558427 160000 --- a/data/lorawan-webhook-templates +++ b/data/lorawan-webhook-templates @@ -1 +1 @@ -Subproject commit 62f572e227ecad348cfada942c332967b4a3914e +Subproject commit 2c0355842769995e3f1d304d004303d9671febe0 diff --git a/go.mod b/go.mod index 4a243df8f6..be8e476f53 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module go.thethings.network/lorawan-stack/v3 -go 1.20 +go 1.21 // Use our fork of throttled/throttled/v2. replace github.com/throttled/throttled/v2 => github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis @@ -15,25 +15,25 @@ require ( github.com/TheThingsIndustries/mystique v0.0.0-20221125120501-80ab21781b6d github.com/TheThingsIndustries/protoc-gen-go-flags v1.2.0 github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0 - github.com/TheThingsNetwork/go-cayenne-lib v1.1.0 - github.com/aws/aws-sdk-go v1.45.19 + github.com/TheThingsNetwork/go-cayenne-lib v1.2.0 + github.com/aws/aws-sdk-go v1.47.1 github.com/blang/semver v3.5.1+incompatible github.com/blevesearch/bleve v1.0.14 github.com/bluele/gcache v0.0.2 github.com/disintegration/imaging v1.6.2 - github.com/dop251/goja v0.0.0-20230828202809-3dbe69dd2b8e + github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d github.com/dustin/go-humanize v1.0.1 github.com/eclipse/paho.mqtt.golang v1.4.4-0.20230810210351-7b759f1d9ddf github.com/emersion/go-smtp v0.18.1 github.com/envoyproxy/protoc-gen-validate v1.0.2 - github.com/felixge/httpsnoop v1.0.3 - github.com/getsentry/sentry-go v0.24.1 + github.com/felixge/httpsnoop v1.0.4 + github.com/getsentry/sentry-go v0.25.0 github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f - github.com/google/go-cmp v0.5.9 - github.com/google/uuid v1.3.1 + github.com/google/go-cmp v0.6.0 + github.com/google/uuid v1.4.0 github.com/gorilla/csrf v1.7.1 github.com/gorilla/handlers v1.5.1 - github.com/gorilla/mux v1.8.0 + github.com/gorilla/mux v1.8.1 github.com/gorilla/schema v1.2.0 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/websocket v1.5.0 @@ -41,8 +41,8 @@ require ( github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 - github.com/hellofresh/health-go/v5 v5.3.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.2-0.20231120080707-5e5867a3a4b0 + github.com/hellofresh/health-go/v5 v5.5.0 github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef github.com/iancoleman/strcase v0.3.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa @@ -52,18 +52,19 @@ require ( github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 github.com/json-iterator/go v1.1.12 github.com/jtacoma/uritemplates v1.0.0 + github.com/klauspost/compress v1.17.2 github.com/kr/pretty v0.3.1 github.com/lib/pq v1.10.9 github.com/mitchellh/mapstructure v1.5.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 - github.com/nats-io/nats-server/v2 v2.10.1 - github.com/nats-io/nats.go v1.30.2 + github.com/nats-io/nats-server/v2 v2.10.4 + github.com/nats-io/nats.go v1.31.0 github.com/oklog/ulid/v2 v2.1.0 github.com/openshift/osin v1.0.2-0.20220317075346-0f4d38c6e53f github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.17.0 - github.com/redis/go-redis/v9 v9.2.1 + github.com/redis/go-redis/v9 v9.3.0 github.com/satori/go.uuid v1.2.0 github.com/sendgrid/sendgrid-go v3.13.0+incompatible github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e @@ -71,53 +72,54 @@ require ( github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.16.0 + github.com/spf13/viper v1.17.0 github.com/throttled/throttled v2.2.5+incompatible github.com/throttled/throttled/v2 v2.12.0 github.com/uptrace/bun v1.1.16 github.com/uptrace/bun/dialect/pgdialect v1.1.16 github.com/uptrace/bun/driver/pgdriver v1.1.16 - github.com/vmihailenco/msgpack/v5 v5.4.0 + github.com/vmihailenco/msgpack/v5 v5.4.1 go.opencensus.io v0.24.0 - go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 - go.opentelemetry.io/otel v1.19.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 - go.opentelemetry.io/otel/sdk v1.19.0 - go.opentelemetry.io/otel/trace v1.19.0 - go.packetbroker.org/api/iam v1.7.0 - go.packetbroker.org/api/iam/v2 v2.7.13 - go.packetbroker.org/api/mapping/v2 v2.1.32 - go.packetbroker.org/api/routing v1.8.23 - go.packetbroker.org/api/v3 v3.15.2 + go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 + go.opentelemetry.io/otel v1.20.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 + go.opentelemetry.io/otel/sdk v1.20.0 + go.opentelemetry.io/otel/trace v1.20.0 + go.packetbroker.org/api/iam v1.8.1 + go.packetbroker.org/api/iam/v2 v2.9.0 + go.packetbroker.org/api/mapping/v2 v2.3.0 + go.packetbroker.org/api/routing v1.9.1 + go.packetbroker.org/api/v3 v3.17.0 go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e go.thethings.network/lorawan-stack-legacy/v2 v2.1.0 go.uber.org/automaxprocs v1.5.3 go.uber.org/zap v1.26.0 gocloud.dev v0.34.0 gocloud.dev/pubsub/natspubsub v0.34.0 - golang.org/x/crypto v0.13.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 - golang.org/x/net v0.15.0 - golang.org/x/oauth2 v0.12.0 - golang.org/x/sync v0.3.0 - google.golang.org/genproto v0.0.0-20230911183012-2d3300fd4832 - google.golang.org/genproto/googleapis/api v0.0.0-20230911183012-2d3300fd4832 - google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 - google.golang.org/grpc v1.58.2 + golang.org/x/crypto v0.15.0 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/net v0.18.0 + golang.org/x/oauth2 v0.14.0 + golang.org/x/sync v0.4.0 + google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 gopkg.in/mail.v2 v2.3.1 gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v2 v2.4.0 + nhooyr.io/websocket v1.8.10 ) require ( - cloud.google.com/go v0.110.7 // indirect - cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go v0.110.9 // indirect + cloud.google.com/go/compute v1.23.2 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.1 // indirect + cloud.google.com/go/iam v1.1.4 // indirect cloud.google.com/go/pubsub v1.33.0 // indirect cloud.google.com/go/storage v1.31.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect @@ -172,11 +174,11 @@ require ( github.com/dlclark/regexp2 v1.7.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/godbus/dbus/v5 v5.0.6 // indirect @@ -186,9 +188,9 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/gomodule/redigo v1.8.9 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect - github.com/google/s2a-go v0.1.4 // indirect + github.com/google/s2a-go v0.1.7 // indirect github.com/google/wire v0.5.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 // indirect @@ -205,12 +207,11 @@ require ( github.com/jacobsa/reqtrace v0.0.0-20150505043853-245c9e0234cb // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect @@ -218,46 +219,48 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/nats-io/jwt/v2 v2.5.2 // indirect - github.com/nats-io/nkeys v0.4.5 // indirect + github.com/nats-io/nkeys v0.4.6 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect github.com/pborman/uuid v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/philhofer/fwd v1.0.0 // indirect github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/prometheus/statsd_exporter v0.22.7 // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.3.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/smartystreets/assertions v1.13.1 // indirect - github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.10.0 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/steveyen/gtreap v0.1.0 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/tinylib/msgp v1.1.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/willf/bitset v1.1.11 // indirect go.etcd.io/bbolt v1.3.6 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 // indirect + go.opentelemetry.io/otel/metric v1.20.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/image v0.5.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/image v0.10.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.134.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/api v0.143.0 // indirect + google.golang.org/appengine v1.6.8 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index c2d911f3a8..f2db5ff523 100644 --- a/go.sum +++ b/go.sum @@ -18,22 +18,22 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= -cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68= +cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= -cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers= +cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk= +cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -58,6 +58,7 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9Orh github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0 h1:Ma67P/GGprNwsslzEH6+Kb8nybI8jpDTm4Wmzu2ReK8= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0 h1:nVocQV40OQne5613EeLayJiRAJuKlBGy+m22qWG+WRg= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.1.0/go.mod h1:7QJP7dr2wznCMeqIrhMgWGf7XpAQnVrJqDm9nvV3Cu4= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -88,18 +89,17 @@ github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0 h1:FTaVxiDPoV9o6k2OFBij github.com/TheThingsIndustries/protoc-gen-go-json v1.6.0/go.mod h1:6ourNr6TBk/2SB2V4In+o2eqZd/DIdiBLnoxvQ3UyWk= github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis h1:uashKgjy7XCNZNb00+3GheWtJXnS9DnAkYQ1X89cAIg= github.com/TheThingsIndustries/throttled/v2 v2.7.1-noredis/go.mod h1:XC/YhKcHsxRy8shbYICwf+oWeYTCC2kpL5/clSJbt+U= -github.com/TheThingsNetwork/go-cayenne-lib v1.1.0 h1:uw+WnTMSSwTo58/ob3ktWNBiCY2psIof8p3lKdxreAE= -github.com/TheThingsNetwork/go-cayenne-lib v1.1.0/go.mod h1:HTTus7UIBhXKvLIeNGybbG1o7wr4zwwVbbUXwFqrtp0= +github.com/TheThingsNetwork/go-cayenne-lib v1.2.0 h1:yW4x7mNk2vyNTUYNRhda9oV8caLePMNR7Z5QbaG5Ifs= +github.com/TheThingsNetwork/go-cayenne-lib v1.2.0/go.mod h1:HTTus7UIBhXKvLIeNGybbG1o7wr4zwwVbbUXwFqrtp0= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/aws/aws-sdk-go v1.45.19 h1:+4yXWhldhCVXWFOQRF99ZTJ92t4DtoHROZIbN7Ujk/U= -github.com/aws/aws-sdk-go v1.45.19/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.47.1 h1:j9ih0Ashcw8tQcnfqNimBM8ARQ/CMpoBwjKue1D6Fuk= +github.com/aws/aws-sdk-go v1.47.1/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8= github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ= @@ -176,7 +176,9 @@ github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -196,11 +198,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/cgroups/v3 v3.0.1 h1:4hfGvu8rfGIwVIDd+nLzn/B9ZXx4BcCjzt5ToenJRaE= github.com/containerd/cgroups/v3 v3.0.1/go.mod h1:/vtwk1VXrtoa5AaZLkypuOJgA/6DyPMZHJPGQNtlHnw= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -221,8 +220,9 @@ github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ1 github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= @@ -232,11 +232,12 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230828202809-3dbe69dd2b8e h1:UvQD6hTSfeM6hhTQ24Dlw2RppP05W7SWbWb6kubJAog= -github.com/dop251/goja v0.0.0-20230828202809-3dbe69dd2b8e/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= +github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d h1:wi6jN5LVt/ljaBG4ue79Ekzb12QfJ52L9Q98tl8SWhw= +github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= @@ -253,7 +254,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= @@ -261,22 +261,23 @@ github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htX github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk= -github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI= +github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -293,8 +294,8 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= @@ -312,7 +313,6 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg= github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -366,16 +366,19 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= +github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= +github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -389,18 +392,18 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= -github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= +github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= -github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -413,8 +416,8 @@ github.com/gorilla/csrf v1.7.1 h1:Ir3o2c1/Uzj6FBxMlAUB6SivgVMy1ONXwYgXn+/aHPE= github.com/gorilla/csrf v1.7.1/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= @@ -434,9 +437,8 @@ github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0 h1:f4tg github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0/go.mod h1:hKAkSgNkL0FII46ZkJcpVEAai4KV+swlIWCKfekd1pA= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3 h1:o95KDiV/b1xdkumY5YbLR0/n2+wBxUpgf3HgfKgTyLI= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.3/go.mod h1:hTxjzRcX49ogbTGVJ1sM5mz5s+SSgiGIyL3jjPxl32E= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.2-0.20231120080707-5e5867a3a4b0 h1:GrtGrVoGhFkqHHD4CkcULpMFE3b+PCrYHrf+Z2zlAgQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.2-0.20231120080707-5e5867a3a4b0/go.mod h1:TqYzBEZ4nh11Kg7YWLR3xZ0WgChhCC8NrheYg/WyqaI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= @@ -445,8 +447,8 @@ github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hellofresh/health-go/v5 v5.3.0 h1:T0tapAAuqVIiagRn0YQzFoIPAQek120/vQYPxpMMJ9M= -github.com/hellofresh/health-go/v5 v5.3.0/go.mod h1:N6MLoACjLHjQQhQh+m2S1rXj1PuSBs/5uI32JKBzwf8= +github.com/hellofresh/health-go/v5 v5.5.0 h1:N6zl1kOTTRsn26Bvo0KLTFSrK3iBOekhCLj3jbP9brI= +github.com/hellofresh/health-go/v5 v5.5.0/go.mod h1:+eIMwQtFWKlrl9kE+eLeK//f97xAewFg2pP1U1v+Svg= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -511,8 +513,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -542,9 +544,10 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= +github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= @@ -568,12 +571,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt/v2 v2.5.2 h1:DhGH+nKt+wIkDxM6qnVSKjokq5t59AZV5HRcFW0zJwU= github.com/nats-io/jwt/v2 v2.5.2/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI= -github.com/nats-io/nats-server/v2 v2.10.1 h1:MIJ614dhOIdo71iSzY8ln78miXwrYvlvXHUyS+XdKZQ= -github.com/nats-io/nats-server/v2 v2.10.1/go.mod h1:3PMvMSu2cuK0J9YInRLWdFpFsswKKGUS77zVSAudRto= -github.com/nats-io/nats.go v1.30.2 h1:aloM0TGpPorZKQhbAkdCzYDj+ZmsJDyeo3Gkbr72NuY= -github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM= -github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk= -github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= +github.com/nats-io/nats-server/v2 v2.10.4 h1:uB9xcwon3tPXWAdmTJqqqC6cie3yuPWHJjjTBgaPNus= +github.com/nats-io/nats-server/v2 v2.10.4/go.mod h1:eWm2JmHP9Lqm2oemB6/XGi0/GwsZwtWf8HIPUsh+9ns= +github.com/nats-io/nats.go v1.31.0 h1:/WFBHEc/dOKBF6qf1TZhrdEfTmOZ5JzdJ+Y3m6Y/p7E= +github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= +github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY= +github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= @@ -595,11 +598,12 @@ github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -608,9 +612,11 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= @@ -632,8 +638,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -645,13 +651,12 @@ github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/ github.com/prometheus/statsd_exporter v0.22.7 h1:7Pji/i2GuhK6Lu7DHrtTkFmNBCudCPT1pX2CziuyQR0= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= -github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/redis/go-redis/v9 v9.3.0 h1:RiVDjmig62jIWp7Kk4XVLs0hzV6pI3PyTnnL0cnn0u0= +github.com/redis/go-redis/v9 v9.3.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -660,6 +665,10 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= +github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0= @@ -680,10 +689,12 @@ github.com/smarty/assertions v1.15.1/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+ github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/assertions v1.13.1 h1:Ef7KhSmjZcK6AVf9YbJdvPYG9avaF0ZxudX+ThRdWfU= github.com/smartystreets/assertions v1.13.1/go.mod h1:cXr/IwVfSo/RbCSPhoAPv73p3hlSdrBH/b3SdnW/LMY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -694,16 +705,14 @@ github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= +github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= @@ -722,11 +731,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg= @@ -746,8 +755,9 @@ github.com/uptrace/bun/dialect/pgdialect v1.1.16/go.mod h1:KQjfx/r6JM0OXfbv0rFrx github.com/uptrace/bun/driver/pgdriver v1.1.16 h1:b/NiSXk6Ldw7KLfMLbOqIkm4odHd7QiNOCPLqPFJjK4= github.com/uptrace/bun/driver/pgdriver v1.1.16/go.mod h1:Rmfbc+7lx1z/umjMyAxkOHK81LgnGj71XC5YpA6k1vU= github.com/vitorsalgado/mocha/v2 v2.0.2 h1:wb1QCRzVkp8uhRcUYmb9jJfbMj/qbiqcDyD8rD+Ldfw= -github.com/vmihailenco/msgpack/v5 v5.4.0 h1:hRM0digJwyR6vll33NNAwCFguy5JuBD6jxDmQP3l608= -github.com/vmihailenco/msgpack/v5 v5.4.0/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vitorsalgado/mocha/v2 v2.0.2/go.mod h1:l7jRVm7KTL4VAxxazH99UVo+KzwztjrYpFTksTmL1DE= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -771,39 +781,38 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0 h1:CaagQrotQLgtDlHU6u9pE/Mf4mAwiLD8wrReIVt06lY= -go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0/go.mod h1:LOjFy00/ZMyMYfKFPta6kZe2cDUc1sNo/qtv1pSORWA= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= -go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0 h1:Nw7Dv4lwvGrI68+wULbcq7su9K2cebeCUrDjVrUJHxM= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.19.0/go.mod h1:1MsF6Y7gTqosgoZvHlzcaaM8DIMNZgJh87ykokoNH7Y= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= -go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= -go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.0 h1:HxJLvY878W39Q/yHlZW//4TXCPNth9t1MV1DcpoXzs0= +go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.46.0/go.mod h1:obCHBtvpRB//1iCFOeLyJtdd5aN2ZT0MAmYbxhIpo4M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0/go.mod h1:HyABWq60Uy1kjJSa2BVOxUVao8Cdick5AWSKPutqy6U= +go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= +go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0 h1:4s9HxB4azeeQkhY0GE5wZlMj4/pz8tE5gx2OQpGUw58= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.20.0/go.mod h1:djVA3TUJ2fSdMX0JE5XxFBOaZzprElJoP7fD4vnV2SU= +go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= +go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= +go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= +go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.packetbroker.org/api/iam v1.7.0 h1:JBPaR6xLcmZvCx7VXIET6SgIjyswnpvsoMyPTMPsVls= -go.packetbroker.org/api/iam v1.7.0/go.mod h1:3xdC7qtWtDJh3Tjb1TueoDGAtrOizE2onrY1K6+Gm6U= -go.packetbroker.org/api/iam/v2 v2.7.13 h1:uVNOGFAUttLcvYcC+ZrOXOPEZYkV47gxMyLm9viv+vo= -go.packetbroker.org/api/iam/v2 v2.7.13/go.mod h1:HPBEl7oTtmxSq762h9WW3zyGMvZXnoNQIopczUV7gEE= -go.packetbroker.org/api/mapping/v2 v2.1.32 h1:SeJ4oc+BYAUzUpZWkGJg9YtKZy/D1IDss9O2dX/NW54= -go.packetbroker.org/api/mapping/v2 v2.1.32/go.mod h1:I2qf9dWkMAH+uRY8Q/5gGxv68wLJBRRt48niAlOQ1NY= -go.packetbroker.org/api/routing v1.8.23 h1:fCPGt6zYKZ+/RW60nVnxe+yn4gck0Hcr6VAgU0PD+4U= -go.packetbroker.org/api/routing v1.8.23/go.mod h1:NmFAo4VGGGEYIHKdD0Tmk03f5e81NSYu8QApAF7vONs= -go.packetbroker.org/api/v3 v3.15.2 h1:CqBWwsqU3q7URTcwZEa+cJ+Stpc97ZVIXTMZlUJiFHM= -go.packetbroker.org/api/v3 v3.15.2/go.mod h1:6bVbdWAYLnvZ5kgXxA7GBQvZTN7vxI0DoF1Di1NoAT4= +go.packetbroker.org/api/iam v1.8.1 h1:x4p0kxfzOQ0dhxQUCAmFqXsBMB6BWpVTnPvtFzDgzd4= +go.packetbroker.org/api/iam v1.8.1/go.mod h1:MRgGTxJwPM7spA3SB6qe6ARvbqBkUEExLe/MFb6Ol4Y= +go.packetbroker.org/api/iam/v2 v2.9.0 h1:abBdj56opWeWFXXbLnCCf5Ao1bht+bPcWZZlPYLwhXY= +go.packetbroker.org/api/iam/v2 v2.9.0/go.mod h1:Z2uiw0kwDHBwRgdfYfZsg4GQEpI0JfWOMOJdJo81jGU= +go.packetbroker.org/api/mapping/v2 v2.3.0 h1:aGLF21uGcDssucTX3TMmEvrtWl29+mI/pdTFnPG2+zs= +go.packetbroker.org/api/mapping/v2 v2.3.0/go.mod h1:SmnnK2mwsUeS09xeKXrA96VUZrd8hd1lPvrR4jAboiM= +go.packetbroker.org/api/routing v1.9.1 h1:HhIIYH75njzPoDSFIFgqV6no3/h+x8HGIYcLHm2V86g= +go.packetbroker.org/api/routing v1.9.1/go.mod h1:om1s5jnhezPlpsemK8uJonH9YzRoqvIp0mCBTtfpLc0= +go.packetbroker.org/api/v3 v3.17.0 h1:7yHGYrKt457JwD/nAN8ouXD8B3NrSpbDIwZCKL3l6vc= +go.packetbroker.org/api/v3 v3.17.0/go.mod h1:6bVbdWAYLnvZ5kgXxA7GBQvZTN7vxI0DoF1Di1NoAT4= go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e h1:TWGQ3lh7gI2W5hnb6qPdpoAa0d7s/XPwvgf2VVCMJaY= go.thethings.network/lorawan-application-payload v0.0.0-20220125153912-1198ff1e403e/go.mod h1:/smENFuESiJCyWRsHRLBjbZGMN889BORQXIPP6NlpZE= go.thethings.network/lorawan-stack-legacy/v2 v2.1.0 h1:xP1fElQiH8/6GWXg6JG8UqRD0uluhmicIRS4e/BzcAw= @@ -812,7 +821,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -832,11 +842,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -847,13 +856,13 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= -golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= +golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M= +golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -876,6 +885,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -917,10 +927,10 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -934,8 +944,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210413134643-5e61552d6c78/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= +golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -949,8 +959,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1009,17 +1020,16 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1031,8 +1041,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1091,6 +1102,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1117,16 +1129,17 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.134.0 h1:ktL4Goua+UBgoP1eL1/60LwZJqa1sIzkLmvoR3hR6Gw= -google.golang.org/api v0.134.0/go.mod h1:sjRL3UnjTx5UqNQS9EWr9N8p7xbHpy1k0XGRLCf3Spk= +google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA= +google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1152,7 +1165,6 @@ google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1167,12 +1179,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230911183012-2d3300fd4832 h1:/30npZKtUjXqju7ZA2MsvpkGKD4mQFtf+zPnZasABjg= -google.golang.org/genproto v0.0.0-20230911183012-2d3300fd4832/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230911183012-2d3300fd4832 h1:4E7rZzBdR5LmiZx6n47Dg4AjH8JLhMQWywsYqvXNLcs= -google.golang.org/genproto/googleapis/api v0.0.0-20230911183012-2d3300fd4832/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832 h1:o4LtQxebKIJ4vkzyhtD2rfUNZ20Zf0ik5YVP5E7G7VE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230911183012-2d3300fd4832/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U= +google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1187,15 +1199,12 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= -google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/examples v0.0.0-20210424002626-9572fd6faeae/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1233,7 +1242,6 @@ gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1254,6 +1262,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo= mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/package.json b/package.json index f466eba1ea..cfc6aaeabc 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "ttn-stack", - "version": "3.27.2", + "version": "3.28.1", "description": "The Things Stack", "main": "index.js", "repository": "https://github.com/TheThingsNetwork/lorawan-stack.git", "license": "Apache-2.0", "devDependencies": { - "@babel/cli": "^7.22.9", + "@babel/cli": "^7.23.0", "@babel/core": "^7.22.5", "@babel/eslint-parser": "^7.22.9", "@babel/plugin-proposal-class-properties": "^7.18.6", @@ -15,10 +15,10 @@ "@babel/plugin-transform-runtime": "^7.22.10", "@babel/plugin-transform-spread": "^7.22.5", "@babel/plugin-transform-strict-mode": "^7.22.5", - "@babel/preset-env": "^7.22.5", - "@babel/preset-react": "^7.22.5", - "@babel/register": "^7.22.5", - "@babel/runtime-corejs2": "^7.22.5", + "@babel/preset-env": "^7.23.2", + "@babel/preset-react": "^7.22.15", + "@babel/register": "^7.22.15", + "@babel/runtime-corejs2": "^7.23.5", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", "@storybook/addon-actions": "^7.0.24", "@storybook/addon-info": "6.0.0-alpha.2", @@ -38,12 +38,12 @@ "cypress-file-upload": "^5.0.8", "cypress-log-to-output": "^1.1.2", "eslint": "^8.44.0", - "eslint-config-prettier": "^8.8.0", + "eslint-config-prettier": "^9.0.0", "eslint-config-ttn": "git+https://github.com/TheThingsNetwork/eslint-config-ttn.git#v1.4.0", - "eslint-import-resolver-webpack": "^0.13.7", + "eslint-import-resolver-webpack": "^0.13.8", "eslint-plugin-babel": "^5.3.1", "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-import": "^2.27.5", + "eslint-plugin-import": "^2.29.0", "eslint-plugin-jest": "^27.2.3", "eslint-plugin-jsdoc": "^46.8.2", "eslint-plugin-prefer-arrow": "^1.2.3", @@ -66,7 +66,7 @@ "stylint": "^2.0.0", "stylus": "^0.59.0", "stylus-loader": "^7.1.3", - "wait-on": "^7.0.1", + "wait-on": "^7.2.0", "webpack": "^5.88.2", "webpack-cli": "^5.1.4", "webpack-dev-server": "^4.15.1", @@ -76,12 +76,12 @@ "dependencies": { "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-displaynames": "^6.5.0", - "@formatjs/intl-listformat": "^7.4.0", + "@formatjs/intl-listformat": "^7.5.3", "@formatjs/intl-locale": "^3.3.2", "@formatjs/intl-numberformat": "^8.7.0", - "@formatjs/intl-pluralrules": "^5.2.4", + "@formatjs/intl-pluralrules": "^5.2.7", "@formatjs/intl-relativetimeformat": "^11.2.4", - "@sentry/browser": "^7.57.0", + "@sentry/browser": "^7.77.0", "@sentry/integrations": "^7.61.0", "@tippyjs/react": "^4.2.6", "autobind-decorator": "^2.4.0", diff --git a/pkg/applicationserver/io/web/health_sink.go b/pkg/applicationserver/io/web/health_sink.go index 1b247a912f..0adc3a0f2e 100644 --- a/pkg/applicationserver/io/web/health_sink.go +++ b/pkg/applicationserver/io/web/health_sink.go @@ -46,21 +46,28 @@ func (reg *healthStatusRegistry) Get(r *http.Request) (*ttnpb.ApplicationWebhook } // Set implements HealthStatusRegistry. -func (reg *healthStatusRegistry) Set(r *http.Request, f func(*ttnpb.ApplicationWebhookHealth) (*ttnpb.ApplicationWebhookHealth, error)) error { +func (reg *healthStatusRegistry) Set( + r *http.Request, f func(*ttnpb.ApplicationWebhookHealth) (*ttnpb.ApplicationWebhookHealth, error), +) error { ctx := r.Context() ids := webhookIDFromContext(ctx) - _, err := reg.registry.Set(ctx, ids, []string{"health_status"}, func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { - if wh == nil { - // The webhook has been deleted during execution. - return nil, nil, nil - } - new, err := f(wh.HealthStatus) - if err != nil { - return nil, nil, err - } - wh.HealthStatus = new - return wh, []string{"health_status"}, nil - }) + _, err := reg.registry.Set( + ctx, + ids, + []string{"health_status"}, + func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { + if wh == nil { + // The webhook has been deleted during execution. + return nil, nil, nil + } + updated, err := f(wh.HealthStatus) + if err != nil { + return nil, nil, err + } + wh.HealthStatus = updated + return wh, []string{"health_status"}, nil + }, + ) return err } @@ -91,7 +98,9 @@ func (reg *cachedHealthStatusRegistry) Get(r *http.Request) (*ttnpb.ApplicationW } // Set implements HealthStatusRegistry. -func (reg *cachedHealthStatusRegistry) Set(r *http.Request, f func(*ttnpb.ApplicationWebhookHealth) (*ttnpb.ApplicationWebhookHealth, error)) error { +func (reg *cachedHealthStatusRegistry) Set( + r *http.Request, f func(*ttnpb.ApplicationWebhookHealth) (*ttnpb.ApplicationWebhookHealth, error), +) error { return reg.registry.Set(r, f) } @@ -111,67 +120,87 @@ type healthCheckSink struct { // Process runs the health checks and sends the request to the underlying sink // if they pass. func (hcs *healthCheckSink) Process(r *http.Request) error { - healthy, err := hcs.preRunCheck(r) + lastKnownState, err := hcs.preRunCheck(r) if err != nil { return err } - return hcs.executeAndRecord(r, healthy) + return hcs.executeAndRecord(r, lastKnownState) } +type healthState int + +const ( + healthStateUnknown healthState = iota + healthStateHealthy + healthStateMonitorSkipRecord + healthStateMonitorRecord + healthStateUnhealthy +) + var errWebhookDisabled = errors.DefineAborted("webhook_disabled", "webhook disabled") // preRunCheck verifies if the webhook should be executed. -func (hcs *healthCheckSink) preRunCheck(r *http.Request) (bool, error) { +func (hcs *healthCheckSink) preRunCheck(r *http.Request) (healthState, error) { h, err := hcs.registry.Get(r) if err != nil { - return false, err + return healthStateUnknown, err } switch { - case h == nil: + case h == nil, h.Status == nil: + return healthStateUnknown, nil case h.GetHealthy() != nil: - return true, nil + return healthStateHealthy, nil case h.GetUnhealthy() != nil: h := h.GetUnhealthy() - lastFailedAttemptAt := ttnpb.StdTime(h.LastFailedAttemptAt) - nextAttemptAt := lastFailedAttemptAt.Add(hcs.unhealthyRetryInterval) - now := time.Now() + monitorOnly := hcs.unhealthyAttemptsThreshold <= 0 || hcs.unhealthyRetryInterval <= 0 + nextAttemptAt := ttnpb.StdTime(h.LastFailedAttemptAt).Add(hcs.unhealthyRetryInterval) + retryIntervalPassed := time.Now().After(nextAttemptAt) switch { - case hcs.unhealthyAttemptsThreshold <= 0: + case monitorOnly: // The system only monitors the health status, but does not block execution. + if retryIntervalPassed { + return healthStateMonitorRecord, nil + } + return healthStateMonitorSkipRecord, nil case h.FailedAttempts < uint64(hcs.unhealthyAttemptsThreshold): // The webhook is unhealthy but it has not failed enough times to be disabled yet. // This comparison is racing, as we may allow multiple webhooks at a time to execute // under the assumption that we are still under the threshold. However, serializing the // execution of unhealthy webhooks is considered costly, so we allow the race to occur. + return healthStateUnhealthy, nil - case h.FailedAttempts >= uint64(hcs.unhealthyAttemptsThreshold) && now.After(nextAttemptAt): + case h.FailedAttempts >= uint64(hcs.unhealthyAttemptsThreshold) && retryIntervalPassed: // The webhook is above the threshold, but the cooldown period has elapsed. + return healthStateUnhealthy, nil default: // The webhook is above the threshold, and the cooldown period has not passed yet. - return false, errWebhookDisabled.New() + return healthStateUnhealthy, errWebhookDisabled.New() } default: panic("unreachable") } - - return false, nil } // executeAndRecord runs the provided request using the underlying sink and records the health status. -func (hcs *healthCheckSink) executeAndRecord(r *http.Request, healthy bool) error { +func (hcs *healthCheckSink) executeAndRecord(r *http.Request, lastKnownState healthState) error { sinkErr := hcs.sink.Process(r) - // Fast path: the health status is available, the request did not error, and the webhook is healthy. - if sinkErr == nil && healthy { + // Fast path 1: the health status is available, the request did not error, and the webhook is healthy. + if sinkErr == nil && lastKnownState == healthStateHealthy { return nil } + // Fast path 2: the health status is available, the request did error, and the webhook is unhealthy. + if sinkErr != nil && lastKnownState == healthStateMonitorSkipRecord { + return sinkErr + } + // Slow path: the request did error, or the webhook is unhealthy. var details *ttnpb.ErrorDetails if sinkErr != nil { @@ -205,7 +234,9 @@ func (hcs *healthCheckSink) executeAndRecord(r *http.Request, healthy bool) erro // NewHealthCheckSink creates a Sink that records the health status of the webhooks and stops them from executing if // too many fail in a specified interval of time. -func NewHealthCheckSink(sink Sink, registry HealthStatusRegistry, unhealthyAttemptsThreshold int, unhealthyRetryInterval time.Duration) Sink { +func NewHealthCheckSink( + sink Sink, registry HealthStatusRegistry, unhealthyAttemptsThreshold int, unhealthyRetryInterval time.Duration, +) Sink { return &healthCheckSink{ sink: sink, registry: registry, diff --git a/pkg/applicationserver/io/web/health_sink_test.go b/pkg/applicationserver/io/web/health_sink_test.go index bc01185f5e..39c90bb576 100644 --- a/pkg/applicationserver/io/web/health_sink_test.go +++ b/pkg/applicationserver/io/web/health_sink_test.go @@ -35,6 +35,8 @@ var registeredWebhookIDs = &ttnpb.ApplicationWebhookIdentifiers{ } func TestHealthStatusRegistry(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) redisClient, flush := test.NewRedis(ctx, "web_test") @@ -48,18 +50,25 @@ func TestHealthStatusRegistry(t *testing.T) { t.FailNow() } - _, err := webhookRegistry.Set(ctx, registeredWebhookIDs, nil, func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { - return &ttnpb.ApplicationWebhook{ - Ids: registeredWebhookIDs, - BaseUrl: "http://example.com", - Format: "json", - }, []string{"ids", "base_url", "format"}, nil - }) + _, err := webhookRegistry.Set( + ctx, + registeredWebhookIDs, + nil, + func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { + return &ttnpb.ApplicationWebhook{ + Ids: registeredWebhookIDs, + BaseUrl: "http://example.com", + Format: "json", + }, []string{"ids", "base_url", "format"}, nil + }, + ) if !a.So(err, should.BeNil) { t.FailNow() } - r, err := http.NewRequestWithContext(web.WithWebhookID(ctx, registeredWebhookIDs), http.MethodPost, "http://foo.bar", nil) + r, err := http.NewRequestWithContext( + web.WithWebhookID(ctx, registeredWebhookIDs), http.MethodPost, "http://foo.bar", nil, + ) if !a.So(err, should.BeNil) { t.FailNow() } @@ -193,7 +202,9 @@ func TestHealthStatusRegistry(t *testing.T) { }) } -func TestHealthCheckSink(t *testing.T) { +func TestHealthCheckSink(t *testing.T) { // nolint:gocyclo + t.Parallel() + a, ctx := test.New(t) redisClient, flush := test.NewRedis(ctx, "web_test") @@ -207,13 +218,18 @@ func TestHealthCheckSink(t *testing.T) { t.FailNow() } - _, err := webhookRegistry.Set(ctx, registeredWebhookIDs, nil, func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { - return &ttnpb.ApplicationWebhook{ - Ids: registeredWebhookIDs, - BaseUrl: "http://example.com", - Format: "json", - }, []string{"ids", "base_url", "format"}, nil - }) + _, err := webhookRegistry.Set( + ctx, + registeredWebhookIDs, + nil, + func(wh *ttnpb.ApplicationWebhook) (*ttnpb.ApplicationWebhook, []string, error) { + return &ttnpb.ApplicationWebhook{ + Ids: registeredWebhookIDs, + BaseUrl: "http://example.com", + Format: "json", + }, []string{"ids", "base_url", "format"}, nil + }, + ) if !a.So(err, should.BeNil) { t.FailNow() } @@ -225,13 +241,18 @@ func TestHealthCheckSink(t *testing.T) { registry := web.NewHealthStatusRegistry(webhookRegistry) healthSink := web.NewHealthCheckSink(sink, registry, 4, 8*Timeout) - r, err := http.NewRequestWithContext(web.WithWebhookID(ctx, registeredWebhookIDs), http.MethodPost, "http://foo.bar", nil) + r, err := http.NewRequestWithContext( + web.WithWebhookID(ctx, registeredWebhookIDs), http.MethodPost, "http://foo.bar", nil, + ) if !a.So(err, should.BeNil) { t.FailNow() } // No processing error - the webhook should move to healthy. err = healthSink.Process(r) + if !a.So(err, should.BeNil) { + t.FailNow() + } select { case <-sink.ch: case <-time.After(Timeout): @@ -255,6 +276,9 @@ func TestHealthCheckSink(t *testing.T) { for i := 1; i <= 4; i++ { now := time.Now() err = healthSink.Process(r) + if !a.So(err, should.HaveSameErrorDefinitionAs, requestErr) { + t.FailNow() + } select { case <-sink.ch: case <-time.After(Timeout): @@ -277,6 +301,9 @@ func TestHealthCheckSink(t *testing.T) { for i := 1; i <= 4; i++ { // The request should not reach the underlying sink. err = healthSink.Process(r) + if !a.So(err, should.NotBeNil) { + t.FailNow() + } select { case <-sink.ch: t.Fatal("unexpected request") @@ -300,6 +327,9 @@ func TestHealthCheckSink(t *testing.T) { for i := 1; i <= 4; i++ { now := time.Now() err = healthSink.Process(r) + if !a.So(err, should.NotBeNil) { + t.FailNow() + } if i == 1 { select { case <-sink.ch: @@ -339,6 +369,9 @@ func TestHealthCheckSink(t *testing.T) { // No processing error - the webhook should move to healthy. for i := 1; i <= 4; i++ { err = healthSink.Process(r) + if !a.So(err, should.BeNil) { + t.FailNow() + } select { case <-sink.ch: case <-time.After(Timeout): diff --git a/pkg/applicationserver/observability.go b/pkg/applicationserver/observability.go index d9dfcd3784..63a9466e38 100644 --- a/pkg/applicationserver/observability.go +++ b/pkg/applicationserver/observability.go @@ -178,14 +178,6 @@ var asMetrics = &messageMetrics{ }, []string{"error"}, ), - uplinkPayloadValueViolations: metrics.NewContextualCounterVec( - prometheus.CounterOpts{ - Subsystem: subsystem, - Name: "uplink_payload_value_violations_total", - Help: "Total number of uplink payload value violations", - }, - []string{"payload_formatter", "value_context", "value_type"}, - ), nsAsUplinkLatency: metrics.NewContextualHistogramVec( prometheus.HistogramOpts{ Subsystem: "ns_as", @@ -228,14 +220,6 @@ var asMetrics = &messageMetrics{ }, []string{"error"}, ), - downlinkPayloadValueViolations: metrics.NewContextualCounterVec( - prometheus.CounterOpts{ - Subsystem: subsystem, - Name: "downlink_payload_value_violations_total", - Help: "Total number of downlink payload value violations when decoding downlink messages", - }, - []string{"payload_formatter", "value_context", "value_type"}, - ), } func init() { @@ -243,42 +227,36 @@ func init() { } type messageMetrics struct { - uplinkReceived *metrics.ContextualCounterVec - uplinkForwarded *metrics.ContextualCounterVec - uplinkDropped *metrics.ContextualCounterVec - uplinkPayloadValueViolations *metrics.ContextualCounterVec - nsAsUplinkLatency *metrics.ContextualHistogramVec - gtwAsUplinkLatency *metrics.ContextualHistogramVec - downlinkReceived *metrics.ContextualCounterVec - downlinkForwarded *metrics.ContextualCounterVec - downlinkDropped *metrics.ContextualCounterVec - downlinkPayloadValueViolations *metrics.ContextualCounterVec + uplinkReceived *metrics.ContextualCounterVec + uplinkForwarded *metrics.ContextualCounterVec + uplinkDropped *metrics.ContextualCounterVec + nsAsUplinkLatency *metrics.ContextualHistogramVec + gtwAsUplinkLatency *metrics.ContextualHistogramVec + downlinkReceived *metrics.ContextualCounterVec + downlinkForwarded *metrics.ContextualCounterVec + downlinkDropped *metrics.ContextualCounterVec } func (m messageMetrics) Describe(ch chan<- *prometheus.Desc) { m.uplinkReceived.Describe(ch) m.uplinkForwarded.Describe(ch) m.uplinkDropped.Describe(ch) - m.uplinkPayloadValueViolations.Describe(ch) m.nsAsUplinkLatency.Describe(ch) m.gtwAsUplinkLatency.Describe(ch) m.downlinkReceived.Describe(ch) m.downlinkForwarded.Describe(ch) m.downlinkDropped.Describe(ch) - m.downlinkPayloadValueViolations.Describe(ch) } func (m messageMetrics) Collect(ch chan<- prometheus.Metric) { m.uplinkReceived.Collect(ch) m.uplinkForwarded.Collect(ch) m.uplinkDropped.Collect(ch) - m.uplinkPayloadValueViolations.Collect(ch) m.nsAsUplinkLatency.Collect(ch) m.gtwAsUplinkLatency.Collect(ch) m.downlinkReceived.Collect(ch) m.downlinkForwarded.Collect(ch) m.downlinkDropped.Collect(ch) - m.downlinkPayloadValueViolations.Collect(ch) } func registerReceiveUp(ctx context.Context, msg *ttnpb.ApplicationUp) { diff --git a/pkg/applicationserver/payload.go b/pkg/applicationserver/payload.go index 193fd3aace..568e29c31c 100644 --- a/pkg/applicationserver/payload.go +++ b/pkg/applicationserver/payload.go @@ -25,10 +25,8 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/events" "go.thethings.network/lorawan-stack/v3/pkg/goproto" "go.thethings.network/lorawan-stack/v3/pkg/log" - "go.thethings.network/lorawan-stack/v3/pkg/metrics" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/types" - "google.golang.org/protobuf/types/known/structpb" ) var ( @@ -36,21 +34,6 @@ var ( errNoFPort = errors.DefineInvalidArgument("no_f_port", "no FPort") ) -func recordPayloadValueViolations( - ctx context.Context, - counter *metrics.ContextualCounterVec, - formatter ttnpb.PayloadFormatter, - decodedPayload *structpb.Struct, -) { - violations := FindViolations(decodedPayload) - if len(violations) == 0 { - return - } - for _, violation := range violations { - counter.WithLabelValues(ctx, formatter.String(), violation.Context.String(), violation.Type.String()).Inc() - } -} - func (as *ApplicationServer) encodeDownlink(ctx context.Context, dev *ttnpb.EndDevice, downlink *ttnpb.ApplicationDownlink, defaultFormatters *ttnpb.MessagePayloadFormatters) error { if downlink.FrmPayload == nil && downlink.DecodedPayload == nil { return errNoPayload.New() @@ -177,7 +160,6 @@ func (as *ApplicationServer) decodeUplink(ctx context.Context, dev *ttnpb.EndDev } if len(uplink.DecodedPayloadWarnings) > 0 { events.Publish(evtDecodeWarningDataUp.NewWithIdentifiersAndData(ctx, dev.Ids, uplink)) - recordPayloadValueViolations(ctx, asMetrics.uplinkPayloadValueViolations, formatter, uplink.DecodedPayload) } if len(uplink.NormalizedPayloadWarnings) > 0 { events.Publish(evtNormalizeWarningDataUp.NewWithIdentifiersAndData(ctx, dev.Ids, uplink)) @@ -237,7 +219,6 @@ func (as *ApplicationServer) decodeDownlink(ctx context.Context, dev *ttnpb.EndD } if len(downlink.DecodedPayloadWarnings) > 0 { events.Publish(evtDecodeWarningDataDown.NewWithIdentifiersAndData(ctx, dev.Ids, downlink)) - recordPayloadValueViolations(ctx, asMetrics.downlinkPayloadValueViolations, formatter, downlink.DecodedPayload) } return nil } diff --git a/pkg/applicationserver/violations.go b/pkg/applicationserver/violations.go deleted file mode 100644 index 26fc786096..0000000000 --- a/pkg/applicationserver/violations.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright © 2023 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 applicationserver - -import ( - "google.golang.org/protobuf/types/known/structpb" -) - -// ValueType is the type of value violation (NaN, Infinity, -Infinity). -type ValueType string - -func (vt ValueType) String() string { - return string(vt) -} - -const ( - // ValueTypeNaN is a NaN violation. - ValueTypeNaN ValueType = "NaN" - - // ValueTypePosInf is a positive Infinity violation. - ValueTypePosInf ValueType = "Infinity" - - // ValueTypeNegInf is a negative Infinity violation. - ValueTypeNegInf ValueType = "-Infinity" -) - -// ValueContext is the context in which the value is located (struct, list). -type ValueContext string - -func (vt ValueContext) String() string { - return string(vt) -} - -const ( - // ValueContextStruct indicates a violation in a struct. - ValueContextStruct ValueContext = "struct" - - // ValueContextList indicates a violation in a list. - ValueContextList ValueContext = "list" -) - -// ValueViolation is a violation of a value. -type ValueViolation struct { - Type ValueType - Context ValueContext -} - -func findViolation(s string, valueContext ValueContext) *ValueViolation { - violation := ValueType(s) - switch violation { - case ValueTypeNaN: - return &ValueViolation{ - Type: ValueTypeNaN, - Context: valueContext, - } - case ValueTypePosInf: - return &ValueViolation{ - Type: ValueTypePosInf, - Context: valueContext, - } - case ValueTypeNegInf: - return &ValueViolation{ - Type: ValueTypeNegInf, - Context: valueContext, - } - } - return nil -} - -func findListViolations(l *structpb.ListValue) []ValueViolation { - if l == nil { - return nil - } - total := make([]ValueViolation, 0) - for _, v := range l.Values { - switch vv := v.GetKind().(type) { - case *structpb.Value_StringValue: - if vv == nil { - break - } - violation := findViolation(vv.StringValue, ValueContextList) - if violation != nil { - total = append(total, *violation) - } - case *structpb.Value_StructValue: - if vv == nil { - break - } - total = append(total, findStructViolations(vv.StructValue)...) - case *structpb.Value_ListValue: - if vv == nil { - break - } - total = append(total, findListViolations(vv.ListValue)...) - } - } - return total -} - -func findStructViolations(st *structpb.Struct) []ValueViolation { - if st == nil { - return nil - } - total := make([]ValueViolation, 0) - for _, v := range st.Fields { - switch vv := v.GetKind().(type) { - case *structpb.Value_StringValue: - if vv == nil { - break - } - violation := findViolation(vv.StringValue, ValueContextStruct) - if violation != nil { - total = append(total, *violation) - } - case *structpb.Value_StructValue: - if vv == nil { - break - } - stViolations := findStructViolations(vv.StructValue) - if len(stViolations) > 0 { - total = append(total, stViolations...) - } - case *structpb.Value_ListValue: - if vv == nil { - break - } - listViolations := findListViolations(vv.ListValue) - if len(listViolations) > 0 { - total = append(total, listViolations...) - } - } - } - return total -} - -// FindViolations recursively verifies if the struct contains any invalid values (NaN, -Infinity, Infinity) -// and creates ValueViolations for such fields. -func FindViolations(st *structpb.Struct) []ValueViolation { - return findStructViolations(st) -} diff --git a/pkg/applicationserver/violations_test.go b/pkg/applicationserver/violations_test.go deleted file mode 100644 index d8147fc196..0000000000 --- a/pkg/applicationserver/violations_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright © 2023 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 applicationserver - -import ( - "testing" - - "github.com/smarty/assertions" - "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" - "google.golang.org/protobuf/types/known/structpb" -) - -func TestValidateStruct(t *testing.T) { - t.Parallel() - - for _, tc := range []struct { - name string - - st map[string]any - expected []ValueViolation - }{ - { - name: "empty", - }, - { - name: "simple object", - - st: map[string]any{ - "foo": 123, - }, - }, - { - name: "top level NaN", - st: map[string]any{ - "foo": "NaN", - }, - expected: []ValueViolation{ - { - Type: ValueTypeNaN, - Context: ValueContextStruct, - }, - }, - }, - { - name: "nested object Infinity", - - st: map[string]any{ - "foo": map[string]any{ - "bar": "Infinity", - }, - }, - expected: []ValueViolation{ - { - Type: ValueTypePosInf, - Context: ValueContextStruct, - }, - }, - }, - { - name: "nested object -Infinity", - st: map[string]any{ - "foo": []any{"-Infinity"}, - }, - expected: []ValueViolation{ - { - Type: ValueTypeNegInf, - Context: ValueContextList, - }, - }, - }, - { - name: "nested object NaN", - st: map[string]any{ - "foo": []any{ - map[string]any{ - "bar": "NaN", - }, - }, - }, - expected: []ValueViolation{ - { - Type: ValueTypeNaN, - Context: ValueContextStruct, - }, - }, - }, - } { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - - a := assertions.New(t) - - st, err := structpb.NewStruct(tc.st) - if !a.So(err, should.BeNil) { - t.FailNow() - } - - warnings := FindViolations(st) - a.So(warnings, should.Resemble, tc.expected) - }) - } -} diff --git a/pkg/auth/rights/auth_info.go b/pkg/auth/rights/auth_info.go index f6b59c71ab..1a7158ffd3 100644 --- a/pkg/auth/rights/auth_info.go +++ b/pkg/auth/rights/auth_info.go @@ -51,16 +51,14 @@ func AuthInfo(ctx context.Context) (authInfo *ttnpb.AuthInfoResponse, err error) var errUnauthenticated = errors.DefineUnauthenticated("unauthenticated", "unauthenticated") -// RequireAuthentication confirms if the authentication information within a context contains any rights, if so, +// RequireAuthenticated confirms if the authentication information within a context contains any rights, if so, // the request is considered to be authenticated. -func RequireAuthentication(ctx context.Context) error { - log.FromContext(ctx).Debug("Authenticate request") +func RequireAuthenticated(ctx context.Context) error { authInfo, err := AuthInfo(ctx) if err != nil { log.FromContext(ctx).WithError(err).Debug("Failed to validate authentication information") return errUnauthenticated.WithCause(err) } - if authInfo.GetAccessMethod() == nil && len(authInfo.GetUniversalRights().GetRights()) == 0 { return errUnauthenticated.New() } diff --git a/pkg/band/as_923_rp2_v1_0_4.go b/pkg/band/as_923_rp2_v1_0_4.go index c8e85a7bf7..126947e6fe 100644 --- a/pkg/band/as_923_rp2_v1_0_4.go +++ b/pkg/band/as_923_rp2_v1_0_4.go @@ -112,6 +112,6 @@ var as923RP2104Band = func(id string, offset as923GroupOffset) Band { Relay: as923RelayParameters(offset), - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } } diff --git a/pkg/band/au_915_928_rp2_v1_0_4.go b/pkg/band/au_915_928_rp2_v1_0_4.go index d16587ab3c..88973684a6 100644 --- a/pkg/band/au_915_928_rp2_v1_0_4.go +++ b/pkg/band/au_915_928_rp2_v1_0_4.go @@ -112,5 +112,5 @@ var AU_915_928_RP2_v1_0_4 = Band{ Relay: au915928RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/channel_mask.go b/pkg/band/channel_mask.go index 557bb12ee5..466bf14af0 100644 --- a/pkg/band/channel_mask.go +++ b/pkg/band/channel_mask.go @@ -17,8 +17,7 @@ package band import ( "fmt" "math" - - "golang.org/x/exp/slices" + "slices" ) // ChMaskCntlPair pairs a ChMaskCntl with a mask. diff --git a/pkg/band/cn_470_510_20_a_rp2_v1_0_4.go b/pkg/band/cn_470_510_20_a_rp2_v1_0_4.go index de207342c7..be1fad1a2c 100644 --- a/pkg/band/cn_470_510_20_a_rp2_v1_0_4.go +++ b/pkg/band/cn_470_510_20_a_rp2_v1_0_4.go @@ -90,5 +90,5 @@ var CN_470_510_20_A_RP2_v1_0_4 = Band{ Relay: cn470510RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/cn_470_510_20_b_rp2_v1_0_4.go b/pkg/band/cn_470_510_20_b_rp2_v1_0_4.go index 5dd6d84c89..9b42885432 100644 --- a/pkg/band/cn_470_510_20_b_rp2_v1_0_4.go +++ b/pkg/band/cn_470_510_20_b_rp2_v1_0_4.go @@ -90,5 +90,5 @@ var CN_470_510_20_B_RP2_v1_0_4 = Band{ Relay: cn470510RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/cn_470_510_26_a_rp2_v1_0_4.go b/pkg/band/cn_470_510_26_a_rp2_v1_0_4.go index e8711296bb..06fa2a67ee 100644 --- a/pkg/band/cn_470_510_26_a_rp2_v1_0_4.go +++ b/pkg/band/cn_470_510_26_a_rp2_v1_0_4.go @@ -92,5 +92,5 @@ var CN_470_510_26_A_RP2_v1_0_4 = Band{ Relay: cn470510RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/cn_470_510_26_b_rp2_v1_0_4.go b/pkg/band/cn_470_510_26_b_rp2_v1_0_4.go index d97a901a83..07b967c89f 100644 --- a/pkg/band/cn_470_510_26_b_rp2_v1_0_4.go +++ b/pkg/band/cn_470_510_26_b_rp2_v1_0_4.go @@ -92,5 +92,5 @@ var CN_470_510_26_B_RP2_v1_0_4 = Band{ Relay: cn470510RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/eu_433_rp2_v1_0_4.go b/pkg/band/eu_433_rp2_v1_0_4.go index 4ca789cf09..2f45aee35b 100644 --- a/pkg/band/eu_433_rp2_v1_0_4.go +++ b/pkg/band/eu_433_rp2_v1_0_4.go @@ -88,5 +88,5 @@ var EU_433_RP2_V1_0_4 = Band{ }, PingSlotFrequencies: eu433BeaconFrequencies, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/eu_863_870_rp2_v1_0_4.go b/pkg/band/eu_863_870_rp2_v1_0_4.go index 12ca4155df..473cf0925c 100644 --- a/pkg/band/eu_863_870_rp2_v1_0_4.go +++ b/pkg/band/eu_863_870_rp2_v1_0_4.go @@ -133,5 +133,5 @@ var EU_863_870_RP2_V1_0_4 = Band{ Relay: eu863870RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/in_865_867_rp2_v1_0_4.go b/pkg/band/in_865_867_rp2_v1_0_4.go index d32bef896d..f36f0047dd 100644 --- a/pkg/band/in_865_867_rp2_v1_0_4.go +++ b/pkg/band/in_865_867_rp2_v1_0_4.go @@ -100,5 +100,5 @@ var IN_865_867_RP2_V1_0_4 = Band{ Relay: in865867RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/ism_2400_universal.go b/pkg/band/ism_2400_universal.go index 4d5720f077..722c30d15e 100644 --- a/pkg/band/ism_2400_universal.go +++ b/pkg/band/ism_2400_universal.go @@ -86,5 +86,5 @@ var ISM_2400_Universal = Band{ }, PingSlotFrequencies: ism2400BeaconFrequencies, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/kr_920_923_rp2_v1_0_4.go b/pkg/band/kr_920_923_rp2_v1_0_4.go index 92d18a8e85..ad9956443d 100644 --- a/pkg/band/kr_920_923_rp2_v1_0_4.go +++ b/pkg/band/kr_920_923_rp2_v1_0_4.go @@ -89,5 +89,5 @@ var KR_920_923_RP2_V1_0_4 = Band{ Relay: kr920923RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/ma_869_870_draft_universal.go b/pkg/band/ma_869_870_draft_universal.go index c0291fb37b..a936815057 100644 --- a/pkg/band/ma_869_870_draft_universal.go +++ b/pkg/band/ma_869_870_draft_universal.go @@ -106,5 +106,5 @@ var MA_869_870_Draft_Universal = Band{ }, PingSlotFrequencies: ma869870DraftBeaconFrequencies, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/rpc.go b/pkg/band/rpc.go index b8ef75c397..6349468428 100644 --- a/pkg/band/rpc.go +++ b/pkg/band/rpc.go @@ -16,9 +16,9 @@ package band import ( "context" + "maps" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "golang.org/x/exp/maps" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/wrapperspb" ) @@ -150,6 +150,13 @@ func (b Band) BandDescription() *ttnpb.BandDescription { Relay: &ttnpb.BandDescription_RelayParameters{}, } + if b.SharedParameters.RelayForwardDelay != 0 { + bandDescription.RelayForwardDelay = durationpb.New(b.SharedParameters.RelayForwardDelay) + } + if b.SharedParameters.RelayReceiveDelay != 0 { + bandDescription.RelayReceiveDelay = durationpb.New(b.SharedParameters.RelayReceiveDelay) + } + for _, channel := range b.UplinkChannels { bandDescription.UplinkChannels = append(bandDescription.UplinkChannels, &ttnpb.BandDescription_Channel{ Frequency: channel.Frequency, @@ -175,10 +182,10 @@ func (b Band) BandDescription() *ttnpb.BandDescription { }) } - for index, datarate := range b.DataRates { + for index, dataRate := range b.DataRates { bandDescription.DataRates[uint32(index)] = &ttnpb.BandDescription_BandDataRate{ Rate: &ttnpb.DataRate{ - Modulation: datarate.Rate.Modulation, + Modulation: dataRate.Rate.Modulation, }, } } diff --git a/pkg/band/rpc_test.go b/pkg/band/rpc_test.go index cc72aaff20..e35853c5d3 100644 --- a/pkg/band/rpc_test.go +++ b/pkg/band/rpc_test.go @@ -504,6 +504,9 @@ func TestBandConvertToBandDescription(t *testing.T) { ADRAckLimit: ttnpb.ADRAckLimitExponent_ADR_ACK_LIMIT_1, MinRetransmitTimeout: 1 * time.Second, MaxRetransmitTimeout: 2 * time.Second, + + RelayForwardDelay: 3 * time.Second, + RelayReceiveDelay: 4 * time.Second, }, }, Expected: &ttnpb.BandDescription{ @@ -591,6 +594,8 @@ func TestBandConvertToBandDescription(t *testing.T) { }, }, }, + RelayForwardDelay: durationpb.New(3 * time.Second), + RelayReceiveDelay: durationpb.New(4 * time.Second), }, }, { @@ -675,6 +680,9 @@ func TestBandConvertToBandDescription(t *testing.T) { ADRAckLimit: ttnpb.ADRAckLimitExponent_ADR_ACK_LIMIT_1, MinRetransmitTimeout: 1 * time.Second, MaxRetransmitTimeout: 2 * time.Second, + + RelayForwardDelay: 3 * time.Second, + RelayReceiveDelay: 4 * time.Second, }, }, Expected: &ttnpb.BandDescription{ @@ -759,6 +767,8 @@ func TestBandConvertToBandDescription(t *testing.T) { }, }, }, + RelayForwardDelay: durationpb.New(3 * time.Second), + RelayReceiveDelay: durationpb.New(4 * time.Second), }, }, } { diff --git a/pkg/band/ru_864_870_rp2_v1_0_4.go b/pkg/band/ru_864_870_rp2_v1_0_4.go index 0d9e437484..2e43750f47 100644 --- a/pkg/band/ru_864_870_rp2_v1_0_4.go +++ b/pkg/band/ru_864_870_rp2_v1_0_4.go @@ -92,5 +92,5 @@ var RU_864_870_RP2_V1_0_4 = Band{ Relay: ru864870RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/band/shared.go b/pkg/band/shared.go index aed850fa30..b33f055513 100644 --- a/pkg/band/shared.go +++ b/pkg/band/shared.go @@ -44,16 +44,34 @@ type SharedParameters struct { MinRetransmitTimeout time.Duration // MaxRetransmitTimeout is the maximum retransmit timeout. MaxRetransmitTimeout time.Duration -} -var universalSharedParameters = SharedParameters{ - ReceiveDelay1: time.Second, - ReceiveDelay2: 2 * time.Second, - JoinAcceptDelay1: 5 * time.Second, - JoinAcceptDelay2: 6 * time.Second, - MaxFCntGap: 16384, - ADRAckLimit: ttnpb.ADRAckLimitExponent_ADR_ACK_LIMIT_64, - ADRAckDelay: ttnpb.ADRAckDelayExponent_ADR_ACK_DELAY_32, - MinRetransmitTimeout: time.Second, - MaxRetransmitTimeout: 3 * time.Second, + // RelayForwardDelay is the default delay between the end of the uplink transmission and the start of the + // relay transmission. + RelayForwardDelay time.Duration + // RelayReceiveDelay is the default RxR window timing in seconds. + RelayReceiveDelay time.Duration + // ServedRelayBackoff is the default number of wake on radio attempts before sending the uplink message directly + // by a served relay device. + ServedRelayBackoff uint32 } + +var ( + universalSharedParameters = SharedParameters{ + ReceiveDelay1: time.Second, + ReceiveDelay2: 2 * time.Second, + JoinAcceptDelay1: 5 * time.Second, + JoinAcceptDelay2: 6 * time.Second, + MaxFCntGap: 16384, + ADRAckLimit: ttnpb.ADRAckLimitExponent_ADR_ACK_LIMIT_64, + ADRAckDelay: ttnpb.ADRAckDelayExponent_ADR_ACK_DELAY_32, + MinRetransmitTimeout: time.Second, + MaxRetransmitTimeout: 3 * time.Second, + } + relayAwareSharedParameters = func() SharedParameters { + parameters := universalSharedParameters + parameters.RelayForwardDelay = 50 * time.Millisecond + parameters.RelayReceiveDelay = 18 * time.Second + parameters.ServedRelayBackoff = 8 + return parameters + }() +) diff --git a/pkg/band/shared_test.go b/pkg/band/shared_test.go new file mode 100644 index 0000000000..33bfd69f3b --- /dev/null +++ b/pkg/band/shared_test.go @@ -0,0 +1,49 @@ +// Copyright © 2023 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 band_test + +import ( + "fmt" + "testing" + "time" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/band" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +func TestRelaySharedParameters(t *testing.T) { + t.Parallel() + for name, versions := range band.All { + name := name + for version, phy := range versions { + version, phy := version, phy + t.Run(fmt.Sprintf("%v/%v", name, version), func(t *testing.T) { + t.Parallel() + a := assertions.New(t) + var expectedForwardDelay, expectedReceiveDelay time.Duration + switch { + case version == ttnpb.PHYVersion_RP002_V1_0_4, + name == band.ISM_2400, + name == band.MA_869_870_DRAFT: + expectedForwardDelay, expectedReceiveDelay = 50*time.Millisecond, 18*time.Second + } + a.So(phy.RelayForwardDelay, should.Equal, expectedForwardDelay) + a.So(phy.RelayReceiveDelay, should.Equal, expectedReceiveDelay) + }) + } + } +} diff --git a/pkg/band/testdata/AS_923_2_RP002_V1_0_1.json b/pkg/band/testdata/AS_923_2_RP002_V1_0_1.json index a3f0f068a6..a3a59ca60e 100644 --- a/pkg/band/testdata/AS_923_2_RP002_V1_0_1.json +++ b/pkg/band/testdata/AS_923_2_RP002_V1_0_1.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_2_RP002_V1_0_2.json b/pkg/band/testdata/AS_923_2_RP002_V1_0_2.json index 8fc4a83a5b..a9962ab97f 100644 --- a/pkg/band/testdata/AS_923_2_RP002_V1_0_2.json +++ b/pkg/band/testdata/AS_923_2_RP002_V1_0_2.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_2_RP002_V1_0_3.json b/pkg/band/testdata/AS_923_2_RP002_V1_0_3.json index 8fc4a83a5b..a9962ab97f 100644 --- a/pkg/band/testdata/AS_923_2_RP002_V1_0_3.json +++ b/pkg/band/testdata/AS_923_2_RP002_V1_0_3.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_2_RP002_V1_0_4.json b/pkg/band/testdata/AS_923_2_RP002_V1_0_4.json index 6cbe85f58a..941f3da47a 100644 --- a/pkg/band/testdata/AS_923_2_RP002_V1_0_4.json +++ b/pkg/band/testdata/AS_923_2_RP002_V1_0_4.json @@ -708,6 +708,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_3_RP002_V1_0_1.json b/pkg/band/testdata/AS_923_3_RP002_V1_0_1.json index 642e0b3a0f..79424d1fa7 100644 --- a/pkg/band/testdata/AS_923_3_RP002_V1_0_1.json +++ b/pkg/band/testdata/AS_923_3_RP002_V1_0_1.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_3_RP002_V1_0_2.json b/pkg/band/testdata/AS_923_3_RP002_V1_0_2.json index 9537b1065a..d18d7aa61c 100644 --- a/pkg/band/testdata/AS_923_3_RP002_V1_0_2.json +++ b/pkg/band/testdata/AS_923_3_RP002_V1_0_2.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_3_RP002_V1_0_3.json b/pkg/band/testdata/AS_923_3_RP002_V1_0_3.json index 9537b1065a..d18d7aa61c 100644 --- a/pkg/band/testdata/AS_923_3_RP002_V1_0_3.json +++ b/pkg/band/testdata/AS_923_3_RP002_V1_0_3.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_3_RP002_V1_0_4.json b/pkg/band/testdata/AS_923_3_RP002_V1_0_4.json index 6c59a5c0a6..d8448f4bdc 100644 --- a/pkg/band/testdata/AS_923_3_RP002_V1_0_4.json +++ b/pkg/band/testdata/AS_923_3_RP002_V1_0_4.json @@ -708,6 +708,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_4_RP002_V1_0_3.json b/pkg/band/testdata/AS_923_4_RP002_V1_0_3.json index 24d91efa7d..9624681bbd 100644 --- a/pkg/band/testdata/AS_923_4_RP002_V1_0_3.json +++ b/pkg/band/testdata/AS_923_4_RP002_V1_0_3.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_4_RP002_V1_0_4.json b/pkg/band/testdata/AS_923_4_RP002_V1_0_4.json index ee5a17bb63..d3ee567912 100644 --- a/pkg/band/testdata/AS_923_4_RP002_V1_0_4.json +++ b/pkg/band/testdata/AS_923_4_RP002_V1_0_4.json @@ -708,6 +708,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_A.json index 8db420d518..e82567b9ba 100644 --- a/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_A.json @@ -700,6 +700,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_B.json index 1aa09ea9fa..fbca3c42f4 100644 --- a/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/AS_923_PHY_V1_0_2_REV_B.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/AS_923_PHY_V1_0_3_REV_A.json index 7c4fbccae4..1f9387e2e7 100644 --- a/pkg/band/testdata/AS_923_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/AS_923_PHY_V1_0_3_REV_A.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_PHY_V1_1_REV_A.json b/pkg/band/testdata/AS_923_PHY_V1_1_REV_A.json index be9d2758b3..b76cf6e26d 100644 --- a/pkg/band/testdata/AS_923_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/AS_923_PHY_V1_1_REV_A.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_PHY_V1_1_REV_B.json b/pkg/band/testdata/AS_923_PHY_V1_1_REV_B.json index be9d2758b3..b76cf6e26d 100644 --- a/pkg/band/testdata/AS_923_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/AS_923_PHY_V1_1_REV_B.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_RP002_V1_0_0.json b/pkg/band/testdata/AS_923_RP002_V1_0_0.json index 0cec3db721..a2a6279be9 100644 --- a/pkg/band/testdata/AS_923_RP002_V1_0_0.json +++ b/pkg/band/testdata/AS_923_RP002_V1_0_0.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_RP002_V1_0_1.json b/pkg/band/testdata/AS_923_RP002_V1_0_1.json index 9d860867b9..0d02d8ec54 100644 --- a/pkg/band/testdata/AS_923_RP002_V1_0_1.json +++ b/pkg/band/testdata/AS_923_RP002_V1_0_1.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_RP002_V1_0_2.json b/pkg/band/testdata/AS_923_RP002_V1_0_2.json index 9e92e936d8..296673a2cb 100644 --- a/pkg/band/testdata/AS_923_RP002_V1_0_2.json +++ b/pkg/band/testdata/AS_923_RP002_V1_0_2.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_RP002_V1_0_3.json b/pkg/band/testdata/AS_923_RP002_V1_0_3.json index 9e92e936d8..296673a2cb 100644 --- a/pkg/band/testdata/AS_923_RP002_V1_0_3.json +++ b/pkg/band/testdata/AS_923_RP002_V1_0_3.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AS_923_RP002_V1_0_4.json b/pkg/band/testdata/AS_923_RP002_V1_0_4.json index 00c307c82d..d467150f24 100644 --- a/pkg/band/testdata/AS_923_RP002_V1_0_4.json +++ b/pkg/band/testdata/AS_923_RP002_V1_0_4.json @@ -708,6 +708,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_0_1.json b/pkg/band/testdata/AU_915_928_PHY_V1_0_1.json index cfac1591e5..458544cdf9 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_0_1.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_0_1.json @@ -924,6 +924,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_A.json index cfac1591e5..458544cdf9 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_A.json @@ -924,6 +924,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_B.json index f10c61a0dc..f014ff4ef6 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_0_2_REV_B.json @@ -994,6 +994,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/AU_915_928_PHY_V1_0_3_REV_A.json index 5efaea74d1..1f7963c8d1 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_0_3_REV_A.json @@ -999,6 +999,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_A.json b/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_A.json index ca611778d7..f28337549a 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_A.json @@ -994,6 +994,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_B.json b/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_B.json index 67f0ad076a..7915097c01 100644 --- a/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/AU_915_928_PHY_V1_1_REV_B.json @@ -998,6 +998,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_RP002_V1_0_0.json b/pkg/band/testdata/AU_915_928_RP002_V1_0_0.json index 27c85d09eb..c55aaf1083 100644 --- a/pkg/band/testdata/AU_915_928_RP002_V1_0_0.json +++ b/pkg/band/testdata/AU_915_928_RP002_V1_0_0.json @@ -998,6 +998,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_RP002_V1_0_1.json b/pkg/band/testdata/AU_915_928_RP002_V1_0_1.json index 27c85d09eb..c55aaf1083 100644 --- a/pkg/band/testdata/AU_915_928_RP002_V1_0_1.json +++ b/pkg/band/testdata/AU_915_928_RP002_V1_0_1.json @@ -998,6 +998,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_RP002_V1_0_2.json b/pkg/band/testdata/AU_915_928_RP002_V1_0_2.json index 73a3c3eb92..2e76cd6dbf 100644 --- a/pkg/band/testdata/AU_915_928_RP002_V1_0_2.json +++ b/pkg/band/testdata/AU_915_928_RP002_V1_0_2.json @@ -1022,6 +1022,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_RP002_V1_0_3.json b/pkg/band/testdata/AU_915_928_RP002_V1_0_3.json index 73a3c3eb92..2e76cd6dbf 100644 --- a/pkg/band/testdata/AU_915_928_RP002_V1_0_3.json +++ b/pkg/band/testdata/AU_915_928_RP002_V1_0_3.json @@ -1022,6 +1022,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/AU_915_928_RP002_V1_0_4.json b/pkg/band/testdata/AU_915_928_RP002_V1_0_4.json index fd2d76c5e9..439dbbb64a 100644 --- a/pkg/band/testdata/AU_915_928_RP002_V1_0_4.json +++ b/pkg/band/testdata/AU_915_928_RP002_V1_0_4.json @@ -1033,6 +1033,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_0.json b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_0.json index a2b60074ea..a5e04ad0a9 100644 --- a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_0.json +++ b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_0.json @@ -1110,6 +1110,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_1.json b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_1.json index d28a81ee08..7cc8968f9f 100644 --- a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_1.json +++ b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_1.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_2.json b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_2.json index d28a81ee08..7cc8968f9f 100644 --- a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_2.json +++ b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_2.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_3.json b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_3.json index d28a81ee08..7cc8968f9f 100644 --- a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_3.json +++ b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_3.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_4.json b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_4.json index 05c366c6bb..d21130bf3f 100644 --- a/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_4.json +++ b/pkg/band/testdata/CN_470_510_20_A_RP002_V1_0_4.json @@ -1132,6 +1132,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_0.json b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_0.json index c818949d9c..83d3951c91 100644 --- a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_0.json +++ b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_0.json @@ -1110,6 +1110,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_1.json b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_1.json index 9ed52db49d..eef8240003 100644 --- a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_1.json +++ b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_1.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_2.json b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_2.json index 9ed52db49d..eef8240003 100644 --- a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_2.json +++ b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_2.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_3.json b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_3.json index 9ed52db49d..eef8240003 100644 --- a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_3.json +++ b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_3.json @@ -1121,6 +1121,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_4.json b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_4.json index 77f337a0ed..08331c33e3 100644 --- a/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_4.json +++ b/pkg/band/testdata/CN_470_510_20_B_RP002_V1_0_4.json @@ -1132,6 +1132,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_0.json b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_0.json index 721f7a6993..bc0bdddfcd 100644 --- a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_0.json +++ b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_0.json @@ -834,6 +834,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_1.json b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_1.json index c1ff8d5082..ed695b8a30 100644 --- a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_1.json +++ b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_1.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_2.json b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_2.json index c1ff8d5082..ed695b8a30 100644 --- a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_2.json +++ b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_2.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_3.json b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_3.json index c1ff8d5082..ed695b8a30 100644 --- a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_3.json +++ b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_3.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_4.json b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_4.json index 311815ae23..aafd93e6ef 100644 --- a/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_4.json +++ b/pkg/band/testdata/CN_470_510_26_A_RP002_V1_0_4.json @@ -856,6 +856,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_0.json b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_0.json index d537ed1f80..fbf27ca32d 100644 --- a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_0.json +++ b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_0.json @@ -834,6 +834,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_1.json b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_1.json index fb8c364ed2..b3bba73d5e 100644 --- a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_1.json +++ b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_1.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_2.json b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_2.json index fb8c364ed2..b3bba73d5e 100644 --- a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_2.json +++ b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_2.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_3.json b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_3.json index fb8c364ed2..b3bba73d5e 100644 --- a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_3.json +++ b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_3.json @@ -845,6 +845,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_4.json b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_4.json index 5851cb9ead..935c11dcea 100644 --- a/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_4.json +++ b/pkg/band/testdata/CN_470_510_26_B_RP002_V1_0_4.json @@ -856,6 +856,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_0_1.json b/pkg/band/testdata/CN_470_510_PHY_V1_0_1.json index 87df9cef37..7b27e8d23b 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_0_1.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_0_1.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_A.json index 87df9cef37..7b27e8d23b 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_A.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_B.json index 1aa12da031..a56304658d 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_0_2_REV_B.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/CN_470_510_PHY_V1_0_3_REV_A.json index 6ec56a01e9..f76c0c1836 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_0_3_REV_A.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_A.json b/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_A.json index 6ec56a01e9..f76c0c1836 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_A.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_B.json b/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_B.json index 6ec56a01e9..f76c0c1836 100644 --- a/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/CN_470_510_PHY_V1_1_REV_B.json @@ -1208,6 +1208,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_0.json b/pkg/band/testdata/CN_779_787_PHY_V1_0.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_0.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_0.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_0_1.json b/pkg/band/testdata/CN_779_787_PHY_V1_0_1.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_0_1.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_0_1.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_A.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_A.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_B.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_0_2_REV_B.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/CN_779_787_PHY_V1_0_3_REV_A.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_0_3_REV_A.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_A.json b/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_A.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_A.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_B.json b/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_B.json index 7e8a28e6c1..a525332d45 100644 --- a/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/CN_779_787_PHY_V1_1_REV_B.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_RP002_V1_0_0.json b/pkg/band/testdata/CN_779_787_RP002_V1_0_0.json index 158941d179..08044d9b99 100644 --- a/pkg/band/testdata/CN_779_787_RP002_V1_0_0.json +++ b/pkg/band/testdata/CN_779_787_RP002_V1_0_0.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_RP002_V1_0_1.json b/pkg/band/testdata/CN_779_787_RP002_V1_0_1.json index 158941d179..08044d9b99 100644 --- a/pkg/band/testdata/CN_779_787_RP002_V1_0_1.json +++ b/pkg/band/testdata/CN_779_787_RP002_V1_0_1.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_RP002_V1_0_2.json b/pkg/band/testdata/CN_779_787_RP002_V1_0_2.json index 158941d179..08044d9b99 100644 --- a/pkg/band/testdata/CN_779_787_RP002_V1_0_2.json +++ b/pkg/band/testdata/CN_779_787_RP002_V1_0_2.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/CN_779_787_RP002_V1_0_3.json b/pkg/band/testdata/CN_779_787_RP002_V1_0_3.json index 158941d179..08044d9b99 100644 --- a/pkg/band/testdata/CN_779_787_RP002_V1_0_3.json +++ b/pkg/band/testdata/CN_779_787_RP002_V1_0_3.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_0.json b/pkg/band/testdata/EU_433_PHY_V1_0.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_0.json +++ b/pkg/band/testdata/EU_433_PHY_V1_0.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_0_1.json b/pkg/band/testdata/EU_433_PHY_V1_0_1.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_0_1.json +++ b/pkg/band/testdata/EU_433_PHY_V1_0_1.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_A.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_A.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_B.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/EU_433_PHY_V1_0_2_REV_B.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/EU_433_PHY_V1_0_3_REV_A.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/EU_433_PHY_V1_0_3_REV_A.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_1_REV_A.json b/pkg/band/testdata/EU_433_PHY_V1_1_REV_A.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/EU_433_PHY_V1_1_REV_A.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_PHY_V1_1_REV_B.json b/pkg/band/testdata/EU_433_PHY_V1_1_REV_B.json index 24e44251bf..1ca9b1a390 100644 --- a/pkg/band/testdata/EU_433_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/EU_433_PHY_V1_1_REV_B.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_RP002_V1_0_0.json b/pkg/band/testdata/EU_433_RP002_V1_0_0.json index aa33c10785..70b7acb008 100644 --- a/pkg/band/testdata/EU_433_RP002_V1_0_0.json +++ b/pkg/band/testdata/EU_433_RP002_V1_0_0.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_RP002_V1_0_1.json b/pkg/band/testdata/EU_433_RP002_V1_0_1.json index aa33c10785..70b7acb008 100644 --- a/pkg/band/testdata/EU_433_RP002_V1_0_1.json +++ b/pkg/band/testdata/EU_433_RP002_V1_0_1.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_RP002_V1_0_2.json b/pkg/band/testdata/EU_433_RP002_V1_0_2.json index aa33c10785..70b7acb008 100644 --- a/pkg/band/testdata/EU_433_RP002_V1_0_2.json +++ b/pkg/band/testdata/EU_433_RP002_V1_0_2.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_RP002_V1_0_3.json b/pkg/band/testdata/EU_433_RP002_V1_0_3.json index aa33c10785..70b7acb008 100644 --- a/pkg/band/testdata/EU_433_RP002_V1_0_3.json +++ b/pkg/band/testdata/EU_433_RP002_V1_0_3.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_433_RP002_V1_0_4.json b/pkg/band/testdata/EU_433_RP002_V1_0_4.json index aa33c10785..1c4c056443 100644 --- a/pkg/band/testdata/EU_433_RP002_V1_0_4.json +++ b/pkg/band/testdata/EU_433_RP002_V1_0_4.json @@ -550,6 +550,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_0.json b/pkg/band/testdata/EU_863_870_PHY_V1_0.json index 691f0adafd..8c7c649215 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_0.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_0.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_0_1.json b/pkg/band/testdata/EU_863_870_PHY_V1_0_1.json index 691f0adafd..8c7c649215 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_0_1.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_0_1.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_A.json index 691f0adafd..8c7c649215 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_A.json @@ -580,6 +580,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_B.json index 68d6bf4695..e676b699d2 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_0_2_REV_B.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/EU_863_870_PHY_V1_0_3_REV_A.json index 68d6bf4695..e676b699d2 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_0_3_REV_A.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_A.json b/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_A.json index 68d6bf4695..e676b699d2 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_A.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_B.json b/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_B.json index 68d6bf4695..e676b699d2 100644 --- a/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/EU_863_870_PHY_V1_1_REV_B.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_RP002_V1_0_0.json b/pkg/band/testdata/EU_863_870_RP002_V1_0_0.json index 6b50e20ac5..83ec7e3359 100644 --- a/pkg/band/testdata/EU_863_870_RP002_V1_0_0.json +++ b/pkg/band/testdata/EU_863_870_RP002_V1_0_0.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_RP002_V1_0_1.json b/pkg/band/testdata/EU_863_870_RP002_V1_0_1.json index 6b50e20ac5..83ec7e3359 100644 --- a/pkg/band/testdata/EU_863_870_RP002_V1_0_1.json +++ b/pkg/band/testdata/EU_863_870_RP002_V1_0_1.json @@ -582,6 +582,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_RP002_V1_0_2.json b/pkg/band/testdata/EU_863_870_RP002_V1_0_2.json index 537f3e6b81..c086bc295d 100644 --- a/pkg/band/testdata/EU_863_870_RP002_V1_0_2.json +++ b/pkg/band/testdata/EU_863_870_RP002_V1_0_2.json @@ -678,6 +678,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_RP002_V1_0_3.json b/pkg/band/testdata/EU_863_870_RP002_V1_0_3.json index 537f3e6b81..c086bc295d 100644 --- a/pkg/band/testdata/EU_863_870_RP002_V1_0_3.json +++ b/pkg/band/testdata/EU_863_870_RP002_V1_0_3.json @@ -678,6 +678,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/EU_863_870_RP002_V1_0_4.json b/pkg/band/testdata/EU_863_870_RP002_V1_0_4.json index fe63a1481f..7137dd9cbb 100644 --- a/pkg/band/testdata/EU_863_870_RP002_V1_0_4.json +++ b/pkg/band/testdata/EU_863_870_RP002_V1_0_4.json @@ -689,6 +689,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/IN_865_867_PHY_V1_0_2_REV_B.json index f2edf7eb53..e4072707e8 100644 --- a/pkg/band/testdata/IN_865_867_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/IN_865_867_PHY_V1_0_2_REV_B.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/IN_865_867_PHY_V1_0_3_REV_A.json index f2edf7eb53..e4072707e8 100644 --- a/pkg/band/testdata/IN_865_867_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/IN_865_867_PHY_V1_0_3_REV_A.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_A.json b/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_A.json index f2edf7eb53..e4072707e8 100644 --- a/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_A.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_B.json b/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_B.json index f2edf7eb53..e4072707e8 100644 --- a/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/IN_865_867_PHY_V1_1_REV_B.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_RP002_V1_0_0.json b/pkg/band/testdata/IN_865_867_RP002_V1_0_0.json index aced696373..af7b408df9 100644 --- a/pkg/band/testdata/IN_865_867_RP002_V1_0_0.json +++ b/pkg/band/testdata/IN_865_867_RP002_V1_0_0.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_RP002_V1_0_1.json b/pkg/band/testdata/IN_865_867_RP002_V1_0_1.json index aced696373..af7b408df9 100644 --- a/pkg/band/testdata/IN_865_867_RP002_V1_0_1.json +++ b/pkg/band/testdata/IN_865_867_RP002_V1_0_1.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_RP002_V1_0_2.json b/pkg/band/testdata/IN_865_867_RP002_V1_0_2.json index aced696373..af7b408df9 100644 --- a/pkg/band/testdata/IN_865_867_RP002_V1_0_2.json +++ b/pkg/band/testdata/IN_865_867_RP002_V1_0_2.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_RP002_V1_0_3.json b/pkg/band/testdata/IN_865_867_RP002_V1_0_3.json index aced696373..af7b408df9 100644 --- a/pkg/band/testdata/IN_865_867_RP002_V1_0_3.json +++ b/pkg/band/testdata/IN_865_867_RP002_V1_0_3.json @@ -702,6 +702,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/IN_865_867_RP002_V1_0_4.json b/pkg/band/testdata/IN_865_867_RP002_V1_0_4.json index ee9066cdab..973a6b9f14 100644 --- a/pkg/band/testdata/IN_865_867_RP002_V1_0_4.json +++ b/pkg/band/testdata/IN_865_867_RP002_V1_0_4.json @@ -713,6 +713,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_0.json b/pkg/band/testdata/ISM_2400_PHY_V1_0.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_0.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_0.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_0_1.json b/pkg/band/testdata/ISM_2400_PHY_V1_0_1.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_0_1.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_0_1.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_A.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_A.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_B.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_0_2_REV_B.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/ISM_2400_PHY_V1_0_3_REV_A.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_0_3_REV_A.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_A.json b/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_A.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_A.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_B.json b/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_B.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/ISM_2400_PHY_V1_1_REV_B.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_RP002_V1_0_0.json b/pkg/band/testdata/ISM_2400_RP002_V1_0_0.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_RP002_V1_0_0.json +++ b/pkg/band/testdata/ISM_2400_RP002_V1_0_0.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_RP002_V1_0_1.json b/pkg/band/testdata/ISM_2400_RP002_V1_0_1.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_RP002_V1_0_1.json +++ b/pkg/band/testdata/ISM_2400_RP002_V1_0_1.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_RP002_V1_0_2.json b/pkg/band/testdata/ISM_2400_RP002_V1_0_2.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_RP002_V1_0_2.json +++ b/pkg/band/testdata/ISM_2400_RP002_V1_0_2.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_RP002_V1_0_3.json b/pkg/band/testdata/ISM_2400_RP002_V1_0_3.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_RP002_V1_0_3.json +++ b/pkg/band/testdata/ISM_2400_RP002_V1_0_3.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/ISM_2400_RP002_V1_0_4.json b/pkg/band/testdata/ISM_2400_RP002_V1_0_4.json index b66fdd9b6f..c8a1b0bbc5 100644 --- a/pkg/band/testdata/ISM_2400_RP002_V1_0_4.json +++ b/pkg/band/testdata/ISM_2400_RP002_V1_0_4.json @@ -554,6 +554,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_A.json index 4aca29fd67..b4c39ae516 100644 --- a/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_A.json @@ -503,6 +503,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_B.json index f835b48d74..df30406473 100644 --- a/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/KR_920_923_PHY_V1_0_2_REV_B.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/KR_920_923_PHY_V1_0_3_REV_A.json index f835b48d74..df30406473 100644 --- a/pkg/band/testdata/KR_920_923_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/KR_920_923_PHY_V1_0_3_REV_A.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_A.json b/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_A.json index f835b48d74..df30406473 100644 --- a/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_A.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_B.json b/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_B.json index f835b48d74..df30406473 100644 --- a/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/KR_920_923_PHY_V1_1_REV_B.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_RP002_V1_0_0.json b/pkg/band/testdata/KR_920_923_RP002_V1_0_0.json index 62a3db519d..a1d9767df8 100644 --- a/pkg/band/testdata/KR_920_923_RP002_V1_0_0.json +++ b/pkg/band/testdata/KR_920_923_RP002_V1_0_0.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_RP002_V1_0_1.json b/pkg/band/testdata/KR_920_923_RP002_V1_0_1.json index 62a3db519d..a1d9767df8 100644 --- a/pkg/band/testdata/KR_920_923_RP002_V1_0_1.json +++ b/pkg/band/testdata/KR_920_923_RP002_V1_0_1.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_RP002_V1_0_2.json b/pkg/band/testdata/KR_920_923_RP002_V1_0_2.json index 62a3db519d..a1d9767df8 100644 --- a/pkg/band/testdata/KR_920_923_RP002_V1_0_2.json +++ b/pkg/band/testdata/KR_920_923_RP002_V1_0_2.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_RP002_V1_0_3.json b/pkg/band/testdata/KR_920_923_RP002_V1_0_3.json index 62a3db519d..a1d9767df8 100644 --- a/pkg/band/testdata/KR_920_923_RP002_V1_0_3.json +++ b/pkg/band/testdata/KR_920_923_RP002_V1_0_3.json @@ -504,6 +504,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/KR_920_923_RP002_V1_0_4.json b/pkg/band/testdata/KR_920_923_RP002_V1_0_4.json index 726a79c642..b11482855f 100644 --- a/pkg/band/testdata/KR_920_923_RP002_V1_0_4.json +++ b/pkg/band/testdata/KR_920_923_RP002_V1_0_4.json @@ -515,6 +515,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_1.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_1.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_1.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_1.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_A.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_A.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_B.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_2_REV_B.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_3_REV_A.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_0_3_REV_A.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_A.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_A.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_A.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_B.json b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_B.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_PHY_V1_1_REV_B.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_0.json b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_0.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_0.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_0.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_1.json b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_1.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_1.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_1.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_2.json b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_2.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_2.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_2.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_3.json b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_3.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_3.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_3.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_4.json b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_4.json index c8e278ebba..175a316a6a 100644 --- a/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_4.json +++ b/pkg/band/testdata/MA_869_870_DRAFT_RP002_V1_0_4.json @@ -612,6 +612,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/RU_864_870_PHY_V1_0_3_REV_A.json index afe9de9edb..c7c1e494d7 100644 --- a/pkg/band/testdata/RU_864_870_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/RU_864_870_PHY_V1_0_3_REV_A.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_A.json b/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_A.json index afe9de9edb..c7c1e494d7 100644 --- a/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_A.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_B.json b/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_B.json index afe9de9edb..c7c1e494d7 100644 --- a/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/RU_864_870_PHY_V1_1_REV_B.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_RP002_V1_0_0.json b/pkg/band/testdata/RU_864_870_RP002_V1_0_0.json index 9f41da26fb..7074a1f833 100644 --- a/pkg/band/testdata/RU_864_870_RP002_V1_0_0.json +++ b/pkg/band/testdata/RU_864_870_RP002_V1_0_0.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_RP002_V1_0_1.json b/pkg/band/testdata/RU_864_870_RP002_V1_0_1.json index 9f41da26fb..7074a1f833 100644 --- a/pkg/band/testdata/RU_864_870_RP002_V1_0_1.json +++ b/pkg/band/testdata/RU_864_870_RP002_V1_0_1.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_RP002_V1_0_2.json b/pkg/band/testdata/RU_864_870_RP002_V1_0_2.json index 9f41da26fb..7074a1f833 100644 --- a/pkg/band/testdata/RU_864_870_RP002_V1_0_2.json +++ b/pkg/band/testdata/RU_864_870_RP002_V1_0_2.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_RP002_V1_0_3.json b/pkg/band/testdata/RU_864_870_RP002_V1_0_3.json index 9f41da26fb..7074a1f833 100644 --- a/pkg/band/testdata/RU_864_870_RP002_V1_0_3.json +++ b/pkg/band/testdata/RU_864_870_RP002_V1_0_3.json @@ -542,6 +542,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/RU_864_870_RP002_V1_0_4.json b/pkg/band/testdata/RU_864_870_RP002_V1_0_4.json index 5a613b6a4a..8fa2895cb1 100644 --- a/pkg/band/testdata/RU_864_870_RP002_V1_0_4.json +++ b/pkg/band/testdata/RU_864_870_RP002_V1_0_4.json @@ -553,6 +553,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_0.json b/pkg/band/testdata/US_902_928_PHY_V1_0.json index 96c41cf2fe..9e46f149a1 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_0.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_0.json @@ -930,6 +930,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_0_1.json b/pkg/band/testdata/US_902_928_PHY_V1_0_1.json index 96c41cf2fe..9e46f149a1 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_0_1.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_0_1.json @@ -930,6 +930,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_A.json b/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_A.json index 6b233ade3d..83a5fc9426 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_A.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_A.json @@ -930,6 +930,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_B.json b/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_B.json index 98ee6e47bc..7887e720ee 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_B.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_0_2_REV_B.json @@ -930,6 +930,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_0_3_REV_A.json b/pkg/band/testdata/US_902_928_PHY_V1_0_3_REV_A.json index 070c454932..22e367111d 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_0_3_REV_A.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_0_3_REV_A.json @@ -935,6 +935,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_1_REV_A.json b/pkg/band/testdata/US_902_928_PHY_V1_1_REV_A.json index e87ffa49f2..663dfa8fea 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_1_REV_A.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_1_REV_A.json @@ -934,6 +934,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_PHY_V1_1_REV_B.json b/pkg/band/testdata/US_902_928_PHY_V1_1_REV_B.json index e87ffa49f2..663dfa8fea 100644 --- a/pkg/band/testdata/US_902_928_PHY_V1_1_REV_B.json +++ b/pkg/band/testdata/US_902_928_PHY_V1_1_REV_B.json @@ -934,6 +934,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_RP002_V1_0_0.json b/pkg/band/testdata/US_902_928_RP002_V1_0_0.json index e87ffa49f2..663dfa8fea 100644 --- a/pkg/band/testdata/US_902_928_RP002_V1_0_0.json +++ b/pkg/band/testdata/US_902_928_RP002_V1_0_0.json @@ -934,6 +934,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_RP002_V1_0_1.json b/pkg/band/testdata/US_902_928_RP002_V1_0_1.json index e87ffa49f2..663dfa8fea 100644 --- a/pkg/band/testdata/US_902_928_RP002_V1_0_1.json +++ b/pkg/band/testdata/US_902_928_RP002_V1_0_1.json @@ -934,6 +934,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_RP002_V1_0_2.json b/pkg/band/testdata/US_902_928_RP002_V1_0_2.json index 9e9a1badbc..1e6d5e62d9 100644 --- a/pkg/band/testdata/US_902_928_RP002_V1_0_2.json +++ b/pkg/band/testdata/US_902_928_RP002_V1_0_2.json @@ -974,6 +974,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_RP002_V1_0_3.json b/pkg/band/testdata/US_902_928_RP002_V1_0_3.json index 9e9a1badbc..1e6d5e62d9 100644 --- a/pkg/band/testdata/US_902_928_RP002_V1_0_3.json +++ b/pkg/band/testdata/US_902_928_RP002_V1_0_3.json @@ -974,6 +974,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 0, + "RelayReceiveDelay": 0, + "ServedRelayBackoff": 0 } } \ No newline at end of file diff --git a/pkg/band/testdata/US_902_928_RP002_V1_0_4.json b/pkg/band/testdata/US_902_928_RP002_V1_0_4.json index 8579f2aeb2..318d1588d1 100644 --- a/pkg/band/testdata/US_902_928_RP002_V1_0_4.json +++ b/pkg/band/testdata/US_902_928_RP002_V1_0_4.json @@ -985,6 +985,9 @@ "ADRAckLimit": "ADR_ACK_LIMIT_64", "ADRAckDelay": "ADR_ACK_DELAY_32", "MinRetransmitTimeout": 1000000000, - "MaxRetransmitTimeout": 3000000000 + "MaxRetransmitTimeout": 3000000000, + "RelayForwardDelay": 50000000, + "RelayReceiveDelay": 18000000000, + "ServedRelayBackoff": 8 } } \ No newline at end of file diff --git a/pkg/band/us_902_928_rp2_v1_0_4.go b/pkg/band/us_902_928_rp2_v1_0_4.go index c0ce24f531..acecc03277 100644 --- a/pkg/band/us_902_928_rp2_v1_0_4.go +++ b/pkg/band/us_902_928_rp2_v1_0_4.go @@ -116,5 +116,5 @@ var US_902_928_RP2_V1_0_4 = Band{ Relay: us902928RelayParameters, - SharedParameters: universalSharedParameters, + SharedParameters: relayAwareSharedParameters, } diff --git a/pkg/basicstation/cups/server.go b/pkg/basicstation/cups/server.go index 323ac8c91f..298fd3c9d5 100644 --- a/pkg/basicstation/cups/server.go +++ b/pkg/basicstation/cups/server.go @@ -33,7 +33,6 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/web" "golang.org/x/sync/singleflight" "google.golang.org/grpc" - "google.golang.org/grpc/metadata" ) // Server implements the Basic Station Configuration and Update Server. @@ -184,17 +183,6 @@ func (s *Server) RegisterRoutes(web *web.Server) { router.Path("/update-info").HandlerFunc(s.UpdateInfo).Methods(http.MethodPost) } -func getContext(r *http.Request) context.Context { - ctx := r.Context() - md := metadata.New(map[string]string{ - "authorization": r.Header.Get("Authorization"), - }) - if ctxMd, ok := metadata.FromIncomingContext(ctx); ok { - md = metadata.Join(ctxMd, md) - } - return metadata.NewIncomingContext(ctx, md) -} - var errNoTrust = errors.DefineInternal("no_trust", "no trusted certificate found") // parseAddress parses a CUPS or LNS address. diff --git a/pkg/console/console.go b/pkg/console/console.go index d012123d35..092e52a1bb 100644 --- a/pkg/console/console.go +++ b/pkg/console/console.go @@ -23,6 +23,7 @@ import ( "github.com/gorilla/csrf" "github.com/gorilla/mux" "go.thethings.network/lorawan-stack/v3/pkg/component" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events" "go.thethings.network/lorawan-stack/v3/pkg/web" "go.thethings.network/lorawan-stack/v3/pkg/web/oauthclient" "go.thethings.network/lorawan-stack/v3/pkg/webhandlers" @@ -58,6 +59,7 @@ func New(c *component.Component, config Config) (*Console, error) { } c.RegisterWeb(console) + c.RegisterWeb(events.New(c)) return console, nil } @@ -88,22 +90,25 @@ func path(u string) (string, error) { } func generateConsoleCSPString(config *Config, nonce string, others ...webui.ContentSecurityPolicy) string { + baseURLs := webui.RewriteSchemes( + webui.WebsocketSchemeRewrites, + config.UI.StackConfig.GS.BaseURL, + config.UI.StackConfig.IS.BaseURL, + config.UI.StackConfig.JS.BaseURL, + config.UI.StackConfig.NS.BaseURL, + config.UI.StackConfig.AS.BaseURL, + config.UI.StackConfig.EDTC.BaseURL, + config.UI.StackConfig.QRG.BaseURL, + config.UI.StackConfig.GCS.BaseURL, + config.UI.StackConfig.DCS.BaseURL, + ) return webui.ContentSecurityPolicy{ - ConnectionSource: []string{ + ConnectionSource: append([]string{ "'self'", - config.UI.StackConfig.GS.BaseURL, - config.UI.StackConfig.IS.BaseURL, - config.UI.StackConfig.JS.BaseURL, - config.UI.StackConfig.NS.BaseURL, - config.UI.StackConfig.AS.BaseURL, - config.UI.StackConfig.EDTC.BaseURL, - config.UI.StackConfig.QRG.BaseURL, - config.UI.StackConfig.GCS.BaseURL, - config.UI.StackConfig.DCS.BaseURL, config.UI.SentryDSN, "gravatar.com", "www.gravatar.com", - }, + }, baseURLs...), StyleSource: []string{ "'self'", config.UI.AssetsBaseURL, diff --git a/pkg/console/internal/events/events.go b/pkg/console/internal/events/events.go new file mode 100644 index 0000000000..3422b160dc --- /dev/null +++ b/pkg/console/internal/events/events.go @@ -0,0 +1,149 @@ +// Copyright © 2023 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 events contains the internal events APi for the Console. +package events + +import ( + "context" + "net/http" + "sync" + + "github.com/gorilla/mux" + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights" + "go.thethings.network/lorawan-stack/v3/pkg/config" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/eventsmux" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/middleware" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/subscriptions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ratelimit" + "go.thethings.network/lorawan-stack/v3/pkg/task" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/web" + "go.thethings.network/lorawan-stack/v3/pkg/webhandlers" + "go.thethings.network/lorawan-stack/v3/pkg/webmiddleware" + "nhooyr.io/websocket" +) + +const ( + authorizationProtocolPrefix = "ttn.lorawan.v3.header.authorization.bearer." + protocolV1 = "ttn.lorawan.v3.console.internal.events.v1" +) + +// Component is the interface of the component to the events API handler. +type Component interface { + task.Starter + Context() context.Context + RateLimiter() ratelimit.Interface + GetBaseConfig(context.Context) config.ServiceBase +} + +type eventsHandler struct { + component Component + subscriber events.Subscriber + definedNames map[string]struct{} +} + +var _ web.Registerer = (*eventsHandler)(nil) + +func (h *eventsHandler) RegisterRoutes(server *web.Server) { + router := server.APIRouter().PathPrefix(ttnpb.HTTPAPIPrefix + "/console/internal/events/").Subrouter() + router.Use( + mux.MiddlewareFunc(webmiddleware.Namespace("console/internal/events")), + mux.MiddlewareFunc(middleware.ProtocolAuthentication(authorizationProtocolPrefix)), + mux.MiddlewareFunc(webmiddleware.Metadata("Authorization")), + ratelimit.HTTPMiddleware(h.component.RateLimiter(), "http:console:internal:events"), + ) + router.Path("/").HandlerFunc(h.handleEvents).Methods(http.MethodGet) +} + +func (h *eventsHandler) handleEvents(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + logger := log.FromContext(ctx) + + if err := rights.RequireAuthenticated(ctx); err != nil { + webhandlers.Error(w, r, err) + return + } + + rateLimit, err := makeRateLimiter(ctx, h.component.RateLimiter()) + if err != nil { + webhandlers.Error(w, r, err) + return + } + + conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{ + Subprotocols: []string{protocolV1}, + InsecureSkipVerify: true, // CORS is not enabled for APIs. + CompressionMode: websocket.CompressionContextTakeover, + }) + if err != nil { + logger.WithError(err).Debug("Failed to accept WebSocket") + return + } + defer conn.Close(websocket.StatusNormalClosure, "main task closed") + + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(nil) + + var wg sync.WaitGroup + defer wg.Wait() + + m := eventsmux.New(func(ctx context.Context, cancel func(error)) subscriptions.Interface { + return subscriptions.New(ctx, cancel, h.subscriber, h.definedNames, h.component) + }) + for name, f := range map[string]func(context.Context) error{ + "console_events_mux": makeMuxTask(m, cancel), + "console_events_read": makeReadTask(conn, m, rateLimit, cancel), + "console_events_write": makeWriteTask(conn, m, cancel), + } { + wg.Add(1) + h.component.StartTask(&task.Config{ + Context: ctx, + ID: name, + Func: f, + Done: wg.Done, + Restart: task.RestartNever, + Backoff: task.DefaultBackoffConfig, + }) + } +} + +// Option configures the events API handler. +type Option func(*eventsHandler) + +// WithSubscriber configures the Subscriber to use for events. +func WithSubscriber(subscriber events.Subscriber) Option { + return func(h *eventsHandler) { + h.subscriber = subscriber + } +} + +// New returns an events API handler for the Console. +func New(c Component, opts ...Option) web.Registerer { + definedNames := make(map[string]struct{}) + for _, def := range events.All().Definitions() { + definedNames[def.Name()] = struct{}{} + } + h := &eventsHandler{ + component: c, + subscriber: events.DefaultPubSub(), + definedNames: definedNames, + } + for _, opt := range opts { + opt(h) + } + return h +} diff --git a/pkg/console/internal/events/eventsmux/mux.go b/pkg/console/internal/events/eventsmux/mux.go new file mode 100644 index 0000000000..e0874f9c51 --- /dev/null +++ b/pkg/console/internal/events/eventsmux/mux.go @@ -0,0 +1,106 @@ +// Copyright © 2023 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 eventsmux implements the events mux. +package eventsmux + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/protocol" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/subscriptions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" +) + +// Interface is the interface for the events mux. +type Interface interface { + // Requests returns the channel for requests. + Requests() chan<- protocol.Request + // Responses returns the channel for responses. + Responses() <-chan protocol.Response + + // Run runs the events mux. + Run(context.Context) error +} + +type mux struct { + createSubs func(context.Context, func(error)) subscriptions.Interface + + requestCh chan protocol.Request + responseCh chan protocol.Response +} + +// Requests implements Interface. +func (m *mux) Requests() chan<- protocol.Request { + return m.requestCh +} + +// Responses implements Interface. +func (m *mux) Responses() <-chan protocol.Response { + return m.responseCh +} + +// Run implements Interface. +func (m *mux) Run(ctx context.Context) (err error) { + ctx, cancel := context.WithCancelCause(ctx) + defer func() { cancel(err) }() + subs := m.createSubs(ctx, cancel) + defer subs.Close() + for { + select { + case <-ctx.Done(): + return ctx.Err() + case req := <-m.requestCh: + var resp protocol.Response + switch req := req.(type) { + case *protocol.SubscribeRequest: + resp = req.Response(subs.Subscribe(req.ID, req.Identifiers, req.After, req.Tail, req.Names)) + case *protocol.UnsubscribeRequest: + resp = req.Response(subs.Unsubscribe(req.ID)) + default: + panic("unreachable") + } + select { + case <-ctx.Done(): + return ctx.Err() + case m.responseCh <- resp: + } + case subEvt := <-subs.SubscriptionEvents(): + evtPB, err := events.Proto(subEvt.Event) + if err != nil { + log.FromContext(ctx).WithError(err).Warn("Failed to convert event to proto") + continue + } + select { + case <-ctx.Done(): + return ctx.Err() + case m.responseCh <- &protocol.PublishResponse{ + ID: subEvt.ID, + Event: evtPB, + }: + } + } + } +} + +// New returns a new Interface. +func New(createSubs func(context.Context, func(error)) subscriptions.Interface) Interface { + return &mux{ + createSubs: createSubs, + + requestCh: make(chan protocol.Request, 1), + responseCh: make(chan protocol.Response, 1), + } +} diff --git a/pkg/console/internal/events/eventsmux/mux_test.go b/pkg/console/internal/events/eventsmux/mux_test.go new file mode 100644 index 0000000000..de220f52fa --- /dev/null +++ b/pkg/console/internal/events/eventsmux/mux_test.go @@ -0,0 +1,315 @@ +// Copyright © 2023 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 eventsmux_test + +import ( + "context" + "errors" + "testing" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/eventsmux" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/protocol" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/subscriptions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/unique" + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +type subscribeRequest struct { + ID uint64 + Identifiers []*ttnpb.EntityIdentifiers + After *time.Time + Tail uint32 + Names []string + + Response chan<- error +} + +type unsubscribeRequest struct { + ID uint64 + + Response chan<- error +} + +type mockSubscriptions struct { + ctx context.Context + subReqs chan subscribeRequest + unsubReqs chan unsubscribeRequest + evsCh chan *subscriptions.SubscriptionEvent +} + +// Subscribe implements subscriptions.Interface. +func (m *mockSubscriptions) Subscribe( + id uint64, identifiers []*ttnpb.EntityIdentifiers, after *time.Time, tail uint32, names []string, +) error { + ch := make(chan error, 1) + select { + case <-m.ctx.Done(): + return m.ctx.Err() + case m.subReqs <- subscribeRequest{ + ID: id, + Identifiers: identifiers, + After: after, + Tail: tail, + Names: names, + + Response: ch, + }: + select { + case <-m.ctx.Done(): + return m.ctx.Err() + case err := <-ch: + return err + } + } +} + +// Unsubscribe implements subscriptions.Interface. +func (m *mockSubscriptions) Unsubscribe(id uint64) error { + ch := make(chan error, 1) + select { + case <-m.ctx.Done(): + return m.ctx.Err() + case m.unsubReqs <- unsubscribeRequest{ + ID: id, + + Response: ch, + }: + select { + case <-m.ctx.Done(): + return m.ctx.Err() + case err := <-ch: + return err + } + } +} + +// SubscriptionEvents implements subscriptions.Interface. +func (m *mockSubscriptions) SubscriptionEvents() <-chan *subscriptions.SubscriptionEvent { + return m.evsCh +} + +// Close implements subscriptions.Interface. +func (*mockSubscriptions) Close() error { return nil } + +var _ subscriptions.Interface = (*mockSubscriptions)(nil) + +func TestMux(t *testing.T) { // nolint:gocyclo + t.Parallel() + + a, ctx := test.New(t) + + appIDs := &ttnpb.ApplicationIdentifiers{ + ApplicationId: "foo", + } + ctx = rights.NewContext(ctx, &rights.Rights{ + ApplicationRights: *rights.NewMap(map[string]*ttnpb.Rights{ + unique.ID(ctx, appIDs): ttnpb.RightsFrom(ttnpb.Right_RIGHT_ALL), + }), + }) + + subs := &mockSubscriptions{ + ctx: ctx, + subReqs: make(chan subscribeRequest, 1), + unsubReqs: make(chan unsubscribeRequest, 1), + evsCh: make(chan *subscriptions.SubscriptionEvent, 1), + } + m := eventsmux.New(func(context.Context, func(error)) subscriptions.Interface { return subs }) + + go m.Run(ctx) // nolint:errcheck + + now := time.Now() + select { + case <-ctx.Done(): + return + case m.Requests() <- &protocol.SubscribeRequest{ + ID: 42, + Identifiers: []*ttnpb.EntityIdentifiers{ + appIDs.GetEntityIdentifiers(), + }, + After: &now, + Tail: 1, + Names: []string{"foo"}, + }: + } + select { + case <-ctx.Done(): + return + case req := <-subs.subReqs: + a.So(req, should.Resemble, subscribeRequest{ + ID: 42, + Identifiers: []*ttnpb.EntityIdentifiers{ + appIDs.GetEntityIdentifiers(), + }, + After: &now, + Tail: 1, + Names: []string{"foo"}, + + Response: req.Response, + }) + select { + case <-ctx.Done(): + return + case req.Response <- nil: + } + } + select { + case <-ctx.Done(): + return + case resp := <-m.Responses(): + a.So(resp, should.Resemble, &protocol.SubscribeResponse{ + ID: 42, + }) + } + + errAlreadySubscribed := errors.New("already subscribed") + select { + case <-ctx.Done(): + return + case m.Requests() <- &protocol.SubscribeRequest{ + ID: 42, + Identifiers: []*ttnpb.EntityIdentifiers{ + appIDs.GetEntityIdentifiers(), + }, + After: &now, + Tail: 1, + Names: []string{"foo"}, + }: + } + select { + case <-ctx.Done(): + return + case req := <-subs.subReqs: + a.So(req, should.Resemble, subscribeRequest{ + ID: 42, + Identifiers: []*ttnpb.EntityIdentifiers{ + appIDs.GetEntityIdentifiers(), + }, + After: &now, + Tail: 1, + Names: []string{"foo"}, + + Response: req.Response, + }) + select { + case <-ctx.Done(): + return + case req.Response <- errAlreadySubscribed: + } + } + select { + case <-ctx.Done(): + return + case resp := <-m.Responses(): + a.So(resp, should.Resemble, &protocol.ErrorResponse{ + ID: 42, + Error: status.New(codes.Unknown, "already subscribed"), + }) + } + + ev := events.New( + ctx, + "test.evt", + "test event", + events.WithIdentifiers(appIDs), + ) + select { + case <-ctx.Done(): + return + case subs.evsCh <- &subscriptions.SubscriptionEvent{ + ID: 42, + Event: ev, + }: + } + select { + case <-ctx.Done(): + return + case resp := <-m.Responses(): + a.So(resp, should.Resemble, &protocol.PublishResponse{ + ID: 42, + Event: test.Must(events.Proto(ev)), + }) + } + + select { + case <-ctx.Done(): + return + case m.Requests() <- &protocol.UnsubscribeRequest{ + ID: 42, + }: + } + select { + case <-ctx.Done(): + return + case req := <-subs.unsubReqs: + a.So(req, should.Resemble, unsubscribeRequest{ + ID: 42, + + Response: req.Response, + }) + select { + case <-ctx.Done(): + return + case req.Response <- nil: + } + } + select { + case <-ctx.Done(): + return + case resp := <-m.Responses(): + a.So(resp, should.Resemble, &protocol.UnsubscribeResponse{ + ID: 42, + }) + } + + errNotSubscribed := errors.New("not subscribed") + select { + case <-ctx.Done(): + return + case m.Requests() <- &protocol.UnsubscribeRequest{ + ID: 42, + }: + } + select { + case <-ctx.Done(): + return + case req := <-subs.unsubReqs: + a.So(req, should.Resemble, unsubscribeRequest{ + ID: 42, + + Response: req.Response, + }) + select { + case <-ctx.Done(): + return + case req.Response <- errNotSubscribed: + } + } + select { + case <-ctx.Done(): + return + case resp := <-m.Responses(): + a.So(resp, should.Resemble, &protocol.ErrorResponse{ + ID: 42, + Error: status.New(codes.Unknown, "not subscribed"), + }) + } +} diff --git a/pkg/console/internal/events/middleware/auth.go b/pkg/console/internal/events/middleware/auth.go new file mode 100644 index 0000000000..66f2b71e20 --- /dev/null +++ b/pkg/console/internal/events/middleware/auth.go @@ -0,0 +1,78 @@ +// Copyright © 2023 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 middleware + +import ( + "fmt" + "net/http" + "net/textproto" + "strings" + + "go.thethings.network/lorawan-stack/v3/pkg/auth" +) + +var ( + protocolHeader = textproto.CanonicalMIMEHeaderKey("Sec-WebSocket-Protocol") + authorizationHeader = textproto.CanonicalMIMEHeaderKey("Authorization") + connectionHeader = textproto.CanonicalMIMEHeaderKey("Connection") + upgradeHeader = textproto.CanonicalMIMEHeaderKey("Upgrade") +) + +func isWebSocketRequest(r *http.Request) bool { + h := r.Header + return strings.EqualFold(h.Get(connectionHeader), "upgrade") && + strings.EqualFold(h.Get(upgradeHeader), "websocket") +} + +// ProtocolAuthentication returns a middleware that authenticates WebSocket requests using the subprotocol. +// The subprotocol must be prefixed with the given prefix. +// The token is extracted from the subprotocol and used to authenticate the request. +// If the token is valid, the subprotocol is removed from the request. +// If the token is invalid, the request is not authenticated. +func ProtocolAuthentication(prefix string) func(http.Handler) http.Handler { + prefixLen := len(prefix) + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !isWebSocketRequest(r) { + next.ServeHTTP(w, r) + return + } + if r.Header.Get(authorizationHeader) != "" { + next.ServeHTTP(w, r) + return + } + protocols := strings.Split(strings.TrimSpace(r.Header.Get(protocolHeader)), ",") + newProtocols := make([]string, 0, len(protocols)) + token := "" + for _, protocol := range protocols { + p := strings.TrimSpace(protocol) + if len(p) >= prefixLen && strings.EqualFold(prefix, p[:prefixLen]) { + token = p[prefixLen:] + continue + } + newProtocols = append(newProtocols, p) + } + if _, _, _, err := auth.SplitToken(token); err == nil { + if len(newProtocols) > 0 { + r.Header.Set(protocolHeader, strings.Join(newProtocols, ",")) + } else { + r.Header.Del(protocolHeader) + } + r.Header.Set(authorizationHeader, fmt.Sprintf("Bearer %s", token)) + } + next.ServeHTTP(w, r) + }) + } +} diff --git a/pkg/console/internal/events/middleware/middleware.go b/pkg/console/internal/events/middleware/middleware.go new file mode 100644 index 0000000000..61a7321356 --- /dev/null +++ b/pkg/console/internal/events/middleware/middleware.go @@ -0,0 +1,16 @@ +// Copyright © 2023 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 middleware implements the events middleware. +package middleware diff --git a/pkg/console/internal/events/protocol/PROTOCOL.md b/pkg/console/internal/events/protocol/PROTOCOL.md new file mode 100644 index 0000000000..c29ddd5685 --- /dev/null +++ b/pkg/console/internal/events/protocol/PROTOCOL.md @@ -0,0 +1,196 @@ +### Internal Events API + +The Console internal events API is designed as an alternative to the `Events.Stream` gRPC API for event stream interactions. It allows multiple subscriptions to be multiplexed over a singular [WebSocket](https://en.wikipedia.org/wiki/WebSocket) connection. + +### Reasoning + +The `Events.Stream` gRPC API is available to HTTP clients via [grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway). While translated to HTTP, it is visible as a long-polling request whose response body will contain the events as a series of JSON objects. + +This approach is efficient in the context of [HTTP/2](https://en.wikipedia.org/wiki/HTTP/2) which supports multiplexing multiple requests over a singular TCP connection. + +Unfortunately the connection between a browser and The Things Stack is susceptible to proxies. Corporate environments are generally equipped with such proxies, and in their presence the connections are downgraded to HTTP/1.1 semantics. + +In HTTP/1.1 connections can be used for a singular request at a time - it is not possible to multiplex the requests over a singular connection, and only [keep-alive](https://en.wikipedia.org/wiki/HTTP_persistent_connection) connections are available. + +This is problematic as browsers have builtin limits for the number of concurrent connections that singular windows may use. This leads to hard to debug issues which are hardly reproducible. + +But, there is one silver lining - the connection limit _does not apply to WebSocket connections_. The internal events API is designed to deal with this limitation while providing an experience similar to the original `Events.Stream` gRPC API. + +### Endpoint + +The endpoint for the internal events API is `/api/v3/console/internal/events/`. Note that the trailing slash is not optional. + +### Semantics + +The protocol is [full-duplex](https://en.wikipedia.org/wiki/Duplex_(telecommunications)#Full_duplex) - the client side and server side may transmit messages at any time without waiting for a response from the other party. + +The protocol is centered around subscriptions. Subscriptions are identified by an unsigned numerical ID, which is selected by the client. + +A subscription is initiated by the client via a subscription request, which the server confirms either with a subscription response or an error response. + +Following a successful subscription, the server may send at any time publication responses containing the subscription identifier and an event. The subscription identifier can be used on the client side in order to route the event to the appropriate component or view. + +A subscription can be terminated via an unsubscribe request, which the server confirms either with an unsubscribe response or an error response. + +The client can expect that no publication responses will follow an unsubscribe response, but it is recommended that subscription identifiers are not recycled within the same session. + +Error responses can be expected when the request contents are invalid (lack of identifiers, or invalid identifiers), or the caller is not authorized to subscribe to the provided identifiers. It is also invalid to request a subscription with the same identifier as an existing subscription, or to unsubscribe using an identifier which is not subscribed. + +Error response are provided as a debugging facility, and the errors are generally not fixable by the Console user. + +A special case exists for situations in which the caller is no longer authorized to receive any events associated with the provided identifiers _after_ the subscription response has been sent. This can happen if the caller token has expired or the rights have been revoked while the stream is ongoing. In such situations the server will terminate the connection explicitly. + +### Authentication and Authorization + +The authentication for the internal API is similar to other APIs available in The Things Stack. Given a `Bearer` token `t`, the `Authorization` header should contain the value `Bearer t`. + +Upon connecting, no authorization will take place - the endpoint only will check that the provided token is valid (i.e. exists and it is not expired). + +The [standard WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) [does not support custom request headers](https://github.com/whatwg/websockets/issues/16). As a result of this limitation, the backend allows the Console to provide the token as a [protocol](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#parameters). Specifically, given a `Bearer` token `t`, the following protocols should be provided to the `WebSocket` constructor: + +- `ttn.lorawan.v3.console.internal.events.v1` +- `ttn.lorawan.v3.header.authorization.bearer.t` + +### Message Format + +Both requests and responses sent over the WebSocket connection are JSON encoded. All messages are JSON objects and are required to contain at least the following two fields: + +- `type`: a string whose value must be either `subscribe`, `unsubscribe`, `publish` or `error`. +- `id`: an unsigned integer which identifies the underlying subscription being served. + +Each of the following subsections describes an individual message and the message direction (client to server or server to client). + +#### `SubscribeRequest` [C -> S] + +- `type`: `subscribe` +- `id`: the subscription identifier +- `identifiers`, `tail`, `after`, `names`: semantically the same fields as those of the `StreamEventsRequest` Protobuf message. + +Example: + +```json +{ + "type": "subscribe", + "id": 1, + "tail": 10, + "identifiers": [ + { + "application_ids": { + "application_id": "app1" + } + } + ] +} +``` + +#### `SubscribeResponse` [S -> C] + +- `type`: `subscribe` +- `id`: the subscription identifier + +Example: + +```json +{ + "type": "subscribe", + "id": 1 +} +``` + +#### `UnsubscribeRequest` [C -> S] + +- `type`: `unsubscribe` +- `id`: the subscription identifier + +Example: + +```json +{ + "type": "unsubscribe", + "id": 1 +} +``` + +#### `UnsubscribeResponse` [S -> C] + +- `type`: `unsubscribe` +- `id`: the subscription identifier + +Example: + +```json +{ + "type": "unsubscribe", + "id": 1 +} +``` + +#### `PublishResponse` [S -> C] + +- `type`: `publish` +- `id`: the subscription identifier +- `event`: an `Event` Protobuf message encoded as a JSON object + +Example: + +```json +{ + "type": "publish", + "id": 1, + "event": { + "name": "as.up.data.forward", + "time": "2023-10-26T16:27:14.103854Z", + "identifiers": [ + { + "device_ids": { + "device_id": "eui-0000000000000003", + "application_ids": { + "application_id": "app1" + } + } + } + ], + "context": { + "tenant-id": "Cgl0aGV0aGluZ3M=" + }, + "visibility": { + "rights": [ + "RIGHT_APPLICATION_TRAFFIC_READ" + ] + }, + "unique_id": "01HDPCZDSQ358JMHD4SC2BQAB8" + } +} +``` + +#### ErrorResponse [S -> C] + +- `type`: `error` +- `id`: the subscription identifier +- `error`: a `Status` Protobuf message encoded as a JSON object + +Example: + +```json +{ + "type": "error", + "id": 1, + "error": { + "code": 6, + "message": "error:pkg/console/internal/events/subscriptions:already_subscribed (already subscribed with ID `1`)", + "details": [ + { + "@type": "type.googleapis.com/ttn.lorawan.v3.ErrorDetails", + "namespace": "pkg/console/internal/events/subscriptions", + "name": "already_subscribed", + "message_format": "already subscribed with ID `{id}`", + "attributes": { + "id": "1" + }, + "correlation_id": "5da004b9f61f479aafe5bbcae4551e63", + "code": 6 + } + ] + } +} +``` diff --git a/pkg/console/internal/events/protocol/protocol.go b/pkg/console/internal/events/protocol/protocol.go new file mode 100644 index 0000000000..3348a8dc82 --- /dev/null +++ b/pkg/console/internal/events/protocol/protocol.go @@ -0,0 +1,331 @@ +// Copyright © 2023 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 protocol implements the protocol for the events package. +package protocol + +import ( + "encoding/json" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/errors" + "go.thethings.network/lorawan-stack/v3/pkg/jsonpb" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + statuspb "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc/status" +) + +var ( + errMessageType = errors.DefineInvalidArgument("message_type", "invalid message type `{type}`") + + _ json.Marshaler = (*ttnpb.EntityIdentifiers)(nil) + _ json.Unmarshaler = (*ttnpb.EntityIdentifiers)(nil) + + _ json.Marshaler = (*ttnpb.Event)(nil) + _ json.Unmarshaler = (*ttnpb.Event)(nil) +) + +// MessageType is the type of a message. +type MessageType int + +const ( + // MessageTypeSubscribe is the type of a subscribe message. + MessageTypeSubscribe MessageType = iota + // MessageTypeUnsubscribe is the type of an unsubscribe message. + MessageTypeUnsubscribe + // MessageTypePublish is the type of a publish message. + MessageTypePublish + // MessageTypeError is the type of an error message. + MessageTypeError +) + +// MarshalJSON implements json.Marshaler. +func (m MessageType) MarshalJSON() ([]byte, error) { + switch m { + case MessageTypeSubscribe: + return []byte(`"subscribe"`), nil + case MessageTypeUnsubscribe: + return []byte(`"unsubscribe"`), nil + case MessageTypePublish: + return []byte(`"publish"`), nil + case MessageTypeError: + return []byte(`"error"`), nil + default: + return nil, errMessageType.WithAttributes("type", m) + } +} + +// UnmarshalJSON implements json.Unmarshaler. +func (m *MessageType) UnmarshalJSON(data []byte) error { + switch string(data) { + case `"subscribe"`: + *m = MessageTypeSubscribe + case `"unsubscribe"`: + *m = MessageTypeUnsubscribe + case `"publish"`: + *m = MessageTypePublish + case `"error"`: + *m = MessageTypeError + default: + return errMessageType.WithAttributes("type", string(data)) + } + return nil +} + +// Request is a request message. +type Request interface { + _requestMessage() +} + +// Response is a response message. +type Response interface { + _responseMessage() +} + +// SubscribeRequest is the request to subscribe to events. +type SubscribeRequest struct { + ID uint64 `json:"id"` + Identifiers []*ttnpb.EntityIdentifiers `json:"identifiers"` + Tail uint32 `json:"tail"` + After *time.Time `json:"after"` + Names []string `json:"names"` +} + +func (SubscribeRequest) _requestMessage() {} + +// Response builds a response to the request. +func (m SubscribeRequest) Response(err error) Response { + if err != nil { + return newErrorResponse(m.ID, err) + } + return &SubscribeResponse{ + ID: m.ID, + } +} + +// MarshalJSON implements json.Marshaler. +func (m SubscribeRequest) MarshalJSON() ([]byte, error) { + type alias SubscribeRequest + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + alias + }{ + Type: MessageTypeSubscribe, + alias: alias(m), + }) +} + +// SubscribeResponse is the response to a subscribe request. +type SubscribeResponse struct { + ID uint64 `json:"id"` +} + +func (SubscribeResponse) _responseMessage() {} + +// MarshalJSON implements json.Marshaler. +func (m SubscribeResponse) MarshalJSON() ([]byte, error) { + type alias SubscribeResponse + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + alias + }{ + Type: MessageTypeSubscribe, + alias: alias(m), + }) +} + +// UnsubscribeRequest is the request to unsubscribe from events. +type UnsubscribeRequest struct { + ID uint64 `json:"id"` +} + +func (UnsubscribeRequest) _requestMessage() {} + +// MarshalJSON implements json.Marshaler. +func (m UnsubscribeRequest) MarshalJSON() ([]byte, error) { + type alias UnsubscribeRequest + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + alias + }{ + Type: MessageTypeUnsubscribe, + alias: alias(m), + }) +} + +// UnsubscribeResponse is the response to an unsubscribe request. +type UnsubscribeResponse struct { + ID uint64 `json:"id"` +} + +func (UnsubscribeResponse) _responseMessage() {} + +// Response builds a response to the request. +func (m UnsubscribeRequest) Response(err error) Response { + if err != nil { + return newErrorResponse(m.ID, err) + } + return &UnsubscribeResponse{ + ID: m.ID, + } +} + +// MarshalJSON implements json.Marshaler. +func (m UnsubscribeResponse) MarshalJSON() ([]byte, error) { + type alias UnsubscribeResponse + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + alias + }{ + Type: MessageTypeUnsubscribe, + alias: alias(m), + }) +} + +// PublishResponse is the request to publish an event. +type PublishResponse struct { + ID uint64 `json:"id"` + Event *ttnpb.Event `json:"event"` +} + +func (PublishResponse) _responseMessage() {} + +// MarshalJSON implements json.Marshaler. +func (m PublishResponse) MarshalJSON() ([]byte, error) { + type alias PublishResponse + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + alias + }{ + Type: MessageTypePublish, + alias: alias(m), + }) +} + +// ErrorResponse is the response to an error. +type ErrorResponse struct { + ID uint64 + Error *status.Status +} + +func (ErrorResponse) _responseMessage() {} + +// statusAlias is an alias of status.Status which supports JSON marshaling. +type statusAlias statuspb.Status + +// MarshalJSON implements json.Marshaler. +func (s *statusAlias) MarshalJSON() ([]byte, error) { + return jsonpb.TTN().Marshal((*statuspb.Status)(s)) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (s *statusAlias) UnmarshalJSON(data []byte) error { + return jsonpb.TTN().Unmarshal(data, (*statuspb.Status)(s)) +} + +// MarshalJSON implements json.Marshaler. +func (m ErrorResponse) MarshalJSON() ([]byte, error) { + return jsonpb.TTN().Marshal(struct { + Type MessageType `json:"type"` + ID uint64 `json:"id"` + Error *statusAlias `json:"error"` + }{ + Type: MessageTypeError, + ID: m.ID, + Error: (*statusAlias)(m.Error.Proto()), + }) +} + +func newErrorResponse(id uint64, err error) Response { + return &ErrorResponse{ + ID: id, + Error: status.Convert(err), + } +} + +// UnmarshalJSON implements json.Unmarshaler. +func (m *ErrorResponse) UnmarshalJSON(data []byte) error { + var alias struct { + ID uint64 `json:"id"` + Error *statusAlias `json:"error"` + } + if err := jsonpb.TTN().Unmarshal(data, &alias); err != nil { + return err + } + m.ID = alias.ID + m.Error = status.FromProto((*statuspb.Status)(alias.Error)) + return nil +} + +// RequestWrapper wraps a request to be sent over the websocket. +type RequestWrapper struct { + Contents Request +} + +// UnmarshalJSON implements json.Unmarshaler. +func (m *RequestWrapper) UnmarshalJSON(data []byte) error { + var contents struct { + Type MessageType `json:"type"` + } + if err := jsonpb.TTN().Unmarshal(data, &contents); err != nil { + return err + } + switch contents.Type { + case MessageTypeSubscribe: + m.Contents = &SubscribeRequest{} + case MessageTypeUnsubscribe: + m.Contents = &UnsubscribeRequest{} + default: + return errMessageType.WithAttributes("type", contents.Type) + } + return jsonpb.TTN().Unmarshal(data, m.Contents) +} + +// MarshalJSON implements json.Marshaler. +func (m RequestWrapper) MarshalJSON() ([]byte, error) { + return json.Marshal(m.Contents) +} + +// ResponseWrapper wraps a response to be sent over the websocket. +type ResponseWrapper struct { + Contents Response +} + +// UnmarshalJSON implements json.Unmarshaler. +func (m *ResponseWrapper) UnmarshalJSON(data []byte) error { + var contents struct { + Type MessageType `json:"type"` + } + if err := jsonpb.TTN().Unmarshal(data, &contents); err != nil { + return err + } + switch contents.Type { + case MessageTypeSubscribe: + m.Contents = &SubscribeResponse{} + case MessageTypeUnsubscribe: + m.Contents = &UnsubscribeResponse{} + case MessageTypePublish: + m.Contents = &PublishResponse{} + case MessageTypeError: + m.Contents = &ErrorResponse{} + default: + return errMessageType.WithAttributes("type", contents.Type) + } + return jsonpb.TTN().Unmarshal(data, m.Contents) +} + +// MarshalJSON implements json.Marshaler. +func (m ResponseWrapper) MarshalJSON() ([]byte, error) { + return json.Marshal(m.Contents) +} diff --git a/pkg/console/internal/events/protocol/protocol_test.go b/pkg/console/internal/events/protocol/protocol_test.go new file mode 100644 index 0000000000..bec85bc950 --- /dev/null +++ b/pkg/console/internal/events/protocol/protocol_test.go @@ -0,0 +1,220 @@ +// Copyright © 2023 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 protocol_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/protocol" + "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" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +func TestMarshal(t *testing.T) { + t.Parallel() + + a := assertions.New(t) + + b, err := json.Marshal(protocol.MessageTypePublish) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte(`"publish"`)) + } + var tp protocol.MessageType + err = json.Unmarshal([]byte(`"publish"`), &tp) + if a.So(err, should.BeNil) { + a.So(tp, should.Equal, protocol.MessageTypePublish) + } + + b, err = json.Marshal(&protocol.SubscribeRequest{ + ID: 0x42, + Identifiers: []*ttnpb.EntityIdentifiers{ + (&ttnpb.ApplicationIdentifiers{ApplicationId: "foo"}).GetEntityIdentifiers(), + (&ttnpb.ClientIdentifiers{ClientId: "bar"}).GetEntityIdentifiers(), + }, + Tail: 10, + After: timePtr(time.UnixMilli(123456789012).UTC()), + Names: []string{"foo", "bar"}, + }) + if a.So(err, should.BeNil) { + a.So( + b, + should.Resemble, + []byte(`{"type":"subscribe","id":66,"identifiers":[{"application_ids":{"application_id":"foo"}},{"client_ids":{"client_id":"bar"}}],"tail":10,"after":"1973-11-29T21:33:09.012Z","names":["foo","bar"]}`), // nolint:lll + ) + } + var subReq protocol.SubscribeRequest + err = json.Unmarshal( + []byte(`{"type":"subscribe","id":66,"identifiers":[{"application_ids":{"application_id":"foo"}},{"client_ids":{"client_id":"bar"}}],"tail":10,"after":"1973-11-29T21:33:09.012Z","names":["foo","bar"]}`), // nolint:lll + &subReq, + ) + if a.So(err, should.BeNil) { + a.So(subReq, should.Resemble, protocol.SubscribeRequest{ + ID: 0x42, + Identifiers: []*ttnpb.EntityIdentifiers{ + (&ttnpb.ApplicationIdentifiers{ApplicationId: "foo"}).GetEntityIdentifiers(), + (&ttnpb.ClientIdentifiers{ClientId: "bar"}).GetEntityIdentifiers(), + }, + Tail: 10, + After: timePtr(time.UnixMilli(123456789012).UTC()), + Names: []string{"foo", "bar"}, + }) + } + + b, err = json.Marshal(&protocol.SubscribeResponse{ + ID: 0x42, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte(`{"type":"subscribe","id":66}`)) + } + var subResp protocol.SubscribeResponse + err = json.Unmarshal([]byte(`{"type":"subscribe","id":66}`), &subResp) + if a.So(err, should.BeNil) { + a.So(subResp, should.Resemble, protocol.SubscribeResponse{ID: 0x42}) + } + + b, err = json.Marshal(&protocol.UnsubscribeRequest{ + ID: 0x42, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte(`{"type":"unsubscribe","id":66}`)) + } + var unsubReq protocol.UnsubscribeRequest + err = json.Unmarshal([]byte(`{"type":"unsubscribe","id":66}`), &unsubReq) + if a.So(err, should.BeNil) { + a.So(unsubReq, should.Resemble, protocol.UnsubscribeRequest{ID: 0x42}) + } + + b, err = json.Marshal(&protocol.UnsubscribeResponse{ + ID: 0x42, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte(`{"type":"unsubscribe","id":66}`)) + } + var unsubResp protocol.UnsubscribeResponse + err = json.Unmarshal([]byte(`{"type":"unsubscribe","id":66}`), &unsubResp) + if a.So(err, should.BeNil) { + a.So(unsubResp, should.Resemble, protocol.UnsubscribeResponse{ID: 0x42}) + } + + b, err = json.Marshal(&protocol.PublishResponse{ + ID: 0x42, + Event: &ttnpb.Event{ + Name: "foo", + Time: timestamppb.New(time.UnixMilli(123456789012).UTC()), + Identifiers: []*ttnpb.EntityIdentifiers{ + (&ttnpb.ApplicationIdentifiers{ApplicationId: "foo"}).GetEntityIdentifiers(), + }, + Data: test.Must(anypb.New(&ttnpb.ApplicationUp{ + Up: &ttnpb.ApplicationUp_UplinkMessage{ + UplinkMessage: &ttnpb.ApplicationUplink{}, + }, + })), + CorrelationIds: []string{"foo", "bar"}, + }, + }) + if a.So(err, should.BeNil) { + a.So( + b, + should.Resemble, + []byte(`{"type":"publish","id":66,"event":{"name":"foo","time":"1973-11-29T21:33:09.012Z","identifiers":[{"application_ids":{"application_id":"foo"}}],"data":{"@type":"type.googleapis.com/ttn.lorawan.v3.ApplicationUp","uplink_message":{}},"correlation_ids":["foo","bar"]}}`), // nolint:lll + ) + } + var pubResp protocol.PublishResponse + err = json.Unmarshal( + []byte(`{"type":"publish","id":66,"event":{"name":"foo","time":"1973-11-29T21:33:09.012Z","identifiers":[{"application_ids":{"application_id":"foo"}}],"data":{"@type":"type.googleapis.com/ttn.lorawan.v3.ApplicationUp","uplink_message":{}},"correlation_ids":["foo","bar"]}}`), // nolint:lll + &pubResp, + ) + if a.So(err, should.BeNil) { + a.So(pubResp, should.Resemble, protocol.PublishResponse{ + ID: 0x42, + Event: &ttnpb.Event{ + Name: "foo", + Time: timestamppb.New(time.UnixMilli(123456789012).UTC()), + Identifiers: []*ttnpb.EntityIdentifiers{ + (&ttnpb.ApplicationIdentifiers{ApplicationId: "foo"}).GetEntityIdentifiers(), + }, + Data: test.Must(anypb.New(&ttnpb.ApplicationUp{ + Up: &ttnpb.ApplicationUp_UplinkMessage{ + UplinkMessage: &ttnpb.ApplicationUplink{}, + }, + })), + CorrelationIds: []string{"foo", "bar"}, + }, + }) + } + + errDefinition := errors.DefineInvalidArgument("bad_argument", "bad argument `{argument}`") + errInstance := errDefinition.WithAttributes("argument", "foo") + errStatus := status.Convert(errInstance) + errJSON := test.Must(json.Marshal(errInstance)) + b, err = json.Marshal(&protocol.ErrorResponse{ + ID: 0x42, + Error: errStatus, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte(fmt.Sprintf(`{"type":"error","id":66,"error":%v}`, string(errJSON)))) // nolint:lll + } + var errResp protocol.ErrorResponse + err = json.Unmarshal([]byte(fmt.Sprintf(`{"type":"error","id":66,"error":%v}`, string(errJSON))), &errResp) // nolint:lll + if a.So(err, should.BeNil) { + a.So(errResp, should.Resemble, protocol.ErrorResponse{ + ID: 0x42, + Error: errStatus, + }) + } + + var reqWrapper protocol.RequestWrapper + err = json.Unmarshal( + []byte(`{"type":"subscribe","id":66,"identifiers":[{"application_ids":{"application_id":"foo"}},{"client_ids":{"client_id":"bar"}}],"tail":10,"after":"1973-11-29T21:33:09.012Z","names":["foo","bar"]}`), // nolint:lll + &reqWrapper, + ) + if a.So(err, should.BeNil) { + a.So(reqWrapper, should.Resemble, protocol.RequestWrapper{ + Contents: &protocol.SubscribeRequest{ + ID: 0x42, + Identifiers: []*ttnpb.EntityIdentifiers{ + (&ttnpb.ApplicationIdentifiers{ApplicationId: "foo"}).GetEntityIdentifiers(), + (&ttnpb.ClientIdentifiers{ClientId: "bar"}).GetEntityIdentifiers(), + }, + Tail: 10, + After: timePtr(time.UnixMilli(123456789012).UTC()), + Names: []string{"foo", "bar"}, + }, + }) + } + + var respWrapper protocol.ResponseWrapper + err = json.Unmarshal([]byte(`{"type":"subscribe","id":66}`), &respWrapper) + if a.So(err, should.BeNil) { + a.So(respWrapper, should.Resemble, protocol.ResponseWrapper{ + Contents: &protocol.SubscribeResponse{ + ID: 0x42, + }, + }) + } +} + +func timePtr(t time.Time) *time.Time { + return &t +} diff --git a/pkg/console/internal/events/ratelimit.go b/pkg/console/internal/events/ratelimit.go new file mode 100644 index 0000000000..4e8c0369dc --- /dev/null +++ b/pkg/console/internal/events/ratelimit.go @@ -0,0 +1,56 @@ +// Copyright © 2023 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 events + +import ( + "context" + "fmt" + + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights" + "go.thethings.network/lorawan-stack/v3/pkg/errors" + "go.thethings.network/lorawan-stack/v3/pkg/ratelimit" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" +) + +var ( + errUnknownCaller = errors.DefineInternal("unknown_caller", "unknown caller type `{type}`") + errRateExceeded = errors.DefineResourceExhausted("rate_exceeded", "request rate exceeded") +) + +func makeRateLimiter(ctx context.Context, limiter ratelimit.Interface) (func() error, error) { + authInfo, err := rights.AuthInfo(ctx) + if err != nil { + return nil, err + } + resourceID := "" + switch method := authInfo.AccessMethod.(type) { + case *ttnpb.AuthInfoResponse_ApiKey: + resourceID = fmt.Sprintf("api-key:%s", method.ApiKey.ApiKey.Id) + case *ttnpb.AuthInfoResponse_OauthAccessToken: + resourceID = fmt.Sprintf("access-token:%s", method.OauthAccessToken.Id) + case *ttnpb.AuthInfoResponse_UserSession: + resourceID = fmt.Sprintf("session-id:%s", method.UserSession.SessionId) + // NOTE: *ttnpb.AuthInfoResponse_GatewayToken_ is intentionally left out. + default: + return nil, errUnknownCaller.WithAttributes("type", fmt.Sprintf("%T", authInfo.AccessMethod)) + } + resource := ratelimit.ConsoleEventsRequestResource(resourceID) + return func() error { + if limit, _ := limiter.RateLimit(resource); limit { + return errRateExceeded.New() + } + return nil + }, nil +} diff --git a/pkg/console/internal/events/subscriptions/subscriptions.go b/pkg/console/internal/events/subscriptions/subscriptions.go new file mode 100644 index 0000000000..0a099fffdd --- /dev/null +++ b/pkg/console/internal/events/subscriptions/subscriptions.go @@ -0,0 +1,255 @@ +// Copyright © 2023 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 subscriptions implements the events mux subscriptions. +package subscriptions + +import ( + "context" + "sync" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights" + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights/rightsutil" + "go.thethings.network/lorawan-stack/v3/pkg/errors" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/task" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" +) + +// SubscriptionEvent wraps an events.Event with a subscription ID. +type SubscriptionEvent struct { + ID uint64 + Event events.Event +} + +// Interface is the interface for the events mux subscriptions. +type Interface interface { + // Subscribe subscribes to events. + Subscribe( + id uint64, identifiers []*ttnpb.EntityIdentifiers, after *time.Time, tail uint32, names []string, + ) error + // Unsubscribe unsubscribe to events. + Unsubscribe(id uint64) error + + // SubscriptionEvents provides the events for the underlying subscriptions. + SubscriptionEvents() <-chan *SubscriptionEvent + + // Close closes all of the underlying subscriptions and waits for the background tasks to finish. + Close() error +} + +type subscription struct { + id uint64 + cancel func(error) + wg sync.WaitGroup + cancelParent func(error) + inputCh <-chan events.Event + outputCh chan<- *SubscriptionEvent +} + +func (s *subscription) run(ctx context.Context) (err error) { + defer func() { + select { + case <-ctx.Done(): + default: + s.cancelParent(err) + } + }() + for { + select { + case <-ctx.Done(): + return ctx.Err() + case evt := <-s.inputCh: + isVisible, err := rightsutil.EventIsVisible(ctx, evt) + if err != nil { + if err := rights.RequireAny(ctx, evt.Identifiers()...); err != nil { + return err + } + log.FromContext(ctx).WithError(err).Warn("Failed to check event visibility") + continue + } + if !isVisible { + continue + } + select { + case <-ctx.Done(): + return ctx.Err() + case s.outputCh <- &SubscriptionEvent{ + ID: s.id, + Event: evt, + }: + } + } + } +} + +type subscriptions struct { + ctx context.Context + cancel func(error) + subscriber events.Subscriber + definedNames map[string]struct{} + taskStarter task.Starter + + wg sync.WaitGroup + ch chan *SubscriptionEvent + subs map[uint64]*subscription +} + +var _ Interface = (*subscriptions)(nil) + +// Close implements Interface. +func (s *subscriptions) Close() error { + for id, sub := range s.subs { + delete(s.subs, id) + sub.cancel(nil) + sub.wg.Wait() + } + s.wg.Wait() + return nil +} + +// SubscriptionEvents implements Interface. +func (s *subscriptions) SubscriptionEvents() <-chan *SubscriptionEvent { return s.ch } + +var ( + errAlreadySubscribed = errors.DefineAlreadyExists("already_subscribed", "already subscribed with ID `{id}`") + errNoIdentifiers = errors.DefineInvalidArgument("no_identifiers", "no identifiers") +) + +// Subscribe implements Interface. +func (s *subscriptions) Subscribe( + id uint64, identifiers []*ttnpb.EntityIdentifiers, after *time.Time, tail uint32, names []string, +) (err error) { + if err := s.validateSubscribe(id, identifiers); err != nil { + return err + } + names, err = events.NamesFromPatterns(s.definedNames, names) + if err != nil { + return err + } + ch := make(chan events.Event, channelSize(tail)) + ctx, cancel := context.WithCancelCause(s.ctx) + defer func() { + if err != nil { + cancel(err) + } + }() + if store, hasStore := s.subscriber.(events.Store); hasStore { + if after == nil && tail == 0 { + now := time.Now() + after = &now + } + f := func(ctx context.Context) (err error) { + defer func() { + select { + case <-ctx.Done(): + default: + s.cancel(err) + } + }() + return store.SubscribeWithHistory(ctx, names, identifiers, after, int(tail), events.Channel(ch)) + } + s.wg.Add(1) + s.taskStarter.StartTask(&task.Config{ + Context: ctx, + ID: "console_events_subscribe", + Func: f, + Done: s.wg.Done, + Restart: task.RestartNever, + Backoff: task.DefaultBackoffConfig, + }) + } else { + if err := s.subscriber.Subscribe(ctx, names, identifiers, events.Channel(ch)); err != nil { + return err + } + } + sub := &subscription{ + id: id, + cancel: cancel, + cancelParent: s.cancel, + inputCh: ch, + outputCh: s.ch, + } + sub.wg.Add(1) + s.taskStarter.StartTask(&task.Config{ + Context: ctx, + ID: "console_events_filter", + Func: sub.run, + Done: sub.wg.Done, + Restart: task.RestartNever, + Backoff: task.DefaultBackoffConfig, + }) + s.subs[id] = sub + return nil +} + +var errNotSubscribed = errors.DefineNotFound("not_subscribed", "not subscribed with ID `{id}`") + +// Unsubscribe implements Interface. +func (s *subscriptions) Unsubscribe(id uint64) error { + sub, ok := s.subs[id] + if !ok { + return errNotSubscribed.WithAttributes("id", id) + } + delete(s.subs, id) + sub.cancel(nil) + sub.wg.Wait() + return nil +} + +// New returns a new Interface. +func New( + ctx context.Context, + cancel func(error), + subscriber events.Subscriber, + definedNames map[string]struct{}, + taskStarter task.Starter, +) Interface { + return &subscriptions{ + ctx: ctx, + cancel: cancel, + subscriber: subscriber, + definedNames: definedNames, + taskStarter: taskStarter, + ch: make(chan *SubscriptionEvent, 1), + subs: make(map[uint64]*subscription), + } +} + +func (s *subscriptions) validateSubscribe(id uint64, identifiers []*ttnpb.EntityIdentifiers) error { + if _, ok := s.subs[id]; ok { + return errAlreadySubscribed.WithAttributes("id", id) + } + if len(identifiers) == 0 { + return errNoIdentifiers.New() + } + for _, ids := range identifiers { + if err := ids.ValidateFields(); err != nil { + return err + } + } + return rights.RequireAny(s.ctx, identifiers...) +} + +func channelSize(n uint32) uint32 { + if n < 8 { + n = 8 + } + if n > 1024 { + n = 1024 + } + return n +} diff --git a/pkg/console/internal/events/subscriptions/subscriptions_test.go b/pkg/console/internal/events/subscriptions/subscriptions_test.go new file mode 100644 index 0000000000..10aaf738bb --- /dev/null +++ b/pkg/console/internal/events/subscriptions/subscriptions_test.go @@ -0,0 +1,303 @@ +// Copyright © 2023 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 subscriptions_test + +import ( + "context" + "sync" + "testing" + "time" + + "go.thethings.network/lorawan-stack/v3/pkg/auth/rights" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/subscriptions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/task" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/unique" + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +type subscribeRequest struct { + Context context.Context + Names []string + Identifiers []*ttnpb.EntityIdentifiers + After *time.Time + Tail int + Handler events.Handler + + Response chan<- error +} + +type mockSubscriber struct { + subReqs chan subscribeRequest +} + +func (m *mockSubscriber) subscribeRequests() <-chan subscribeRequest { return m.subReqs } + +// Subscribe implements events.Subscriber. +func (m *mockSubscriber) Subscribe( + ctx context.Context, names []string, identifiers []*ttnpb.EntityIdentifiers, hdl events.Handler, +) error { + ch := make(chan error, 1) + select { + case <-ctx.Done(): + return ctx.Err() + case m.subReqs <- subscribeRequest{ + Context: ctx, + Names: names, + Identifiers: identifiers, + Handler: hdl, + + Response: ch, + }: + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-ch: + return err + } + } +} + +var _ events.Subscriber = (*mockSubscriber)(nil) + +type mockPubSubStore struct { + subReqs chan subscribeRequest +} + +func (m *mockPubSubStore) subscribeRequests() <-chan subscribeRequest { return m.subReqs } + +func (*mockPubSubStore) historical() {} + +// Publish implements events.Store. +func (*mockPubSubStore) Publish(...events.Event) { panic("not implemented") } + +// Subscribe implements events.Store. +func (*mockPubSubStore) Subscribe(context.Context, []string, []*ttnpb.EntityIdentifiers, events.Handler) error { + panic("not implemented") +} + +// FindRelated implements events.Store. +func (*mockPubSubStore) FindRelated(context.Context, string) ([]events.Event, error) { + panic("not implemented") +} + +// FetchHistory implements events.Store. +func (*mockPubSubStore) FetchHistory( + context.Context, []string, []*ttnpb.EntityIdentifiers, *time.Time, int, +) ([]events.Event, error) { + panic("not implemented") +} + +// SubscribeWithHistory implements events.Store. +func (m *mockPubSubStore) SubscribeWithHistory( + ctx context.Context, names []string, ids []*ttnpb.EntityIdentifiers, after *time.Time, tail int, hdl events.Handler, +) error { + ch := make(chan error, 1) + select { + case <-ctx.Done(): + return ctx.Err() + case m.subReqs <- subscribeRequest{ + Context: ctx, + Names: names, + Identifiers: ids, + After: after, + Tail: tail, + Handler: hdl, + + Response: ch, + }: + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-ch: + return err + } + } +} + +var _ events.Store = (*mockPubSubStore)(nil) + +func runTestSubscriptions( + t *testing.T, + subscriber interface { + events.Subscriber + subscribeRequests() <-chan subscribeRequest + }, +) { + t.Helper() + + _, historical := subscriber.(interface{ historical() }) + + a, ctx := test.New(t) + ctx, cancel := context.WithCancelCause(ctx) + defer cancel(nil) + + timeout := test.Delay << 3 + app1IDs, app2IDs := &ttnpb.ApplicationIdentifiers{ + ApplicationId: "foo", + }, &ttnpb.ApplicationIdentifiers{ + ApplicationId: "bar", + } + ctx = rights.NewContext(ctx, &rights.Rights{ + ApplicationRights: *rights.NewMap(map[string]*ttnpb.Rights{ + unique.ID(ctx, app1IDs): ttnpb.RightsFrom(ttnpb.Right_RIGHT_APPLICATION_ALL), + }), + }) + + sub := subscriptions.New( + ctx, + cancel, + subscriber, + map[string]struct{}{ + "test": {}, + }, + task.StartTaskFunc(task.DefaultStartTask), + ) + defer sub.Close() + + select { + case <-ctx.Done(): + return + case <-time.After(timeout): + case req := <-subscriber.subscribeRequests(): + t.Fatal("Unexpected subscribe request", req) + } + + now := time.Now() + + var wg sync.WaitGroup + defer wg.Wait() + + wg.Add(1) + go func() { + defer wg.Done() + err := sub.Subscribe( + 1, + []*ttnpb.EntityIdentifiers{ + app1IDs.GetEntityIdentifiers(), + }, + &now, + 10, + []string{"test"}, + ) + a.So(err, should.BeNil) + }() + var handler events.Handler + select { + case <-ctx.Done(): + return + case req := <-subscriber.subscribeRequests(): + a.So(req.Context, should.HaveParentContextOrEqual, ctx) + a.So(req.Names, should.Resemble, []string{"test"}) + a.So(req.Identifiers, should.Resemble, []*ttnpb.EntityIdentifiers{ + app1IDs.GetEntityIdentifiers(), + }) + if historical { + a.So(req.After, should.Resemble, &now) + a.So(req.Tail, should.Equal, 10) + } + a.So(req.Handler, should.NotBeNil) + if !historical { + select { + case <-ctx.Done(): + return + case req.Response <- nil: + } + } + handler = req.Handler + } + wg.Wait() + + err := sub.Subscribe( + 1, + []*ttnpb.EntityIdentifiers{ + app1IDs.GetEntityIdentifiers(), + }, + &now, + 10, + []string{"test"}, + ) + a.So(err, should.NotBeNil) + + evt := events.New( + ctx, + "test", + "test", + events.WithIdentifiers(app2IDs), + events.WithVisibility(ttnpb.Right_RIGHT_APPLICATION_DEVICES_READ), + ) + handler.Notify(evt) + + select { + case <-ctx.Done(): + return + case <-time.After(timeout): + case subEvt := <-sub.SubscriptionEvents(): + t.Fatal("Unexpected subscription event", subEvt) + } + + evt = events.New( + ctx, + "test", + "test", + events.WithIdentifiers(app1IDs), + events.WithVisibility(ttnpb.Right_RIGHT_APPLICATION_DEVICES_READ), + ) + handler.Notify(evt) + + select { + case <-ctx.Done(): + return + case subEvt := <-sub.SubscriptionEvents(): + a.So(subEvt.ID, should.Equal, 1) + a.So(subEvt.Event, should.ResembleEvent, evt) + } + + err = sub.Unsubscribe(1) + a.So(err, should.BeNil) + + err = sub.Unsubscribe(1) + a.So(err, should.NotBeNil) + + select { + case <-ctx.Done(): + return + case <-time.After(timeout): + case subEvt := <-sub.SubscriptionEvents(): + t.Fatal("Unexpected subscription event", subEvt) + } +} + +func TestSubscriptions(t *testing.T) { + t.Parallel() + runTestSubscriptions( + t, + &mockSubscriber{ + subReqs: make(chan subscribeRequest, 1), + }, + ) +} + +func TestStoreSubscriptions(t *testing.T) { + t.Parallel() + runTestSubscriptions( + t, + &mockPubSubStore{ + subReqs: make(chan subscribeRequest, 1), + }, + ) +} diff --git a/pkg/console/internal/events/tasks.go b/pkg/console/internal/events/tasks.go new file mode 100644 index 0000000000..af7024a5b6 --- /dev/null +++ b/pkg/console/internal/events/tasks.go @@ -0,0 +1,81 @@ +// Copyright © 2023 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 events + +import ( + "context" + "errors" + "io" + + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/eventsmux" + "go.thethings.network/lorawan-stack/v3/pkg/console/internal/events/protocol" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "nhooyr.io/websocket" + "nhooyr.io/websocket/wsjson" +) + +func makeMuxTask(m eventsmux.Interface, cancel func(error)) func(context.Context) error { + return func(ctx context.Context) (err error) { + defer func() { cancel(err) }() + return m.Run(ctx) + } +} + +func makeReadTask( + conn *websocket.Conn, m eventsmux.Interface, rateLimit func() error, cancel func(error), +) func(context.Context) error { + return func(ctx context.Context) (err error) { + defer func() { cancel(err) }() + defer func() { + if closeErr := (websocket.CloseError{}); errors.As(err, &closeErr) { + log.FromContext(ctx).WithFields(log.Fields( + "code", closeErr.Code, + "reason", closeErr.Reason, + )).Debug("WebSocket closed") + err = io.EOF + } + }() + for { + var request protocol.RequestWrapper + if err := wsjson.Read(ctx, conn, &request); err != nil { + return err + } + if err := rateLimit(); err != nil { + return err + } + select { + case <-ctx.Done(): + return ctx.Err() + case m.Requests() <- request.Contents: + } + } + } +} + +func makeWriteTask(conn *websocket.Conn, m eventsmux.Interface, cancel func(error)) func(context.Context) error { + return func(ctx context.Context) (err error) { + defer func() { cancel(err) }() + for { + select { + case <-ctx.Done(): + return ctx.Err() + case response := <-m.Responses(): + if err := wsjson.Write(ctx, conn, response); err != nil { + return err + } + } + } + } +} diff --git a/pkg/crypto/join_messages_test.go b/pkg/crypto/join_messages_test.go index 3866f32f50..37e3ad4230 100644 --- a/pkg/crypto/join_messages_test.go +++ b/pkg/crypto/join_messages_test.go @@ -16,6 +16,7 @@ package crypto_test import ( "fmt" + "slices" "testing" "github.com/mohae/deepcopy" @@ -23,7 +24,6 @@ import ( . "go.thethings.network/lorawan-stack/v3/pkg/crypto" "go.thethings.network/lorawan-stack/v3/pkg/types" "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" - "golang.org/x/exp/slices" ) func TestJoinAcceptEncryption(t *testing.T) { diff --git a/pkg/crypto/relay.go b/pkg/crypto/relay.go new file mode 100644 index 0000000000..c64481809c --- /dev/null +++ b/pkg/crypto/relay.go @@ -0,0 +1,31 @@ +// Copyright © 2023 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 crypto + +import ( + "crypto/aes" + + "go.thethings.network/lorawan-stack/v3/pkg/types" +) + +// DeriveRootWorSKey derives the root relay session key. +func DeriveRootWorSKey(nwkSEncKey types.AES128Key) types.AES128Key { + var key types.AES128Key + var plain [16]byte + plain[0] = 0x01 + block, _ := aes.NewCipher(nwkSEncKey[:]) + block.Encrypt(key[:], plain[:]) + return key +} diff --git a/pkg/crypto/relay_test.go b/pkg/crypto/relay_test.go new file mode 100644 index 0000000000..992267bbf4 --- /dev/null +++ b/pkg/crypto/relay_test.go @@ -0,0 +1,35 @@ +// Copyright © 2023 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 crypto_test + +import ( + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/crypto" + "go.thethings.network/lorawan-stack/v3/pkg/types" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +func TestDeriveRootWorSKey(t *testing.T) { + t.Parallel() + a := assertions.New(t) + nwkSEncKey := types.AES128Key{ + 0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0B, + } + a.So(crypto.DeriveRootWorSKey(nwkSEncKey), should.Equal, types.AES128Key{ + 0xEE, 0x91, 0xDC, 0x1A, 0x66, 0x66, 0xC0, 0x6E, 0x82, 0x77, 0xDE, 0x6D, 0xB4, 0xDB, 0x94, 0x5F, + }) +} diff --git a/pkg/deviceclaimingserver/enddevices/ttjsv2/messages.go b/pkg/deviceclaimingserver/enddevices/ttjsv2/messages.go index c000254e1d..a6c5e35f35 100644 --- a/pkg/deviceclaimingserver/enddevices/ttjsv2/messages.go +++ b/pkg/deviceclaimingserver/enddevices/ttjsv2/messages.go @@ -14,6 +14,10 @@ package ttjsv2 +import ( + "context" +) + // ClaimData contains information about the claim. type ClaimData struct { HomeNetID string `json:"homeNetID"` @@ -38,6 +42,25 @@ type ClaimRequest struct { KEK *KEK `json:"kek,omitempty"` } +// Apply applies the context to the request. +func (req ClaimRequest) Apply(ctx context.Context, c Component) (ClaimRequest, error) { + deriv := req + if req.HomeNSID != nil { + deriv.HomeNSID = stringValue(*req.HomeNSID) + } + if req.RegenerateOwnerToken != nil { + deriv.RegenerateOwnerToken = boolValue(*req.RegenerateOwnerToken) + } + if req.Lock != nil { + deriv.Lock = boolValue(*req.Lock) + } + if req.KEK != nil { + kek := *req.KEK + deriv.KEK = &kek + } + return deriv, nil +} + // ErrorResponse is a message that may be returned by The Things Join Server in case of an error. type ErrorResponse struct { Message string `json:"message"` diff --git a/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs.go b/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs.go index 2e15c46245..50e95e30a6 100644 --- a/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs.go +++ b/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs.go @@ -123,7 +123,7 @@ func (c *TTJS) Claim(ctx context.Context, joinEUI, devEUI types.EUI64, claimAuth "url", reqURL, )) - claimReq := &ClaimRequest{ + claimReq := ClaimRequest{ OwnerToken: claimAuthenticationCode, Lock: boolValue(true), HomeNetID: c.config.NetID.String(), @@ -132,6 +132,10 @@ func (c *TTJS) Claim(ctx context.Context, joinEUI, devEUI types.EUI64, claimAuth if c.config.NSID != nil { claimReq.HomeNSID = stringValue(c.config.NSID.String()) } + claimReq, err := claimReq.Apply(ctx, c) + if err != nil { + return err + } buf, err := json.Marshal(claimReq) if err != nil { return err diff --git a/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs_test.go b/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs_test.go index 022420f7b3..08515ba517 100644 --- a/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs_test.go +++ b/pkg/deviceclaimingserver/enddevices/ttjsv2/ttjs_test.go @@ -99,7 +99,7 @@ func TestTTJS(t *testing.T) { //nolint:paralleltest client1 := ttjsv2.NewClient(c, fetcher, ttjsv2.Config{ NetID: test.DefaultNetID, NSID: &homeNSID, - ASID: "localhost", + ASID: client1ASID, JoinEUIPrefixes: []types.EUI64Prefix{ supportedJoinEUIPrefix, }, @@ -176,7 +176,7 @@ func TestTTJS(t *testing.T) { //nolint:paralleltest client2 := ttjsv2.NewClient(c, fetcher, ttjsv2.Config{ NetID: test.DefaultNetID, NSID: &homeNSID, - ASID: "localhost", + ASID: client2ASID, JoinEUIPrefixes: []types.EUI64Prefix{ supportedJoinEUIPrefix, }, diff --git a/pkg/devicerepository/grpc.go b/pkg/devicerepository/grpc.go index c0d490b751..bad776016a 100644 --- a/pkg/devicerepository/grpc.go +++ b/pkg/devicerepository/grpc.go @@ -65,7 +65,7 @@ func (dr *DeviceRepository) ListBrands( ctx context.Context, req *ttnpb.ListEndDeviceBrandsRequest, ) (*ttnpb.ListEndDeviceBrandsResponse, error) { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } if req.Limit > defaultLimit || req.Limit == 0 { @@ -97,7 +97,7 @@ func (dr *DeviceRepository) GetBrand( ctx context.Context, req *ttnpb.GetEndDeviceBrandRequest, ) (*ttnpb.EndDeviceBrand, error) { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } response, err := dr.store.GetBrands(store.GetBrandsRequest{ @@ -121,7 +121,7 @@ func (dr *DeviceRepository) ListModels( ctx context.Context, req *ttnpb.ListEndDeviceModelsRequest, ) (*ttnpb.ListEndDeviceModelsResponse, error) { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } if req.Limit > defaultLimit || req.Limit == 0 { @@ -152,7 +152,7 @@ func (dr *DeviceRepository) GetModel( ctx context.Context, req *ttnpb.GetEndDeviceModelRequest, ) (*ttnpb.EndDeviceModel, error) { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } response, err := dr.store.GetModels(store.GetModelsRequest{ @@ -177,7 +177,7 @@ func (dr *DeviceRepository) GetTemplate( ctx context.Context, req *ttnpb.GetTemplateRequest, ) (*ttnpb.EndDeviceTemplate, error) { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } return dr.store.GetTemplate(req, nil) @@ -189,7 +189,7 @@ func getDecoder( f func(store.GetCodecRequest) (*ttnpb.MessagePayloadDecoder, error), ) (*ttnpb.MessagePayloadDecoder, error) { if clusterauth.Authorized(ctx) != nil { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } } @@ -218,7 +218,7 @@ func (dr *DeviceRepository) GetDownlinkEncoder( req *ttnpb.GetPayloadFormatterRequest, ) (*ttnpb.MessagePayloadEncoder, error) { if clusterauth.Authorized(ctx) != nil { - if err := rights.RequireAuthentication(ctx); err != nil { + if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } } diff --git a/pkg/email/templates/invitation.html.tmpl b/pkg/email/templates/invitation.html.tmpl index fdba94363a..744f744fc3 100644 --- a/pkg/email/templates/invitation.html.tmpl +++ b/pkg/email/templates/invitation.html.tmpl @@ -3,7 +3,7 @@ Invitation {{- end -}} {{- define "preview" -}} -You have been invited {{- with .SenderIds }} by user {{ .IDString }} {{ end -}} to join {{ .Network.Name }}. +You have been invited to join {{ .Network.Name }}. {{- end -}} {{- define "body" -}} @@ -11,7 +11,7 @@ You have been invited {{- with .SenderIds }} by user {{ .IDString }} {{ end -}} Hello,

-You have been invited {{- with .SenderIds }} by user {{ .IDString }} {{ end -}} to join {{ .Network.Name }}. +You have been invited to join {{ .Network.Name }}.

You can now visit this link to register your user account. diff --git a/pkg/email/templates/invitation.txt.tmpl b/pkg/email/templates/invitation.txt.tmpl index 33e74ba21c..f1f9f0d174 100644 --- a/pkg/email/templates/invitation.txt.tmpl +++ b/pkg/email/templates/invitation.txt.tmpl @@ -1,6 +1,6 @@ Hello, -You have been invited {{- with .SenderIds }} by user {{ .IDString }} {{ end -}} to join {{ .Network.Name }}. +You have been invited to join {{ .Network.Name }}. You can now go to {{ .Network.IdentityServerURL }}/register?invitation_token={{ .InvitationToken }} to register your user account. diff --git a/pkg/email/templates/templates_test.go b/pkg/email/templates/templates_test.go index 45f1d93a33..f1577df4fa 100644 --- a/pkg/email/templates/templates_test.go +++ b/pkg/email/templates/templates_test.go @@ -50,6 +50,7 @@ var testTemplateData = email.NewTemplateData( ) func TestEmailTemplates(t *testing.T) { + t.Parallel() defer func() { if t.Failed() { t.Log("NOTE: If you encounter a diff, you may have to run this test with the -write-golden flag.") @@ -60,7 +61,7 @@ func TestEmailTemplates(t *testing.T) { UserId: "foo-usr", } - for _, tt := range []struct { + for _, tc := range []struct { TemplateName string TemplateData email.TemplateData }{ @@ -103,11 +104,13 @@ func TestEmailTemplates(t *testing.T) { }, }, } { - t.Run(tt.TemplateName, func(t *testing.T) { + tc := tc + t.Run(tc.TemplateName, func(t *testing.T) { + t.Parallel() a, ctx := test.New(t) - emailTemplate := email.GetTemplate(ctx, tt.TemplateName) - message, err := emailTemplate.Execute(tt.TemplateData) + emailTemplate := email.GetTemplate(ctx, tc.TemplateName) + message, err := emailTemplate.Execute(tc.TemplateData) if a.So(err, should.BeNil) && a.So(message, should.NotBeNil) { if err = compareMessageToGolden(message); err != nil { t.Error(err) @@ -118,6 +121,7 @@ func TestEmailTemplates(t *testing.T) { } func TestNotificationEmailTemplates(t *testing.T) { + t.Parallel() defer func() { if t.Failed() { t.Log("NOTE: If you encounter a diff, you may have to run this test with the -write-golden flag.") @@ -343,9 +347,11 @@ func TestNotificationEmailTemplates(t *testing.T) { }), }, } { + notification := ttnpb.Clone(notification) notification.CreatedAt = now notification.Email = true t.Run(notification.NotificationType, func(t *testing.T) { + t.Parallel() a, ctx := test.New(t) emailNotification := email.GetNotification(ctx, notification.GetNotificationType()) diff --git a/pkg/email/templates/testdata/invitation.body.golden.html b/pkg/email/templates/testdata/invitation.body.golden.html index afb8195d9f..50228d67ad 100644 --- a/pkg/email/templates/testdata/invitation.body.golden.html +++ b/pkg/email/templates/testdata/invitation.body.golden.html @@ -92,7 +92,7 @@ -

You have been invited by user foo-usr to join The Things Network.
+
You have been invited to join The Things Network.
@@ -172,7 +172,7 @@ Hello,

-You have been invited by user foo-usr to join The Things Network. +You have been invited to join The Things Network.

You can now visit this link to register your user account. diff --git a/pkg/email/templates/testdata/invitation.body.golden.txt b/pkg/email/templates/testdata/invitation.body.golden.txt index 5f7c57dc0f..4300e12462 100644 --- a/pkg/email/templates/testdata/invitation.body.golden.txt +++ b/pkg/email/templates/testdata/invitation.body.golden.txt @@ -1,6 +1,6 @@ Hello, -You have been invited by user foo-usr to join The Things Network. +You have been invited to join The Things Network. You can now go to https://eu1.cloud.thethings.network/oauth/register?invitation_token=TOKEN to register your user account. diff --git a/pkg/email/templates/testdata/user_requested.body.golden.html b/pkg/email/templates/testdata/user_requested.body.golden.html index 34793ef0b3..b9dc565814 100644 --- a/pkg/email/templates/testdata/user_requested.body.golden.html +++ b/pkg/email/templates/testdata/user_requested.body.golden.html @@ -172,23 +172,10 @@ Dear John Doe,

-A new user just registered on The Things Network. +A new user with ID foo-usr just registered on The Things Network. Since user registration requires admin approval, you need to approve this user before they can login.

-

-User ID: foo-usr -

-

-Name: Foo User -

-

-Description: Foo User Description -

-

-Email Address: foo@example.com -

-

You can review this user in the Console.

diff --git a/pkg/email/templates/testdata/user_requested.body.golden.txt b/pkg/email/templates/testdata/user_requested.body.golden.txt index 8c4bba4fdb..6eb8c27dd7 100644 --- a/pkg/email/templates/testdata/user_requested.body.golden.txt +++ b/pkg/email/templates/testdata/user_requested.body.golden.txt @@ -1,11 +1,6 @@ Dear John Doe, -A new user just registered on The Things Network. +A new user with with ID foo-usr just registered on The Things Network. Since user registration requires admin approval, you need to approve this user before they can login. -User ID: foo-usr -Name: Foo User -Description: Foo User Description -Email Address: foo@example.com - You can go to https://console.cloud.thethings.network/admin-panel/user-management/foo-usr to review this user in the Console. diff --git a/pkg/email/templates/testdata/validate.body.golden.html b/pkg/email/templates/testdata/validate.body.golden.html index 0cf6204da5..6e34ea322e 100644 --- a/pkg/email/templates/testdata/validate.body.golden.html +++ b/pkg/email/templates/testdata/validate.body.golden.html @@ -175,7 +175,7 @@ Please confirm your email address for The Things Network.

-Your email address "john.doe@example.com" will be used by user foo-usr. +Your email address will be linked to user foo-usr.

You can now visit this link to confirm your email address. diff --git a/pkg/email/templates/testdata/validate.body.golden.txt b/pkg/email/templates/testdata/validate.body.golden.txt index e5b2da8b07..e5b2af998c 100644 --- a/pkg/email/templates/testdata/validate.body.golden.txt +++ b/pkg/email/templates/testdata/validate.body.golden.txt @@ -2,7 +2,7 @@ Hello, Please confirm your email address for The Things Network. -Your email address "john.doe@example.com" will be used by user "foo-usr". +Your email address will be linked to user "foo-usr". You can go to https://eu1.cloud.thethings.network/oauth/validate?reference=ID&token=TOKEN to confirm your email address. Alternatively, you can use the reference "ID" and confirmation token "TOKEN" directly. diff --git a/pkg/email/templates/user_requested.html.tmpl b/pkg/email/templates/user_requested.html.tmpl index bc8caf9b9f..31327970c1 100644 --- a/pkg/email/templates/user_requested.html.tmpl +++ b/pkg/email/templates/user_requested.html.tmpl @@ -11,23 +11,10 @@ Your review is required for a newly registered user. Dear {{ .ReceiverName }},

-A new user just registered on {{ .Network.Name }}. +A new user with ID {{ .User.Ids.IDString }} just registered on {{ .Network.Name }}. Since user registration requires admin approval, you need to approve this user before they can login.

-

-User ID: {{ .User.Ids.IDString }} -

-

-Name: {{ with .User.Name }}{{ . }}{{ else }}none{{ end }} -

-

-Description: {{ with .User.Description }}{{ . }}{{ else }}none{{ end }} -

-

-Email Address: {{ with .User.PrimaryEmailAddress }}{{ . }}{{ else }}none{{ end }} -

-

You can review this user in the Console.

{{- end -}} diff --git a/pkg/email/templates/user_requested.txt.tmpl b/pkg/email/templates/user_requested.txt.tmpl index 20b4f009e7..495f106d00 100644 --- a/pkg/email/templates/user_requested.txt.tmpl +++ b/pkg/email/templates/user_requested.txt.tmpl @@ -1,11 +1,6 @@ Dear {{ .ReceiverName }}, -A new user just registered on {{ .Network.Name }}. +A new user with with ID {{ .User.Ids.IDString }} just registered on {{ .Network.Name }}. Since user registration requires admin approval, you need to approve this user before they can login. -User ID: {{ .User.Ids.IDString }} -Name: {{ with .User.Name }}{{ . }}{{ else }}(none){{ end }} -Description: {{ with .User.Description }}{{ . }}{{ else }}(none){{ end }} -Email Address: {{ with .User.PrimaryEmailAddress }}{{ . }}{{ else }}(none){{ end }} - You can go to {{ .ConsoleURL }} to review this user in the Console. diff --git a/pkg/email/templates/validate.html.tmpl b/pkg/email/templates/validate.html.tmpl index 1bd37a04bd..4c2832de3e 100644 --- a/pkg/email/templates/validate.html.tmpl +++ b/pkg/email/templates/validate.html.tmpl @@ -14,7 +14,7 @@ Hello, Please confirm your email address for {{ .Network.Name }}.

-Your email address "{{ .Receiver.PrimaryEmailAddress }}" will be used by {{ .EntityType }} {{ .IDString }}. +Your email address will be linked to {{ .EntityType }} {{ .IDString }}.

You can now visit this link to confirm your email address. diff --git a/pkg/email/templates/validate.txt.tmpl b/pkg/email/templates/validate.txt.tmpl index 413d3b609f..2f725d966c 100644 --- a/pkg/email/templates/validate.txt.tmpl +++ b/pkg/email/templates/validate.txt.tmpl @@ -2,7 +2,7 @@ Hello, Please confirm your email address for {{ .Network.Name }}. -Your email address "{{ .Receiver.PrimaryEmailAddress }}" will be used by {{ .EntityType }} "{{ .IDString }}". +Your email address will be linked to {{ .EntityType }} "{{ .IDString }}". You can go to {{ .Network.IdentityServerURL }}/validate?reference={{ .ID }}&token={{ .Token }} to confirm your email address. Alternatively, you can use the reference "{{ .ID }}" and confirmation token "{{ .Token }}" directly. diff --git a/pkg/encoding/lorawan/mac.go b/pkg/encoding/lorawan/mac.go index 2c7ae3152c..ece8e44004 100644 --- a/pkg/encoding/lorawan/mac.go +++ b/pkg/encoding/lorawan/mac.go @@ -904,6 +904,568 @@ var DefaultMACCommands = MACCommandSpec{ return nil }), }, + + ttnpb.MACCommandIdentifier_CID_RELAY_CONF: &MACCommandDescriptor{ + InitiatedByDevice: false, + + UplinkLength: 1, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayConfAns() + var status byte + if pld.SecondChannelFrequencyAck { + status |= 1 + } + if pld.SecondChannelAckOffsetAck { + status |= (1 << 1) + } + if pld.SecondChannelDataRateIndexAck { + status |= (1 << 2) + } + if pld.SecondChannelIndexAck { + status |= (1 << 3) + } + if pld.DefaultChannelIndexAck { + status |= (1 << 4) + } + if pld.CadPeriodicityAck { + status |= (1 << 5) + } + b = append(b, status) + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CONF, + "RelayConfAns", + 1, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayConfAns_{ + RelayConfAns: &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: b[0]&1 == 1, + SecondChannelAckOffsetAck: (b[0]>>1)&1 == 1, + SecondChannelDataRateIndexAck: (b[0]>>2)&1 == 1, + SecondChannelIndexAck: (b[0]>>3)&1 == 1, + DefaultChannelIndexAck: (b[0]>>4)&1 == 1, + CadPeriodicityAck: (b[0]>>5)&1 == 1, + }, + } + return nil + }, + ), + + DownlinkLength: 5, + AppendDownlink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayConfReq() + conf := pld.GetConfiguration() + if conf == nil { + b = append(b, 0x00, 0x00, 0x00, 0x00, 0x00) + return b, nil + } + var chSettings uint16 + chSettings |= 1 << 13 // StartStop + if conf.CadPeriodicity > 5 { + return nil, errExpectedLowerOrEqual("CADPeriodicity", 5)(conf.CadPeriodicity) + } + chSettings |= uint16(conf.CadPeriodicity&0x7) << 10 + if conf.DefaultChannelIndex > 1 { + return nil, errExpectedLowerOrEqual("DefaultChannelIndex", 1)(conf.DefaultChannelIndex) + } + chSettings |= uint16(conf.DefaultChannelIndex&0x1) << 9 + var secondChFrequency uint64 + if secondCh := conf.SecondChannel; secondCh != nil { + chSettings |= 1 << 7 // SecondChannelIndex + if secondCh.DataRateIndex > 15 { + return nil, errExpectedLowerOrEqual("SecondChannelDataRateIndex", 15)(secondCh.DataRateIndex) + } + chSettings |= uint16(secondCh.DataRateIndex&0xf) << 3 + if secondCh.AckOffset > 5 { + return nil, errExpectedLowerOrEqual("SecondChannelAckOffset", 5)(secondCh.AckOffset) + } + chSettings |= uint16(secondCh.AckOffset & 0x7) + if secondCh.Frequency < 100000 || secondCh.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { + return nil, errExpectedBetween( + "SecondChannelFrequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier, + )(secondCh.Frequency) + } + secondChFrequency = secondCh.Frequency + } + b = byteutil.AppendUint16(b, chSettings, 2) + b = byteutil.AppendUint64(b, secondChFrequency/phy.FreqMultiplier, 3) + return b, nil + }, + UnmarshalDownlink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CONF, + "RelayConfReq", + 5, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + payload := &ttnpb.MACCommand_RelayConfReq_{ + RelayConfReq: &ttnpb.MACCommand_RelayConfReq{}, + } + cmd.Payload = payload + chSettings := byteutil.ParseUint16(b[0:2]) + if chSettings&(1<<13) == 0 { + return nil + } + conf := &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: nil, + DefaultChannelIndex: uint32(chSettings>>9) & 0x1, + CadPeriodicity: ttnpb.RelayCADPeriodicity(chSettings>>10) & 0x7, + } + if chSettings&(1<<7) != 0 { + conf.SecondChannel = &ttnpb.RelaySecondChannel{ + Frequency: byteutil.ParseUint64(b[2:5]) * phy.FreqMultiplier, + AckOffset: ttnpb.RelaySecondChAckOffset(chSettings) & 0x7, + DataRateIndex: ttnpb.DataRateIndex(chSettings>>3) & 0xf, + } + } + payload.RelayConfReq.Configuration = conf + return nil + }, + ), + }, + ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF: &MACCommandDescriptor{ + InitiatedByDevice: false, + + UplinkLength: 1, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayEndDeviceConfAns() + var status byte + if pld.SecondChannelFrequencyAck { + status |= 1 + } + if pld.SecondChannelDataRateIndexAck { + status |= (1 << 1) + } + if pld.SecondChannelIndexAck { + status |= (1 << 2) + } + if pld.BackoffAck { + status |= (1 << 3) + } + b = append(b, status) + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + "RelayEndDeviceConfAns", + 1, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayEndDeviceConfAns_{ + RelayEndDeviceConfAns: &ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: b[0]&1 == 1, + SecondChannelDataRateIndexAck: (b[0]>>1)&1 == 1, + SecondChannelIndexAck: (b[0]>>2)&1 == 1, + BackoffAck: (b[0]>>3)&1 == 1, + }, + } + return nil + }, + ), + + DownlinkLength: 6, + AppendDownlink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayEndDeviceConfReq() + conf := pld.GetConfiguration() + if conf == nil { + b = append(b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + return b, nil + } + var mode byte + switch conf.Mode.(type) { + case *ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always: + mode |= 1 << 2 + case *ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic: + mode |= 2 << 2 + smartEnableLevel := conf.GetDynamic().GetSmartEnableLevel() + if smartEnableLevel > 3 { + return nil, errExpectedLowerOrEqual("SmartEnableLevel", 3)(smartEnableLevel) + } + mode |= byte(conf.GetDynamic().GetSmartEnableLevel() & 0x3) + case *ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled: + mode |= 3 << 2 + default: + return nil, errExpectedLengthLowerOrEqual("mode", 3)(conf.Mode) + } + b = append(b, mode) + var chSettings uint16 + if conf.Backoff > 63 { + return nil, errExpectedLowerOrEqual("Backoff", 63)(conf.Backoff) + } + chSettings |= uint16(conf.Backoff&0x3f) << 9 + var secondChFrequency uint64 + if secondCh := conf.SecondChannel; secondCh != nil { + chSettings |= 1 << 7 // SecondChannelIndex + if secondCh.DataRateIndex > 15 { + return nil, errExpectedLowerOrEqual("SecondChannelDataRateIndex", 15)(secondCh.DataRateIndex) + } + chSettings |= uint16(secondCh.DataRateIndex&0xf) << 3 + if secondCh.Frequency < 100000 || secondCh.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { + return nil, errExpectedBetween( + "SecondChannelFrequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier, + )(secondCh.Frequency) + } + if secondCh.AckOffset > 5 { + return nil, errExpectedLowerOrEqual("SecondChannelAckOffset", 5)(secondCh.AckOffset) + } + chSettings |= uint16(secondCh.AckOffset & 0x7) + secondChFrequency = secondCh.Frequency + } + b = byteutil.AppendUint16(b, chSettings, 2) + b = byteutil.AppendUint64(b, secondChFrequency/phy.FreqMultiplier, 3) + return b, nil + }, + UnmarshalDownlink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + "RelayEndDeviceConfReq", + 6, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + payload := &ttnpb.MACCommand_RelayEndDeviceConfReq_{ + RelayEndDeviceConfReq: &ttnpb.MACCommand_RelayEndDeviceConfReq{}, + } + cmd.Payload = payload + var conf *ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration + switch mode := b[0] >> 2; mode { + case 0: + return nil + case 1: + conf = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{}, + } + case 2: + conf = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic{ + Dynamic: &ttnpb.RelayEndDeviceDynamicMode{ + SmartEnableLevel: ttnpb.RelaySmartEnableLevel(b[0] & 0x3), + }, + }, + } + case 3: + conf = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled{}, + } + default: + return errExpectedLengthLowerOrEqual("mode", 3)(mode) + } + payload.RelayEndDeviceConfReq.Configuration = conf + chSettings := byteutil.ParseUint16(b[1:3]) + conf.Backoff = uint32(chSettings>>9) & 0x3f + if chSettings&(1<<7) != 0 { + conf.SecondChannel = &ttnpb.RelaySecondChannel{ + Frequency: byteutil.ParseUint64(b[3:6]) * phy.FreqMultiplier, + AckOffset: ttnpb.RelaySecondChAckOffset(chSettings) & 0x7, + DataRateIndex: ttnpb.DataRateIndex(chSettings>>3) & 0xf, + } + } + return nil + }), + }, + ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST: &MACCommandDescriptor{ + InitiatedByDevice: false, + + UplinkLength: 0, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + "RelayUpdateUplinkListAns", + 0, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayUpdateUplinkListAns_{ + RelayUpdateUplinkListAns: &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + } + return nil + }, + ), + + DownlinkLength: 26, + AppendDownlink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayUpdateUplinkListReq() + if pld.RuleIndex > 15 { + return nil, errExpectedLowerOrEqual("RuleIndex", 15)(pld.RuleIndex) + } + b = append(b, byte(pld.RuleIndex)) + var uplinkLimit byte = 0x3f + if limits := pld.ForwardLimits; limits != nil { + if limits.BucketSize > 3 { + return nil, errExpectedLowerOrEqual("BucketSize", 3)(limits.BucketSize) + } + uplinkLimit = byte(limits.BucketSize&0x3) << 6 + if limits.ReloadRate > 62 { + return nil, errExpectedLowerOrEqual("ReloadRate", 62)(limits.ReloadRate) + } + uplinkLimit |= byte(limits.ReloadRate) + } + b = append(b, uplinkLimit) + if n := len(pld.DevAddr); n != 4 { + return nil, errExpectedLengthEncodedEqual("DevAddr", 4)(n) + } + devAddr := make([]byte, 4) + copyReverse(devAddr, pld.DevAddr) + b = append(b, devAddr...) + b = byteutil.AppendUint32(b, pld.WFCnt, 4) + if n := len(pld.RootWorSKey); n != 16 { + return nil, errExpectedLengthEncodedEqual("RootWorSKey", 16)(n) + } + b = append(b, pld.RootWorSKey...) + return b, nil + }, + UnmarshalDownlink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + "RelayUpdateUplinkListReq", + 26, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + req := &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + DevAddr: make([]byte, 4), + } + cmd.Payload = &ttnpb.MACCommand_RelayUpdateUplinkListReq_{ + RelayUpdateUplinkListReq: req, + } + req.RuleIndex = uint32(b[0]) + if req.RuleIndex > 7 { + return errExpectedLowerOrEqual("RuleIndex", 7)(req.RuleIndex) + } + uplinkLimit := b[1] + if (uplinkLimit & 0x3f) != 0x3f { + req.ForwardLimits = &ttnpb.RelayUplinkForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize(uplinkLimit >> 6), + ReloadRate: uint32(uplinkLimit & 0x3f), + } + } + copyReverse(req.DevAddr[:], b[2:6]) + req.WFCnt = byteutil.ParseUint32(b[6:10]) + req.RootWorSKey = b[10:26] + return nil + }, + ), + }, + ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST: &MACCommandDescriptor{ + InitiatedByDevice: false, + + UplinkLength: 5, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayCtrlUplinkListAns() + var status byte + if pld.RuleIndexAck { + status |= 1 + } + b = append(b, status) + b = byteutil.AppendUint32(b, pld.WFCnt, 4) + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + "RelayCtrlUplinkListAns", + 5, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayCtrlUplinkListAns_{ + RelayCtrlUplinkListAns: &ttnpb.MACCommand_RelayCtrlUplinkListAns{ + RuleIndexAck: b[0]&1 == 1, + WFCnt: byteutil.ParseUint32(b[1:5]), + }, + } + return nil + }, + ), + + DownlinkLength: 1, + AppendDownlink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + req := cmd.GetRelayCtrlUplinkListReq() + if req.RuleIndex > 15 { + return nil, errExpectedLowerOrEqual("RuleIndex", 7)(req.RuleIndex) + } + var action byte + action |= byte(req.RuleIndex) & 0xf + if req.Action > 1 { + return nil, errExpectedLowerOrEqual("Action", 1)(req.Action) + } + action |= byte(req.Action&0x1) << 4 + b = append(b, action) + return b, nil + }, + UnmarshalDownlink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + "RelayCtrlUplinkListReq", + 1, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayCtrlUplinkListReq_{ + RelayCtrlUplinkListReq: &ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: uint32(b[0] & 0xf), + Action: ttnpb.RelayCtrlUplinkListAction(b[0] >> 4), + }, + } + return nil + }, + ), + }, + ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT: &MACCommandDescriptor{ + InitiatedByDevice: false, + + UplinkLength: 0, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + "RelayConfigureFwdLimitAns", + 0, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + cmd.Payload = &ttnpb.MACCommand_RelayConfigureFwdLimitAns_{ + RelayConfigureFwdLimitAns: &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + } + return nil + }, + ), + + DownlinkLength: 5, + AppendDownlink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayConfigureFwdLimitReq() + if pld.ResetLimitCounter > 3 { + return nil, errExpectedLowerOrEqual("ResetLimitCounter", 3)(pld.ResetLimitCounter) + } + var overallReloadRate byte = 0x7f + var overallBucketSize byte + if overall := pld.OverallLimits; overall != nil { + if overall.ReloadRate > 126 { + return nil, errExpectedLowerOrEqual("ReloadRate", 126)(overall.ReloadRate) + } + overallReloadRate = byte(overall.ReloadRate & 0x7f) + if overall.BucketSize > 3 { + return nil, errExpectedLowerOrEqual("BucketSize", 3)(overall.BucketSize) + } + overallBucketSize = byte(overall.BucketSize & 0x3) + } + var globalUplinkReloadRate byte = 0x7f + var globalUplinkBucketSize byte + if global := pld.GlobalUplinkLimits; global != nil { + if global.ReloadRate > 126 { + return nil, errExpectedLowerOrEqual("ReloadRate", 126)(global.ReloadRate) + } + globalUplinkReloadRate = byte(global.ReloadRate & 0x7f) + if global.BucketSize > 3 { + return nil, errExpectedLowerOrEqual("BucketSize", 3)(global.BucketSize) + } + globalUplinkBucketSize = byte(global.BucketSize & 0x3) + } + var notifyReloadRate byte = 0x7f + var notifyBucketSize byte + if notify := pld.NotifyLimits; notify != nil { + if notify.ReloadRate > 126 { + return nil, errExpectedLowerOrEqual("ReloadRate", 126)(notify.ReloadRate) + } + notifyReloadRate = byte(notify.ReloadRate & 0x7f) + if notify.BucketSize > 3 { + return nil, errExpectedLowerOrEqual("BucketSize", 3)(notify.BucketSize) + } + notifyBucketSize = byte(notify.BucketSize & 0x3) + } + var joinRequestLimits byte = 0x7f + var joinRequestBucketSize byte + if joinReq := pld.JoinRequestLimits; joinReq != nil { + if joinReq.ReloadRate > 126 { + return nil, errExpectedLowerOrEqual("ReloadRate", 126)(joinReq.ReloadRate) + } + joinRequestLimits = byte(joinReq.ReloadRate & 0x7f) + if joinReq.BucketSize > 3 { + return nil, errExpectedLowerOrEqual("BucketSize", 3)(joinReq.BucketSize) + } + joinRequestBucketSize = byte(joinReq.BucketSize & 0x3) + } + var reloadRate uint32 + reloadRate |= uint32(overallReloadRate) + reloadRate |= uint32(globalUplinkReloadRate) << 7 + reloadRate |= uint32(notifyReloadRate) << 14 + reloadRate |= uint32(joinRequestLimits) << 21 + reloadRate |= uint32(pld.ResetLimitCounter&0x3) << 28 + b = byteutil.AppendUint32(b, reloadRate, 4) + var bucketSize byte + bucketSize |= overallBucketSize + bucketSize |= globalUplinkBucketSize << 2 + bucketSize |= notifyBucketSize << 4 + bucketSize |= joinRequestBucketSize << 6 + b = append(b, bucketSize) + return b, nil + }, + UnmarshalDownlink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + "RelayConfigureFwdLimitReq", + 5, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + req := &ttnpb.MACCommand_RelayConfigureFwdLimitReq{} + cmd.Payload = &ttnpb.MACCommand_RelayConfigureFwdLimitReq_{ + RelayConfigureFwdLimitReq: req, + } + bucketSize, reloadRate := b[4], byteutil.ParseUint32(b[0:4]) + req.ResetLimitCounter = ttnpb.RelayResetLimitCounter((reloadRate >> 28) & 0x3) + if reloadRate := reloadRate & 0x7f; reloadRate != 0x7f { + req.OverallLimits = &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize(bucketSize & 0x3), + ReloadRate: reloadRate, + } + } + if reloadRate := (reloadRate >> 7) & 0x7f; reloadRate != 0x7f { + req.GlobalUplinkLimits = &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize((bucketSize >> 2) & 0x3), + ReloadRate: reloadRate, + } + } + if reloadRate := (reloadRate >> 14) & 0x7f; reloadRate != 0x7f { + req.NotifyLimits = &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize((bucketSize >> 4) & 0x3), + ReloadRate: reloadRate, + } + } + if reloadRate := (reloadRate >> 21) & 0x7f; reloadRate != 0x7f { + req.JoinRequestLimits = &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize((bucketSize >> 6) & 0x3), + ReloadRate: reloadRate, + } + } + return nil + }, + ), + }, + ttnpb.MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE: &MACCommandDescriptor{ + InitiatedByDevice: true, + + UplinkLength: 6, + AppendUplink: func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) ([]byte, error) { + pld := cmd.GetRelayNotifyNewEndDeviceReq() + var powerLevel uint16 + if pld.Snr < -20 || pld.Snr > 11 { + return nil, errExpectedBetween("SNR", -20, 11)(pld.Snr) + } + powerLevel |= uint16(pld.Snr+20) & 0x1f + if pld.Rssi < -142 || pld.Rssi > -15 { + return nil, errExpectedBetween("RSSI", -142, -15)(pld.Rssi) + } + powerLevel |= uint16(-pld.Rssi-15) & 0x7f << 5 + b = byteutil.AppendUint16(b, powerLevel, 2) + if n := len(pld.DevAddr); n != 4 { + return nil, errExpectedLengthEncodedEqual("DevAddr", 4)(n) + } + devAddr := make([]byte, 4) + copyReverse(devAddr, pld.DevAddr) + b = append(b, devAddr...) + return b, nil + }, + UnmarshalUplink: newMACUnmarshaler( + ttnpb.MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE, + "RelayNotifyNewEndDeviceReq", + 6, + func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { + req := &ttnpb.MACCommand_RelayNotifyNewEndDeviceReq{} + cmd.Payload = &ttnpb.MACCommand_RelayNotifyNewEndDeviceReq_{ + RelayNotifyNewEndDeviceReq: req, + } + powerLevel := byteutil.ParseUint16(b[0:2]) + req.Snr = int32(powerLevel&0x1f) - 20 + req.Rssi = -int32(powerLevel>>5&0x7f) - 15 + req.DevAddr = make([]byte, 4) + copyReverse(req.DevAddr, b[2:6]) + return nil + }, + ), + }, } var ( diff --git a/pkg/encoding/lorawan/mac_test.go b/pkg/encoding/lorawan/mac_test.go index 4aa93b00fb..189fd73fc9 100644 --- a/pkg/encoding/lorawan/mac_test.go +++ b/pkg/encoding/lorawan/mac_test.go @@ -372,6 +372,234 @@ func TestLoRaWANEncodingMAC(t *testing.T) { []byte{0x20, 0x02}, false, }, + + { + "RelayConfReqDisabled", + &ttnpb.MACCommand_RelayConfReq{}, + []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00}, + false, + }, + { + "RelayConfReqNoSecondCh", + &ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: nil, + DefaultChannelIndex: 0x01, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + []byte{0x40, 0x00, 0x2e, 0x00, 0x00, 0x00}, + false, + }, + { + "RelayConfReqSecondCh", + &ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_200, + Frequency: 868100000, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + }, + DefaultChannelIndex: 0x01, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + []byte{0x40, 0x89, 0x2e, 0x28, 0x76, 0x84}, + false, + }, + { + "RelayConfAns", + &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: false, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: false, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + }, + []byte{0x40, 0x35}, + true, + }, + { + "EndDeviceConfReqDisabled", + &ttnpb.MACCommand_RelayEndDeviceConfReq{}, + []byte{0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + false, + }, + { + "EndDeviceConfReqNoSecondCh", + &ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic{ + Dynamic: &ttnpb.RelayEndDeviceDynamicMode{ + SmartEnableLevel: ttnpb.RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_64, + }, + }, + Backoff: 48, + }, + }, + []byte{0x41, 0x0b, 0x00, 0x60, 0x00, 0x00, 0x00}, + false, + }, + { + "EndDeviceConfReqSecondCh", + &ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled{}, + Backoff: 48, + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_200, + Frequency: 868100000, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + }, + }, + }, + []byte{0x41, 0x0c, 0x89, 0x60, 0x28, 0x76, 0x84}, + false, + }, + { + "EndDeviceConfAns", + &ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: false, + BackoffAck: true, + }, + []byte{0x41, 0x0b}, + true, + }, + { + "UpdateUplinkListReqNoForwardLimits", + &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 1, + DevAddr: []byte{0x41, 0x42, 0x43, 0x44}, + WFCnt: 0x00be00ef, + RootWorSKey: []byte{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + []byte{ + 0x43, // CID + 0x01, // RuleIndex + 0x3f, // No limits + 0x44, 0x43, 0x42, 0x41, // DevAddr + 0xef, 0x00, 0xbe, 0x00, // WFCnt + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // RootWorSKey + }, + false, + }, + { + "UpdateUplinkListReqForwardLimits", + &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 1, + ForwardLimits: &ttnpb.RelayUplinkForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 48, + }, + DevAddr: []byte{0x41, 0x42, 0x43, 0x44}, + WFCnt: 0x00be00ef, + RootWorSKey: []byte{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + }, + }, + []byte{ + 0x43, // CID + 0x01, // RuleIndex + 0x70, // BucketSize = 2, ReloadRate = 48 + 0x44, 0x43, 0x42, 0x41, // DevAddr + 0xef, 0x00, 0xbe, 0x00, // WFCnt + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, // RootWorSKey + }, + false, + }, + { + "UpdateUplinkListAns", + &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + []byte{0x43}, + true, + }, + { + "RelayCtrlUplinkListReqRemoveTrustedEndDevice", + &ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: 2, + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE, + }, + []byte{0x44, 0x12}, + false, + }, + { + "RelayCtrlUplinkListReqReadWFCnt", + &ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: 3, + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT, + }, + []byte{0x44, 0x03}, + false, + }, + { + "RelayCtrlUplinkListAnsAccept", + &ttnpb.MACCommand_RelayCtrlUplinkListAns{ + RuleIndexAck: true, + WFCnt: 0x11223344, + }, + []byte{0x44, 0x01, 0x44, 0x33, 0x22, 0x11}, + true, + }, + { + "RelayCtrlUplinkListAnsReject", + &ttnpb.MACCommand_RelayCtrlUplinkListAns{ + RuleIndexAck: false, + WFCnt: 0, + }, + []byte{0x44, 0x00, 0x00, 0x00, 0x00, 0x00}, + true, + }, + { + "ConfigureFwdLimitReqNoLimits", + &ttnpb.MACCommand_RelayConfigureFwdLimitReq{}, + []byte{0x45, 0xff, 0xff, 0xff, 0x0f, 0x00}, + false, + }, + { + "ConfigureFwdLimitReqLimits", + &ttnpb.MACCommand_RelayConfigureFwdLimitReq{ + ResetLimitCounter: ttnpb.RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_NO_RESET, + JoinRequestLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_1, + ReloadRate: 12, + }, + NotifyLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 23, + }, + GlobalUplinkLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 34, + }, + OverallLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_12, + ReloadRate: 45, + }, + }, + []byte{0x45, 0x2d, 0xd1, 0x85, 0x31, 0x1b}, + false, + }, + { + "ConfigureFwdLimitAns", + &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + []byte{0x45}, + true, + }, + { + "NotifyNewEndDeviceReq", + &ttnpb.MACCommand_RelayNotifyNewEndDeviceReq{ + DevAddr: []byte{0x41, 0x42, 0x43, 0x44}, + Snr: 6, + Rssi: -64, + }, + []byte{0x46, 0x3a, 0x06, 0x44, 0x43, 0x42, 0x41}, + true, + }, } { t.Run(tc.Name, func(t *testing.T) { a := assertions.New(t) diff --git a/pkg/encoding/lorawan/relay.go b/pkg/encoding/lorawan/relay.go new file mode 100644 index 0000000000..b6620652dd --- /dev/null +++ b/pkg/encoding/lorawan/relay.go @@ -0,0 +1,91 @@ +// Copyright © 2023 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 lorawan + +import ( + "go.thethings.network/lorawan-stack/v3/pkg/band" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/util/byteutil" +) + +// MarshalRelayForwardDownlinkReq marshals a RelayForwardDownlinkReq. +func MarshalRelayForwardDownlinkReq(req *ttnpb.RelayForwardDownlinkReq) ([]byte, error) { + if len(req.RawPayload) == 0 { + return nil, errMissing("RawPayload") + } + return req.RawPayload, nil +} + +// UnmarshalRelayForwardDownlinkReq unmarshals b into req. +func UnmarshalRelayForwardDownlinkReq(b []byte, req *ttnpb.RelayForwardDownlinkReq) error { + if len(b) == 0 { + return errMissing("RawPayload") + } + req.RawPayload = b + return nil +} + +// MarshalRelayForwardUplinkReq marshals a RelayForwardUplinkReq. +func MarshalRelayForwardUplinkReq(phy *band.Band, req *ttnpb.RelayForwardUplinkReq) ([]byte, error) { + if len(req.RawPayload) == 0 { + return nil, errMissing("RawPayload") + } + var uplinkMetadata uint32 + if req.WorChannel > 1 { + return nil, errExpectedLowerOrEqual("WORChannel", 1)(req.WorChannel) + } + uplinkMetadata |= uint32(req.WorChannel&0x3) << 16 + if req.Rssi < -142 || req.Rssi > -15 { + return nil, errExpectedBetween("RSSI", -142, -15)(req.Rssi) + } + uplinkMetadata |= uint32(-(req.Rssi+15)&0x7f) << 9 + if req.Snr < -20 || req.Snr > 11 { + return nil, errExpectedBetween("SNR", -20, 11)(req.Snr) + } + uplinkMetadata |= uint32((req.Snr+20)&0x1f) << 4 + drIdx, _, found := phy.FindUplinkDataRate(req.DataRate) + if !found { + return nil, errMissing("DataRate") + } + uplinkMetadata |= uint32(drIdx & 0xf) + b := make([]byte, 0, 6+len(req.RawPayload)) + b = byteutil.AppendUint32(b, uplinkMetadata, 3) + b = byteutil.AppendUint64(b, req.Frequency/phy.FreqMultiplier, 3) + if n := len(req.RawPayload); n == 0 { + return nil, errExpectedLengthHigherOrEqual("RawPayload", 1)(n) + } + b = append(b, req.RawPayload...) + return b, nil +} + +// UnmarshalRelayForwardUplinkReq unmarshals b into req. +func UnmarshalRelayForwardUplinkReq(phy *band.Band, b []byte, req *ttnpb.RelayForwardUplinkReq) error { + if n := len(b); n < 6 { + return errExpectedLengthHigherOrEqual("RawPayload", 6)(n) + } + uplinkMetadata := byteutil.ParseUint32(b[:3]) + req.WorChannel = ttnpb.RelayWORChannel(uplinkMetadata>>16) & 0x3 + req.Rssi = -int32(uplinkMetadata>>9&0x7f) - 15 + req.Snr = int32(uplinkMetadata>>4&0x1f) - 20 + drIdx := ttnpb.DataRateIndex(uplinkMetadata & 0xf) + dataRate, ok := phy.DataRates[drIdx] + if !ok { + return errMissing("DataRate") + } + req.DataRate = dataRate.Rate + req.Frequency = byteutil.ParseUint64(b[3:6]) * phy.FreqMultiplier + req.RawPayload = b[6:] + return nil +} diff --git a/pkg/encoding/lorawan/relay_test.go b/pkg/encoding/lorawan/relay_test.go new file mode 100644 index 0000000000..ce9af13ced --- /dev/null +++ b/pkg/encoding/lorawan/relay_test.go @@ -0,0 +1,148 @@ +// Copyright © 2023 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 lorawan_test + +import ( + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/band" + "go.thethings.network/lorawan-stack/v3/pkg/encoding/lorawan" + "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/assertions/should" +) + +func TestMarshalRelayForwardDownlinkReq(t *testing.T) { + t.Parallel() + + a := assertions.New(t) + + _, err := lorawan.MarshalRelayForwardDownlinkReq(&ttnpb.RelayForwardDownlinkReq{}) + a.So(err, should.NotBeNil) + + b, err := lorawan.MarshalRelayForwardDownlinkReq(&ttnpb.RelayForwardDownlinkReq{ + RawPayload: []byte{0x01, 0x02, 0x03}, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte{0x01, 0x02, 0x03}) + } +} + +func TestUnmarshalRelayForwardDownlinkReq(t *testing.T) { + t.Parallel() + + a := assertions.New(t) + + err := lorawan.UnmarshalRelayForwardDownlinkReq(nil, &ttnpb.RelayForwardDownlinkReq{}) + a.So(err, should.NotBeNil) + + var req ttnpb.RelayForwardDownlinkReq + err = lorawan.UnmarshalRelayForwardDownlinkReq([]byte{0x01, 0x02, 0x03}, &req) + if a.So(err, should.BeNil) { + a.So(req.RawPayload, should.Resemble, []byte{0x01, 0x02, 0x03}) + } +} + +func TestMarshalRelayForwardUplinkReq(t *testing.T) { + t.Parallel() + + a, phy := assertions.New(t), &band.EU_863_870_RP2_V1_0_4 + for _, tc := range []struct { + Name string + Request *ttnpb.RelayForwardUplinkReq + }{ + { + Name: "InvalidWORChannel", + Request: &ttnpb.RelayForwardUplinkReq{ + WorChannel: 2, + }, + }, + { + Name: "InvalidRSSI", + Request: &ttnpb.RelayForwardUplinkReq{ + WorChannel: ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT, + Rssi: -143, + }, + }, + { + Name: "InvalidSNR", + Request: &ttnpb.RelayForwardUplinkReq{ + WorChannel: ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT, + Rssi: -64, + Snr: -21, + }, + }, + { + Name: "InvalidDataRateIndex", + Request: &ttnpb.RelayForwardUplinkReq{ + WorChannel: ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT, + Rssi: -64, + Snr: 5, + DataRate: &ttnpb.DataRate{}, + }, + }, + { + Name: "InvalidRawPayload", + Request: &ttnpb.RelayForwardUplinkReq{ + WorChannel: ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT, + Rssi: -64, + Snr: 5, + DataRate: phy.DataRates[ttnpb.DataRateIndex_DATA_RATE_1].Rate, + }, + }, + } { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + + a := assertions.New(t) + _, err := lorawan.MarshalRelayForwardUplinkReq(phy, tc.Request) + a.So(errors.IsInvalidArgument(err), should.BeTrue) + }) + } + + b, err := lorawan.MarshalRelayForwardUplinkReq(phy, &ttnpb.RelayForwardUplinkReq{ + WorChannel: ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_SECONDARY, + Rssi: -64, + Snr: 5, + DataRate: phy.DataRates[ttnpb.DataRateIndex_DATA_RATE_1].Rate, + Frequency: 868100000, + RawPayload: []byte{0x01, 0x02, 0x03}, + }) + if a.So(err, should.BeNil) { + a.So(b, should.Resemble, []byte{0x91, 0x63, 0x01, 0x28, 0x76, 0x84, 0x01, 0x02, 0x03}) + } +} + +func TestUnmarshalRelayForwardUplinkReq(t *testing.T) { + t.Parallel() + + a, phy := assertions.New(t), &band.EU_863_870_RP2_V1_0_4 + + err := lorawan.UnmarshalRelayForwardUplinkReq(phy, nil, &ttnpb.RelayForwardUplinkReq{}) + a.So(err, should.NotBeNil) + + var req ttnpb.RelayForwardUplinkReq + err = lorawan.UnmarshalRelayForwardUplinkReq(phy, []byte{0x91, 0x63, 0x01, 0x28, 0x76, 0x84, 0x01, 0x02, 0x03}, &req) + if a.So(err, should.BeNil) { + a.So(req.WorChannel, should.Equal, ttnpb.RelayWORChannel_RELAY_WOR_CHANNEL_SECONDARY) + a.So(req.Rssi, should.Equal, -64) + a.So(req.Snr, should.Equal, 5) + a.So(req.DataRate, should.Resemble, phy.DataRates[ttnpb.DataRateIndex_DATA_RATE_1].Rate) + a.So(req.Frequency, should.Equal, 868100000) + a.So(req.RawPayload, should.Resemble, []byte{0x01, 0x02, 0x03}) + } +} diff --git a/pkg/events/batch/batch.go b/pkg/events/batch/batch.go index 86ed535a6c..dbbabf7abb 100644 --- a/pkg/events/batch/batch.go +++ b/pkg/events/batch/batch.go @@ -41,7 +41,7 @@ func (bp *batchPublisher) process(ctx context.Context) error { flushed := false for n := len(batch); n >= lowerBound; n = len(batch) { toFlush := n - if upperBound := 2 * lowerBound; n > upperBound { + if upperBound := 2 * bp.targetSize; n > upperBound { toFlush = upperBound } select { diff --git a/pkg/events/grpc/grpc.go b/pkg/events/grpc/grpc.go index 0de69e6009..be250151c4 100644 --- a/pkg/events/grpc/grpc.go +++ b/pkg/events/grpc/grpc.go @@ -19,9 +19,6 @@ package grpc import ( "context" "os" - "regexp" - "sort" - "strings" "time" grpc_runtime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" @@ -65,58 +62,6 @@ type EventsServer struct { definedNames map[string]struct{} } -var ( - errInvalidRegexp = errors.DefineInvalidArgument("invalid_regexp", "invalid regexp") - errNoMatchingEvents = errors.DefineInvalidArgument("no_matching_events", "no matching events for regexp `{regexp}`") - errUnknownEventName = errors.DefineInvalidArgument("unknown_event_name", "unknown event `{name}`") -) - -func (srv *EventsServer) processNames(names ...string) ([]string, error) { - if len(names) == 0 { - return nil, nil - } - nameMap := make(map[string]struct{}) - for _, name := range names { - if strings.HasPrefix(name, "/") && strings.HasSuffix(name, "/") { - re, err := regexp.Compile(strings.Trim(name, "/")) - if err != nil { - return nil, errInvalidRegexp.WithCause(err) - } - var found bool - for defined := range srv.definedNames { - if re.MatchString(defined) { - nameMap[defined] = struct{}{} - found = true - } - } - if !found { - return nil, errNoMatchingEvents.WithAttributes("regexp", re.String()) - } - } else { - var found bool - for defined := range srv.definedNames { - if name == defined { - nameMap[name] = struct{}{} - found = true - break - } - } - if !found { - return nil, errUnknownEventName.WithAttributes("name", name) - } - } - } - if len(nameMap) == 0 { - return nil, nil - } - out := make([]string, 0, len(nameMap)) - for name := range nameMap { - out = append(out, name) - } - sort.Strings(out) - return out, nil -} - var errNoIdentifiers = errors.DefineInvalidArgument("no_identifiers", "no identifiers") // Stream implements the EventsServer interface. @@ -125,7 +70,7 @@ func (srv *EventsServer) Stream(req *ttnpb.StreamEventsRequest, stream ttnpb.Eve return errNoIdentifiers.New() } - names, err := srv.processNames(req.Names...) + names, err := events.NamesFromPatterns(srv.definedNames, req.Names) if err != nil { return err } diff --git a/pkg/events/pattern.go b/pkg/events/pattern.go new file mode 100644 index 0000000000..bb3d5389c3 --- /dev/null +++ b/pkg/events/pattern.go @@ -0,0 +1,77 @@ +// Copyright © 2023 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 events + +import ( + "regexp" + "sort" + "strings" + + "go.thethings.network/lorawan-stack/v3/pkg/errors" +) + +var ( + errInvalidRegexp = errors.DefineInvalidArgument("invalid_regexp", "invalid regexp") + errNoMatchingEvents = errors.DefineInvalidArgument("no_matching_events", "no matching events for regexp `{regexp}`") + errUnknownEventName = errors.DefineInvalidArgument("unknown_event_name", "unknown event `{name}`") +) + +// NamesFromPatterns returns the event names which match the given patterns. +// The defined names are a set of event names which are used to match the patterns. +func NamesFromPatterns(definedNames map[string]struct{}, patterns []string) ([]string, error) { + if len(patterns) == 0 { + return nil, nil + } + nameMap := make(map[string]struct{}) + for _, name := range patterns { + if strings.HasPrefix(name, "/") && strings.HasSuffix(name, "/") { + re, err := regexp.Compile(strings.Trim(name, "/")) + if err != nil { + return nil, errInvalidRegexp.WithCause(err) + } + var found bool + for defined := range definedNames { + if re.MatchString(defined) { + nameMap[defined] = struct{}{} + found = true + } + } + if !found { + return nil, errNoMatchingEvents.WithAttributes("regexp", re.String()) + } + } else { + var found bool + for defined := range definedNames { + if name == defined { + nameMap[name] = struct{}{} + found = true + break + } + } + if !found { + return nil, errUnknownEventName.WithAttributes("name", name) + } + } + } + if len(nameMap) == 0 { + return nil, nil + } + out := make([]string, 0, len(nameMap)) + for name := range nameMap { + out = append(out, name) + } + sort.Strings(out) + return out, nil +} diff --git a/pkg/events/redis/store.go b/pkg/events/redis/store.go index abf59ae03d..3421ab4002 100644 --- a/pkg/events/redis/store.go +++ b/pkg/events/redis/store.go @@ -20,6 +20,7 @@ import ( "errors" "hash/fnv" "math/rand" + "slices" "strconv" "strings" "sync" @@ -34,7 +35,6 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/task" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" - "golang.org/x/exp/slices" ) const ttlJitter = 0.01 diff --git a/pkg/experimental/experimental_test.go b/pkg/experimental/experimental_test.go index ed18f25be3..5af0a94ced 100644 --- a/pkg/experimental/experimental_test.go +++ b/pkg/experimental/experimental_test.go @@ -24,6 +24,8 @@ import ( ) func TestExperimentalFeatures(t *testing.T) { + t.Parallel() + a := assertions.New(t) r := NewRegistry() @@ -32,21 +34,21 @@ func TestExperimentalFeatures(t *testing.T) { feature := DefineFeature("experimental.feature", false) a.So(feature.GetValue(ctx), should.BeFalse) - a.So(AllFeatures(ctx), should.Resemble, map[string]bool{"experimental.feature": false}) + a.So(AllFeatures(ctx)["experimental.feature"], should.BeFalse) a.So(feature.GetValue(context.Background()), should.BeFalse) - a.So(AllFeatures(context.Background()), should.Resemble, map[string]bool{"experimental.feature": false}) + a.So(AllFeatures(context.Background())["experimental.feature"], should.BeFalse) r.EnableFeatures("experimental.feature") a.So(feature.GetValue(ctx), should.BeTrue) - a.So(AllFeatures(ctx), should.Resemble, map[string]bool{"experimental.feature": true}) + a.So(AllFeatures(ctx)["experimental.feature"], should.BeTrue) a.So(feature.GetValue(context.Background()), should.BeFalse) - a.So(AllFeatures(context.Background()), should.Resemble, map[string]bool{"experimental.feature": false}) + a.So(AllFeatures(context.Background())["experimental.feature"], should.BeFalse) EnableFeatures("experimental.feature") r.DisableFeatures("experimental.feature") a.So(feature.GetValue(ctx), should.BeFalse) - a.So(AllFeatures(ctx), should.Resemble, map[string]bool{"experimental.feature": false}) + a.So(AllFeatures(ctx)["experimental.feature"], should.BeFalse) a.So(feature.GetValue(context.Background()), should.BeTrue) - a.So(AllFeatures(context.Background()), should.Resemble, map[string]bool{"experimental.feature": true}) + a.So(AllFeatures(context.Background())["experimental.feature"], should.BeTrue) } diff --git a/pkg/fetch/basepath_test.go b/pkg/fetch/basepath_test.go index 6ccd67a8de..a660f1fa3a 100644 --- a/pkg/fetch/basepath_test.go +++ b/pkg/fetch/basepath_test.go @@ -15,12 +15,12 @@ package fetch_test import ( + "slices" "testing" "github.com/smarty/assertions" "go.thethings.network/lorawan-stack/v3/pkg/fetch" "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" - "golang.org/x/exp/slices" ) type MockInterface struct { diff --git a/pkg/frequencyplans/frequencyplans.go b/pkg/frequencyplans/frequencyplans.go index 41e42b0222..647de475ad 100644 --- a/pkg/frequencyplans/frequencyplans.go +++ b/pkg/frequencyplans/frequencyplans.go @@ -519,6 +519,8 @@ type FrequencyPlanDescription struct { ID string `yaml:"id"` // BaseID is the ID of the base frequency plan that this frequency plan extends (optional). BaseID string `yaml:"base-id,omitempty"` + // BandID is the ID of the band that this frequency plan uses. + BandID string `yaml:"band-id,omitempty"` // Name is a human readable name of the frequency plan. Name string `yaml:"name"` // BaseFrequency is the base frequency of the frequency plan (i.e. 868, 915) diff --git a/pkg/frequencyplans/rpc.go b/pkg/frequencyplans/rpc.go index 9349a4676f..ee1766e44f 100644 --- a/pkg/frequencyplans/rpc.go +++ b/pkg/frequencyplans/rpc.go @@ -39,8 +39,12 @@ func (s *RPCServer) ListFrequencyPlans(ctx context.Context, req *ttnpb.ListFrequ if req.BaseFrequency != 0 && uint16(req.BaseFrequency) != desc.BaseFrequency { continue } + if req.BandId != "" && req.BandId != desc.BandID { + continue + } res.FrequencyPlans = append(res.FrequencyPlans, &ttnpb.FrequencyPlanDescription{ Id: desc.ID, + BandId: desc.BandID, BaseId: desc.BaseID, Name: desc.Name, BaseFrequency: uint32(desc.BaseFrequency), diff --git a/pkg/frequencyplans/rpc_test.go b/pkg/frequencyplans/rpc_test.go index 2d645dfcd9..47bd61ef1f 100644 --- a/pkg/frequencyplans/rpc_test.go +++ b/pkg/frequencyplans/rpc_test.go @@ -26,18 +26,22 @@ import ( ) func TestRPCServer(t *testing.T) { + t.Parallel() a := assertions.New(t) store := frequencyplans.NewStore(fetch.NewMemFetcher(map[string][]byte{ "frequency-plans.yml": []byte(`- id: A + band-id: EU_863_870 description: Frequency Plan A base-frequency: 868 file: A.yml - id: B + band-id: AS_923 base-id: A description: Frequency Plan B file: B.yml - id: C + band-id: US_902_928 description: Frequency Plan C base-frequency: 915 file: C.yml`), @@ -45,13 +49,41 @@ func TestRPCServer(t *testing.T) { server := frequencyplans.NewRPCServer(store) - all, err := server.ListFrequencyPlans(context.Background(), &ttnpb.ListFrequencyPlansRequest{}) + expectedAll := []*ttnpb.FrequencyPlanDescription{ + { + Id: "A", + BandId: "EU_863_870", + BaseFrequency: 868, + }, + { + Id: "B", + BaseId: "A", + BaseFrequency: 868, + BandId: "AS_923", + }, + { + Id: "C", + BaseFrequency: 915, + BandId: "US_902_928", + }, + } + + actualAll, err := server.ListFrequencyPlans(context.Background(), &ttnpb.ListFrequencyPlansRequest{}) a.So(err, should.BeNil) - a.So(all.FrequencyPlans, should.HaveLength, 3) + a.So(actualAll.FrequencyPlans, should.HaveLength, 3) + a.So(actualAll.FrequencyPlans[0], should.Resemble, expectedAll[0]) base915, err := server.ListFrequencyPlans(context.Background(), &ttnpb.ListFrequencyPlansRequest{ BaseFrequency: 868, }) a.So(err, should.BeNil) a.So(base915.FrequencyPlans, should.HaveLength, 2) + a.So(base915.FrequencyPlans, should.Resemble, expectedAll[:2]) + + bandAS, err := server.ListFrequencyPlans(context.Background(), &ttnpb.ListFrequencyPlansRequest{ + BandId: "AS_923", + }) + a.So(err, should.BeNil) + a.So(bandAS.FrequencyPlans, should.HaveLength, 1) + a.So(bandAS.FrequencyPlans[0], should.Resemble, expectedAll[1]) } diff --git a/pkg/gatewayconfigurationserver/http.go b/pkg/gatewayconfigurationserver/http.go index d5578d8c97..3912548da6 100644 --- a/pkg/gatewayconfigurationserver/http.go +++ b/pkg/gatewayconfigurationserver/http.go @@ -38,8 +38,8 @@ func (s *Server) RegisterRoutes(server *web.Server) { router := server.Prefix(ttnpb.HTTPAPIPrefix + "/gcs/gateways/{gateway_id}/").Subrouter() router.Use( mux.MiddlewareFunc(webmiddleware.Namespace("gatewayconfigurationserver")), - ratelimit.HTTPMiddleware(s.Component.RateLimiter(), "http:gcs"), mux.MiddlewareFunc(webmiddleware.Metadata("Authorization")), + ratelimit.HTTPMiddleware(s.Component.RateLimiter(), "http:gcs"), validateAndFillIDs, ) if s.config.RequireAuth { diff --git a/pkg/gatewayconfigurationserver/v2/server.go b/pkg/gatewayconfigurationserver/v2/server.go index c7b5bb66f2..87acf0f9d7 100644 --- a/pkg/gatewayconfigurationserver/v2/server.go +++ b/pkg/gatewayconfigurationserver/v2/server.go @@ -84,9 +84,9 @@ func (s *Server) RegisterRoutes(server *web.Server) { middleware := []webmiddleware.MiddlewareFunc{ webmiddleware.Namespace("gatewayconfigurationserver/v2"), - ratelimit.HTTPMiddleware(s.component.RateLimiter(), "http:gcs"), rewriteAuthorization, webmiddleware.Metadata("Authorization"), + ratelimit.HTTPMiddleware(s.component.RateLimiter(), "http:gcs"), } router.Handle( diff --git a/pkg/gatewayserver/gatewayserver.go b/pkg/gatewayserver/gatewayserver.go index 450bf831c5..804cef400f 100644 --- a/pkg/gatewayserver/gatewayserver.go +++ b/pkg/gatewayserver/gatewayserver.go @@ -450,6 +450,11 @@ type connectionEntry struct { tasksDone *sync.WaitGroup } +// AssertGatewayRights checks that the caller has the required rights over the provided gateway identifiers. +func (gs *GatewayServer) AssertGatewayRights(ctx context.Context, ids *ttnpb.GatewayIdentifiers, rights ...ttnpb.Right) error { + return gs.entityRegistry.AssertGatewayRights(ctx, ids, rights...) +} + // Connect connects a gateway by its identifiers to the Gateway Server, and returns a io.Connection for traffic and // control. func (gs *GatewayServer) Connect( @@ -459,7 +464,7 @@ func (gs *GatewayServer) Connect( addr *ttnpb.GatewayRemoteAddress, opts ...io.ConnectionOption, ) (*io.Connection, error) { - if err := gs.entityRegistry.AssertGatewayRights(ctx, ids, ttnpb.Right_RIGHT_GATEWAY_LINK); err != nil { + if err := gs.AssertGatewayRights(ctx, ids, ttnpb.Right_RIGHT_GATEWAY_LINK); err != nil { return nil, err } @@ -486,6 +491,7 @@ func (gs *GatewayServer) Connect( "enforce_duty_cycle", "frequency_plan_id", "frequency_plan_ids", + "gateway_server_address", "location_public", "require_authenticated_connection", "schedule_anytime_delay", @@ -611,7 +617,8 @@ func requireDisconnect(connected, current *ttnpb.Gateway) bool { connected.StatusPublic != current.StatusPublic || connected.UpdateLocationFromStatus != current.UpdateLocationFromStatus || connected.FrequencyPlanId != current.FrequencyPlanId || - len(connected.FrequencyPlanIds) != len(current.FrequencyPlanIds) { + len(connected.FrequencyPlanIds) != len(current.FrequencyPlanIds) || + connected.GatewayServerAddress != current.GatewayServerAddress { return true } for i := range connected.FrequencyPlanIds { @@ -646,6 +653,7 @@ func (gs *GatewayServer) startDisconnectOnChangeTask(conn connectionEntry) { "enforce_duty_cycle", "frequency_plan_id", "frequency_plan_ids", + "gateway_server_address", "location_public", "require_authenticated_connection", "schedule_anytime_delay", diff --git a/pkg/gatewayserver/io/io.go b/pkg/gatewayserver/io/io.go index 276a40291e..3659ba02c4 100644 --- a/pkg/gatewayserver/io/io.go +++ b/pkg/gatewayserver/io/io.go @@ -60,8 +60,11 @@ type Server interface { GetBaseConfig(ctx context.Context) config.ServiceBase // FillGatewayContext fills the given context and identifiers. // This method should only be used for request contexts. - FillGatewayContext(ctx context.Context, - ids *ttnpb.GatewayIdentifiers) (context.Context, *ttnpb.GatewayIdentifiers, error) + FillGatewayContext( + ctx context.Context, ids *ttnpb.GatewayIdentifiers, + ) (context.Context, *ttnpb.GatewayIdentifiers, error) + // AssertGatewayRights checks that the caller has the required rights over the provided gateway identifiers. + AssertGatewayRights(ctx context.Context, ids *ttnpb.GatewayIdentifiers, required ...ttnpb.Right) error // Connect connects a gateway by its identifiers to the Gateway Server, and returns a Connection for traffic and // control. Connect( @@ -109,7 +112,7 @@ type Connection struct { frontend Frontend gateway *ttnpb.Gateway gatewayPrimaryFP *frequencyplans.FrequencyPlan - gatewayFPs map[string]*frequencyplans.FrequencyPlan + gatewayFPs []*frequencyplans.FrequencyPlan band *band.Band fps *frequencyplans.Store scheduler *scheduling.Scheduler @@ -178,13 +181,17 @@ func NewConnection( opt(connectionOptions) } - gatewayFPs := make(map[string]*frequencyplans.FrequencyPlan, len(gateway.FrequencyPlanIds)) + gatewayFPLen := len(gateway.FrequencyPlanIds) + if gatewayFPLen == 0 { + gatewayFPLen = 1 + } + gatewayFPs := make([]*frequencyplans.FrequencyPlan, gatewayFPLen) fp0ID := gateway.FrequencyPlanId fp0, err := fps.GetByID(fp0ID) if err != nil { return nil, err } - gatewayFPs[fp0ID] = fp0 + gatewayFPs[0] = fp0 phy, err := band.GetLatest(fp0.BandID) if err != nil { return nil, err @@ -202,7 +209,7 @@ func NewConnection( if fpn.BandID != fp0.BandID { return nil, errFrequencyPlansNotFromSameBand.New() } - gatewayFPs[gateway.FrequencyPlanIds[i]] = fpn + gatewayFPs[i] = fpn } } @@ -530,16 +537,13 @@ func (c *Connection) ScheduleDown(path *ttnpb.DownlinkPath, msg *ttnpb.DownlinkM var fp *frequencyplans.FrequencyPlan fpID := request.GetFrequencyPlanId() if fpID != "" { - fp = c.gatewayFPs[fpID] - if fp == nil { - // The requested frequency plan is not configured for the gateway. Load the plan and enforce that it's in the same band. - fp, err = c.fps.GetByID(fpID) - if err != nil { - return false, false, 0, errFrequencyPlanNotConfigured.WithCause(err).WithAttributes("id", request.FrequencyPlanId) - } - if fp.BandID != c.band.ID { - return false, false, 0, errFrequencyPlansNotFromSameBand.New() - } + // Load the plan and enforce that it's in the same band. + fp, err = c.fps.GetByID(fpID) + if err != nil { + return false, false, 0, errFrequencyPlanNotConfigured.WithCause(err).WithAttributes("id", request.FrequencyPlanId) + } + if fp.BandID != c.band.ID { + return false, false, 0, errFrequencyPlansNotFromSameBand.New() } } else { // Backwards compatibility. If there's no FrequencyPlanID in the TxRequest, then there must be only one Frequency @@ -863,7 +867,7 @@ func (c *Connection) Stats() (*ttnpb.GatewayConnectionStats, []string) { } // FrequencyPlans returns the frequency plans for the gateway. -func (c *Connection) FrequencyPlans() map[string]*frequencyplans.FrequencyPlan { return c.gatewayFPs } +func (c *Connection) FrequencyPlans() []*frequencyplans.FrequencyPlan { return c.gatewayFPs } // PrimaryFrequencyPlan returns the primary frequency plan of the gateway. func (c *Connection) PrimaryFrequencyPlan() *frequencyplans.FrequencyPlan { return c.gatewayPrimaryFP } diff --git a/pkg/gatewayserver/io/mock/server.go b/pkg/gatewayserver/io/mock/server.go index 083d05ff09..080e1da0cc 100644 --- a/pkg/gatewayserver/io/mock/server.go +++ b/pkg/gatewayserver/io/mock/server.go @@ -76,6 +76,11 @@ func (s *server) FillGatewayContext(ctx context.Context, ids *ttnpb.GatewayIdent return ctx, ids, nil } +// AssertRights implements io.Server. +func (*server) AssertGatewayRights(ctx context.Context, ids *ttnpb.GatewayIdentifiers, required ...ttnpb.Right) error { + return rights.RequireGateway(ctx, ids, required...) +} + // Connect implements io.Server. func (s *server) Connect( ctx context.Context, @@ -84,7 +89,7 @@ func (s *server) Connect( addr *ttnpb.GatewayRemoteAddress, opts ...io.ConnectionOption, ) (*io.Connection, error) { - if err := rights.RequireGateway(ctx, ids, ttnpb.Right_RIGHT_GATEWAY_LINK); err != nil { + if err := s.AssertGatewayRights(ctx, ids, ttnpb.Right_RIGHT_GATEWAY_LINK); err != nil { return nil, err } gtw, err := s.identityStore.GatewayRegistry().Get(ctx, &ttnpb.GetGatewayRequest{GatewayIds: ids}) diff --git a/pkg/gatewayserver/io/udp/udp.go b/pkg/gatewayserver/io/udp/udp.go index e394520dfb..45a0c003f2 100644 --- a/pkg/gatewayserver/io/udp/udp.go +++ b/pkg/gatewayserver/io/udp/udp.go @@ -18,6 +18,7 @@ import ( "context" "encoding/binary" "net" + "slices" "sync" "sync/atomic" "time" @@ -34,7 +35,6 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/types" "go.thethings.network/lorawan-stack/v3/pkg/unique" "go.thethings.network/lorawan-stack/v3/pkg/workerpool" - "golang.org/x/exp/slices" "google.golang.org/protobuf/types/known/timestamppb" ) diff --git a/pkg/gatewayserver/io/ws/format.go b/pkg/gatewayserver/io/ws/format.go index 34ba32ddc2..d8c59a9162 100644 --- a/pkg/gatewayserver/io/ws/format.go +++ b/pkg/gatewayserver/io/ws/format.go @@ -41,12 +41,22 @@ type Formatter interface { Endpoints() Endpoints // HandleConnectionInfo handles connection information requests from web socket based protocols. // This function returns a byte stream that contains connection information (ex: scheme, host, port etc) or an error if applicable. - HandleConnectionInfo(ctx context.Context, raw []byte, server io.Server, serverInfo ServerInfo, receivedAt time.Time) []byte + HandleConnectionInfo( + ctx context.Context, + raw []byte, + server io.Server, + serverInfo ServerInfo, + assertAuth func(context.Context, *ttnpb.GatewayIdentifiers) error, + ) []byte // HandleUp handles upstream messages from web socket based gateways. // This function optionally returns a byte stream to be sent as response to the upstream message. - HandleUp(ctx context.Context, raw []byte, ids *ttnpb.GatewayIdentifiers, conn *io.Connection, receivedAt time.Time) ([]byte, error) + HandleUp( + ctx context.Context, raw []byte, ids *ttnpb.GatewayIdentifiers, conn *io.Connection, receivedAt time.Time, + ) ([]byte, error) // FromDownlink generates a downlink byte stream that can be sent over the WS connection. FromDownlink(ctx context.Context, down *ttnpb.DownlinkMessage, bandID string, dlTime time.Time) ([]byte, error) // TransferTime generates a spurious time transfer message for a particular server time. - TransferTime(ctx context.Context, serverTime time.Time, gpsTime *time.Time, concentratorTime *scheduling.ConcentratorTime) ([]byte, error) + TransferTime( + ctx context.Context, serverTime time.Time, gpsTime *time.Time, concentratorTime *scheduling.ConcentratorTime, + ) ([]byte, error) } diff --git a/pkg/gatewayserver/io/ws/lbslns/discover.go b/pkg/gatewayserver/io/ws/lbslns/discover.go index c2601930dc..5400eea70c 100644 --- a/pkg/gatewayserver/io/ws/lbslns/discover.go +++ b/pkg/gatewayserver/io/ws/lbslns/discover.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "fmt" - "time" "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/gatewayserver/io" @@ -32,7 +31,13 @@ import ( var errEmptyGatewayEUI = errors.DefineFailedPrecondition("empty_gateway_eui", "empty gateway EUI") // HandleConnectionInfo implements Formatter. -func (f *lbsLNS) HandleConnectionInfo(ctx context.Context, raw []byte, server io.Server, info ws.ServerInfo, receivedAt time.Time) []byte { +func (f *lbsLNS) HandleConnectionInfo( + ctx context.Context, + raw []byte, + server io.Server, + info ws.ServerInfo, + assertAuth func(ctx context.Context, ids *ttnpb.GatewayIdentifiers) error, +) []byte { var req DiscoverQuery if err := json.Unmarshal(raw, &req); err != nil { @@ -52,6 +57,10 @@ func (f *lbsLNS) HandleConnectionInfo(ctx context.Context, raw []byte, server io } ctx = filledCtx + if err := assertAuth(ctx, ids); err != nil { + return logAndWrapDiscoverError(ctx, err, fmt.Sprintf("Unauthorized")) + } + euiWithPrefix := fmt.Sprintf("eui-%s", types.MustEUI64(ids.Eui).OrZero().String()) res := DiscoverResponse{ EUI: req.EUI, diff --git a/pkg/gatewayserver/io/ws/lbslns/discover_test.go b/pkg/gatewayserver/io/ws/lbslns/discover_test.go index 12c3f6a27b..bc7e4c998b 100644 --- a/pkg/gatewayserver/io/ws/lbslns/discover_test.go +++ b/pkg/gatewayserver/io/ws/lbslns/discover_test.go @@ -18,7 +18,6 @@ import ( "context" "encoding/json" "testing" - "time" "github.com/smarty/assertions" "go.thethings.network/lorawan-stack/v3/pkg/gatewayserver/io/ws" @@ -69,9 +68,11 @@ func TestDiscover(t *testing.T) { t.Run(tc.Name, func(t *testing.T) { msg, err := json.Marshal(tc.Query) a.So(err, should.BeNil) - resp := lbsLNS.HandleConnectionInfo(ctx, msg, mockServer, info, time.Now()) + resp := lbsLNS.HandleConnectionInfo(ctx, msg, mockServer, info, noopAssertRights) expected, _ := json.Marshal(tc.ExpectedResponse) a.So(string(resp), should.Equal, string(expected)) }) } } + +func noopAssertRights(context.Context, *ttnpb.GatewayIdentifiers) error { return nil } diff --git a/pkg/gatewayserver/io/ws/lbslns/discover_util_test.go b/pkg/gatewayserver/io/ws/lbslns/discover_util_test.go index 19743b5693..e8e62e96e8 100644 --- a/pkg/gatewayserver/io/ws/lbslns/discover_util_test.go +++ b/pkg/gatewayserver/io/ws/lbslns/discover_util_test.go @@ -37,6 +37,10 @@ func (srv mockServer) FillGatewayContext(ctx context.Context, ids *ttnpb.Gateway return ctx, srv.ids, nil } +func (mockServer) AssertGatewayRights(context.Context, *ttnpb.GatewayIdentifiers, ...ttnpb.Right) error { + return nil +} + func (mockServer) Connect( context.Context, io.Frontend, *ttnpb.GatewayIdentifiers, *ttnpb.GatewayRemoteAddress, ...io.ConnectionOption, ) (*io.Connection, error) { diff --git a/pkg/gatewayserver/io/ws/lbslns/version.go b/pkg/gatewayserver/io/ws/lbslns/version.go index d3dd7db1c4..f86eafc187 100644 --- a/pkg/gatewayserver/io/ws/lbslns/version.go +++ b/pkg/gatewayserver/io/ws/lbslns/version.go @@ -64,7 +64,7 @@ func (*lbsLNS) GetRouterConfig( ctx context.Context, msg []byte, bandID string, - fps map[string]*frequencyplans.FrequencyPlan, + fps []*frequencyplans.FrequencyPlan, antennaGain int, receivedAt time.Time, ) (context.Context, []byte, *ttnpb.GatewayStatus, error) { diff --git a/pkg/gatewayserver/io/ws/ws.go b/pkg/gatewayserver/io/ws/ws.go index 41834ef38f..225ae1fe01 100644 --- a/pkg/gatewayserver/io/ws/ws.go +++ b/pkg/gatewayserver/io/ws/ws.go @@ -117,6 +117,18 @@ func (s *srv) handleConnectionInfo(w http.ResponseWriter, r *http.Request) { "remote_addr", r.RemoteAddr, )) logger := log.FromContext(ctx) + + assertAuth := func(ctx context.Context, ids *ttnpb.GatewayIdentifiers) error { + ctx, hasAuth := withForwardedAuth(ctx, ids, r.Header.Get("Authorization")) + if !hasAuth { + if !s.cfg.AllowUnauthenticated { + return errNoAuthProvided.WithAttributes("uid", unique.ID(ctx, ids)) + } + return nil + } + return s.server.AssertGatewayRights(ctx, ids, ttnpb.Right_RIGHT_GATEWAY_LINK) + } + ws, err := s.upgrader.Upgrade(w, r, nil) if err != nil { logger.WithError(err).Debug("Failed to upgrade request to websocket connection") @@ -154,7 +166,7 @@ func (s *srv) handleConnectionInfo(w http.ResponseWriter, r *http.Request) { Address: net.JoinHostPort(host, port), } - resp := s.formatter.HandleConnectionInfo(ctx, data, s.server, info, time.Now()) + resp := s.formatter.HandleConnectionInfo(ctx, data, s.server, info, assertAuth) if err := ws.WriteMessage(websocket.TextMessage, resp); err != nil { logger.WithError(err).Warn("Failed to write connection info response message") return @@ -202,47 +214,12 @@ func (s *srv) handleTraffic(w http.ResponseWriter, r *http.Request) (err error) uid := unique.ID(ctx, ids) ctx = log.NewContextWithField(ctx, "gateway_uid", uid) - var md metadata.MD - - if auth != "" { - if !strings.HasPrefix(auth, "Bearer ") { - auth = fmt.Sprintf("Bearer %s", auth) - } - md = metadata.New(map[string]string{ - "id": ids.GatewayId, - "authorization": auth, - }) - } - - if ctxMd, ok := metadata.FromIncomingContext(ctx); ok { - md = metadata.Join(ctxMd, md) - } - ctx = metadata.NewIncomingContext(ctx, md) - // If a fallback frequency is defined in the server context, inject it into local the context. - if fallback, ok := frequencyplans.FallbackIDFromContext(s.ctx); ok { - ctx = frequencyplans.WithFallbackID(ctx, fallback) - } - - var hasAuth bool - if auth != "" { - if !strings.HasPrefix(auth, "Bearer ") { - auth = fmt.Sprintf("Bearer %s", auth) - } - md = metadata.New(map[string]string{ - "authorization": auth, - }) - hasAuth = true - } - - if ctxMd, ok := metadata.FromIncomingContext(ctx); ok { - md = metadata.Join(ctxMd, md) - } - ctx = metadata.NewIncomingContext(ctx, md) // If a fallback frequency is defined in the server context, inject it into local the context. if fallback, ok := frequencyplans.FallbackIDFromContext(s.ctx); ok { ctx = frequencyplans.WithFallbackID(ctx, fallback) } + ctx, hasAuth := withForwardedAuth(ctx, ids, auth) if !hasAuth { if !s.cfg.AllowUnauthenticated { // We error here directly as there is no auth. @@ -416,3 +393,24 @@ func (s *srv) handleTraffic(w http.ResponseWriter, r *http.Request) (err error) } } } + +func withForwardedAuth(ctx context.Context, ids *ttnpb.GatewayIdentifiers, auth string) (context.Context, bool) { + var md metadata.MD + var hasAuth bool + if auth != "" { + if !strings.HasPrefix(auth, "Bearer ") { + auth = fmt.Sprintf("Bearer %s", auth) + } + m := map[string]string{"authorization": auth} + if ids != nil { + m["id"] = ids.GatewayId + } + md = metadata.New(m) + if ctxMd, ok := metadata.FromIncomingContext(ctx); ok { + md = metadata.Join(ctxMd, md) + } + ctx = metadata.NewIncomingContext(ctx, md) + hasAuth = true + } + return ctx, hasAuth +} diff --git a/pkg/gatewayserver/scheduling/scheduler.go b/pkg/gatewayserver/scheduling/scheduler.go index e574bc8f92..88cf0d90a1 100644 --- a/pkg/gatewayserver/scheduling/scheduler.go +++ b/pkg/gatewayserver/scheduling/scheduler.go @@ -81,7 +81,7 @@ var ( // If no time source is specified, the system time is used. func NewScheduler( ctx context.Context, - fps map[string]*frequencyplans.FrequencyPlan, + fps []*frequencyplans.FrequencyPlan, enforceDutyCycle bool, dutyCycleStyle DutyCycleStyle, scheduleAnytimeDelay *time.Duration, @@ -188,7 +188,7 @@ func NewScheduler( // Scheduler is a packet scheduler that takes time conflicts and sub-band restrictions into account. type Scheduler struct { clock *RolloverClock - fps map[string]*frequencyplans.FrequencyPlan + fps []*frequencyplans.FrequencyPlan timeOffAir frequencyplans.TimeOffAir timeSource TimeSource subBands []*SubBand diff --git a/pkg/gatewayserver/scheduling/scheduler_test.go b/pkg/gatewayserver/scheduling/scheduler_test.go index c7297f87c6..557862a1d8 100644 --- a/pkg/gatewayserver/scheduling/scheduler_test.go +++ b/pkg/gatewayserver/scheduling/scheduler_test.go @@ -35,7 +35,7 @@ import ( func TestScheduleAtWithBandDutyCycle(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -350,7 +350,7 @@ func TestScheduleAtWithBandDutyCycle(t *testing.T) { func TestScheduleAtWithFrequencyPlanDutyCycle(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, SubBands: []frequencyplans.SubBandParameters{ { @@ -438,7 +438,7 @@ func TestScheduleAtWithFrequencyPlanDutyCycle(t *testing.T) { func TestScheduleAnytime(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -552,7 +552,7 @@ func TestScheduleAnytime(t *testing.T) { func TestScheduleAnytimeShort(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -752,7 +752,7 @@ func TestScheduleAnytimeShort(t *testing.T) { func TestScheduleAnytimeClassC(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -843,14 +843,14 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { ctx := test.Context() for _, tc := range []struct { Name string - FrequencyPlans map[string]*frequencyplans.FrequencyPlan + FrequencyPlans []*frequencyplans.FrequencyPlan ExpectedSubBandCount int ErrorAssertion func(error) bool }{ { Name: "RepeatedNoOverlap", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - test.EUFrequencyPlanID: { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -860,7 +860,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { Duration: durationPtr(2 * time.Second), }, }, - "EU_863_870_Custom": { + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -875,8 +875,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, { Name: "UnionOfNonOverlapping", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - test.EUFrequencyPlanID: { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -895,7 +895,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, }, }, - "EU_863_870_Custom": { + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -910,8 +910,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, { Name: "MismatchedTimeOffAir", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - test.EUFrequencyPlanID: { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: 2 * time.Second, @@ -921,7 +921,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { Duration: durationPtr(2 * time.Second), }, }, - "EU_863_870_Custom": { + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -938,8 +938,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, { Name: "OverlappingSubBands", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - test.EUFrequencyPlanID: { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -958,7 +958,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, }, }, - "EU_863_870_Custom": { + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -975,8 +975,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { }, { Name: "OverlappingSubBandsFromBand", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - "AS_923": { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { // This is a fictional test case since currently we don't support mix-band frequency plans (https://github.com/TheThingsNetwork/lorawan-stack/issues/1394). BandID: band.AS_923, TimeOffAir: frequencyplans.TimeOffAir{ @@ -987,7 +987,7 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { Duration: durationPtr(2 * time.Second), }, }, - "AU_915_928": { + { BandID: band.AU_915_928, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -1029,8 +1029,8 @@ func TestSchedulerWithMultipleFrequencyPlans(t *testing.T) { func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{ - test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{ + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -1049,7 +1049,7 @@ func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) { }, }, }, - "EU_863_870_Custom": { + { BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, @@ -1140,7 +1140,7 @@ func TestSchedulingWithMultipleFrequencyPlans(t *testing.T) { func TestScheduleSyncViaUplinkToken(t *testing.T) { a := assertions.New(t) ctx := test.Context() - fps := map[string]*frequencyplans.FrequencyPlan{test.EUFrequencyPlanID: { + fps := []*frequencyplans.FrequencyPlan{{ BandID: band.EU_863_870, TimeOffAir: frequencyplans.TimeOffAir{ Duration: time.Second, diff --git a/pkg/httpclient/http.go b/pkg/httpclient/http.go index 94d5ec6b8d..0e6fe3b7bf 100644 --- a/pkg/httpclient/http.go +++ b/pkg/httpclient/http.go @@ -23,12 +23,16 @@ import ( "time" "github.com/gregjones/httpcache" + "github.com/klauspost/compress/gzhttp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.thethings.network/lorawan-stack/v3/pkg/config/tlsconfig" + "go.thethings.network/lorawan-stack/v3/pkg/experimental" "go.thethings.network/lorawan-stack/v3/pkg/telemetry/tracing" "go.thethings.network/lorawan-stack/v3/pkg/version" ) +var transportCompressionFeatureFlag = experimental.DefineFeature("http.client.transport.compression", true) + // defaultHTTPClientTimeout is the default timeout for the HTTP client. const defaultHTTPClientTimeout = 10 * time.Second @@ -95,11 +99,14 @@ func (p *provider) HTTPClient(ctx context.Context, opts ...Option) (*http.Client transport := http.DefaultTransport.(*http.Transport).Clone() transport.TLSClientConfig = options.tlsConfig - otelTransport := otelhttp.NewTransport(transport, + var rt http.RoundTripper = transport + if transportCompressionFeatureFlag.GetValue(ctx) { + rt = gzhttp.Transport(rt) + } + rt = otelhttp.NewTransport( + rt, otelhttp.WithTracerProvider(tracing.FromContext(ctx)), ) - - rt := http.RoundTripper(otelTransport) if options.cache { rt = &httpcache.Transport{ Transport: rt, diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index f731b361eb..34460cc6f3 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -19,6 +19,7 @@ import ( "bytes" "encoding/json" "fmt" + "maps" "os" "path/filepath" "runtime" @@ -27,7 +28,6 @@ import ( "sync" "github.com/gotnospirit/messageformat" - "golang.org/x/exp/maps" ) const defaultLanguage = "en" // The language of the messages written in Go files. diff --git a/pkg/identityserver/gateway_access.go b/pkg/identityserver/gateway_access.go index 5229fb4eaa..5c4ad4c6d0 100644 --- a/pkg/identityserver/gateway_access.go +++ b/pkg/identityserver/gateway_access.go @@ -537,7 +537,7 @@ type gatewayBatchAccess struct { } var ( - errEmtpyRequest = errors.DefineInvalidArgument( + errEmptyRequest = errors.DefineInvalidArgument( "empty_request", "empty request", ) @@ -555,7 +555,7 @@ func (gba *gatewayBatchAccess) AssertRights( // Sanitize request. required := req.Required.Unique() if len(required.GetRights()) == 0 { - return nil, errEmtpyRequest.New() + return nil, errEmptyRequest.New() } // Check that the request is checking only gateway rights. diff --git a/pkg/identityserver/gateway_access_test.go b/pkg/identityserver/gateway_access_test.go index a305e19729..b666c731e0 100644 --- a/pkg/identityserver/gateway_access_test.go +++ b/pkg/identityserver/gateway_access_test.go @@ -589,16 +589,30 @@ func TestGatewayBatchAccess(t *testing.T) { locUserKey, _ := p.NewAPIKey(locUser.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) locUserCreds := rpcCreds(locUserKey) - testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { - is.config.AdminRights.All = true + dualMembershipUser := p.NewUser() + dualMembershipUserKey, _ := p.NewAPIKey(dualMembershipUser.GetEntityIdentifiers(), ttnpb.Right_RIGHT_ALL) + dualMembershipUserCreds := rpcCreds(dualMembershipUserKey) + p.NewMembership( + dualMembershipUser.GetOrganizationOrUserIdentifiers(), + gtw3.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_GATEWAY_ALL, + ) + org1 := p.NewOrganization(dualMembershipUser.GetOrganizationOrUserIdentifiers()) + p.NewMembership( + org1.GetOrganizationOrUserIdentifiers(), + gtw3.GetEntityIdentifiers(), + ttnpb.Right_RIGHT_GATEWAY_ALL, + ) + testWithIdentityServer(t, func(is *IdentityServer, cc *grpc.ClientConn) { reg := ttnpb.NewGatewayBatchAccessClient(cc) for _, tc := range []struct { - Name string - Credentials grpc.CallOption - Request *ttnpb.AssertGatewayRightsRequest - ErrorAssertion func(error) bool + Name string + Credentials grpc.CallOption + Request *ttnpb.AssertGatewayRightsRequest + ErrorAssertion func(error) bool + LimitedAdminRights bool }{ { Name: "Empty request", @@ -771,6 +785,20 @@ func TestGatewayBatchAccess(t *testing.T) { Credentials: collaboratorCreds, ErrorAssertion: errors.IsPermissionDenied, }, + { + Name: "Universal rights for admin", + Request: &ttnpb.AssertGatewayRightsRequest{ + GatewayIds: []*ttnpb.GatewayIdentifiers{ + gtw3.GetIds(), + }, + Required: &ttnpb.Rights{ + Rights: []ttnpb.Right{ + ttnpb.Right_RIGHT_GATEWAY_SETTINGS_API_KEYS, + }, + }, + }, + Credentials: adminCreds, + }, { Name: "Limited rights for admin", Request: &ttnpb.AssertGatewayRightsRequest{ @@ -783,8 +811,9 @@ func TestGatewayBatchAccess(t *testing.T) { }, }, }, - Credentials: adminCreds, - ErrorAssertion: errors.IsNotFound, + Credentials: adminCreds, + ErrorAssertion: errors.IsPermissionDenied, + LimitedAdminRights: true, }, { Name: "Read Stats Failure", @@ -942,9 +971,25 @@ func TestGatewayBatchAccess(t *testing.T) { }, Credentials: usr1Creds, }, + { + Name: "Dual membership user", + Request: &ttnpb.AssertGatewayRightsRequest{ + GatewayIds: []*ttnpb.GatewayIdentifiers{ + gtw3.GetIds(), + }, + Required: &ttnpb.Rights{ + Rights: []ttnpb.Right{ + ttnpb.Right_RIGHT_GATEWAY_ALL, + }, + }, + }, + Credentials: dualMembershipUserCreds, + }, } { tc := tc t.Run(tc.Name, func(t *testing.T) { + is.config.AdminRights.All = !tc.LimitedAdminRights + _, err := reg.AssertRights(ctx, tc.Request, tc.Credentials) if err != nil { if tc.ErrorAssertion == nil || !a.So(tc.ErrorAssertion(err), should.BeTrue) { diff --git a/pkg/identityserver/identityserver.go b/pkg/identityserver/identityserver.go index 896ed0d2a2..c068ae877b 100644 --- a/pkg/identityserver/identityserver.go +++ b/pkg/identityserver/identityserver.go @@ -88,14 +88,17 @@ func (is *IdentityServer) configFromContext(ctx context.Context) *Config { // GenerateCSPString returns a Content-Security-Policy header value // for OAuth and Account app template. func GenerateCSPString(config *oauth.Config, nonce string) string { + baseURLs := webui.RewriteSchemes( + webui.WebsocketSchemeRewrites, + config.UI.StackConfig.IS.BaseURL, + ) return webui.ContentSecurityPolicy{ - ConnectionSource: []string{ + ConnectionSource: append([]string{ "'self'", - config.UI.StackConfig.IS.BaseURL, config.UI.SentryDSN, "gravatar.com", "www.gravatar.com", - }, + }, baseURLs...), StyleSource: []string{ "'self'", config.UI.AssetsBaseURL, diff --git a/pkg/identityserver/rights.go b/pkg/identityserver/rights.go index 6850da8e7b..b021745dfd 100644 --- a/pkg/identityserver/rights.go +++ b/pkg/identityserver/rights.go @@ -20,7 +20,6 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/identityserver/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" - "go.thethings.network/lorawan-stack/v3/pkg/unique" ) func allPotentialRights(eIDs *ttnpb.EntityIdentifiers, rights *ttnpb.Rights) *ttnpb.Rights { @@ -252,13 +251,16 @@ func (is *IdentityServer) assertGatewayRights( // nolint:gocyclo return errInsufficientRights.New() } + // If the caller has specified the identifiers multiple times, deduplicate them. + gtwIDs = uniqueIdentifiers(gtwIDs) + return is.store.Transact(ctx, func(ctx context.Context, st store.Store) error { gtws, err := st.FindGateways(ctx, gtwIDs, []string{"ids", "status_public", "location_public"}) if err != nil { return err } if len(gtws) != len(gtwIDs) { - if is.IsAdmin(ctx) { + if authInfo.IsAdmin { // Return the cause only to the admin. // This follows the same logic as in ListRights. return errSomeGatewaysNotFound.New() @@ -289,21 +291,21 @@ func (is *IdentityServer) assertGatewayRights( // nolint:gocyclo if bothStatsAndLocation { for _, gtw := range gtws { if gtw.StatusPublic && gtw.LocationPublic { - publicGatewayIds[unique.ID(ctx, gtw.Ids)] = struct{}{} + publicGatewayIds[gtw.IDString()] = struct{}{} } } } else { if onlyPublicStats { for _, gtw := range gtws { if gtw.StatusPublic { - publicGatewayIds[unique.ID(ctx, gtw.Ids)] = struct{}{} + publicGatewayIds[gtw.IDString()] = struct{}{} } } } if onlyPublicLocation { for _, gtw := range gtws { if gtw.LocationPublic { - publicGatewayIds[unique.ID(ctx, gtw.Ids)] = struct{}{} + publicGatewayIds[gtw.IDString()] = struct{}{} } } } @@ -311,11 +313,19 @@ func (is *IdentityServer) assertGatewayRights( // nolint:gocyclo entityIDs := make([]string, 0, len(gtwIDs)) for _, gtwID := range gtwIDs { - if _, ok := publicGatewayIds[unique.ID(ctx, gtwID)]; ok { + if _, ok := publicGatewayIds[gtwID.IDString()]; ok { continue } entityIDs = append(entityIDs, gtwID.GetEntityIdentifiers().IDString()) } + if len(entityIDs) == 0 { + return nil + } + if authInfo.IsAdmin { + if authInfo.GetUniversalRights().IncludesAll(requiredGatewayRights.GetRights()...) { + return nil + } + } membershipChains, err := st.FindAccountMembershipChains( ctx, ouID, @@ -325,19 +335,30 @@ func (is *IdentityServer) assertGatewayRights( // nolint:gocyclo if err != nil { return err } - if len(membershipChains) != len(entityIDs) { - // Some memberships were not found. - if is.IsAdmin(ctx) { - return errSomeGatewaysNotFound.New() - } - return errInsufficientRights.New() - } + entityRights := make(map[string]*ttnpb.Rights, len(membershipChains)) for _, chain := range membershipChains { + id := chain.EntityIdentifiers.IDString() + entityRights[id] = entityRights[id].Union(chain.GetRights()) + } + for _, entityID := range entityIDs { // Make sure that there are no extra rights requested. - if !chain.GetRights().IncludesAll(requiredGatewayRights.GetRights()...) { + if !entityRights[entityID].IncludesAll(requiredGatewayRights.GetRights()...) { return errInsufficientRights.New() } } return nil }) } + +func uniqueIdentifiers[T ttnpb.IDStringer](ids []T) []T { + m := make(map[string]struct{}, len(ids)) + result := make([]T, 0, len(ids)) + for _, id := range ids { + if _, ok := m[id.IDString()]; ok { + continue + } + m[id.IDString()] = struct{}{} + result = append(result, id) + } + return result +} diff --git a/pkg/messageprocessors/javascript/javascript.go b/pkg/messageprocessors/javascript/javascript.go index bdf2b5e008..81219b288f 100644 --- a/pkg/messageprocessors/javascript/javascript.go +++ b/pkg/messageprocessors/javascript/javascript.go @@ -56,9 +56,10 @@ type encodeDownlinkOutput struct { } var ( - errInput = errors.DefineInvalidArgument("input", "invalid input") - errOutput = errors.Define("output", "invalid output") - errOutputErrors = errors.DefineAborted("output_errors", "{errors}") + errInput = errors.DefineInvalidArgument("input", "invalid input") + errOutput = errors.Define("output", "invalid output") + errOutputErrors = errors.DefineAborted("output_errors", "{errors}") + errOutputEncoding = errors.DefineInvalidArgument("output_encoding", "{errors}") ) func wrapDownlinkEncoderScript(script string) string { @@ -309,6 +310,10 @@ func (*host) decodeUplink( if err != nil { return errOutput.WithCause(err) } + if errs := goproto.ValidateStruct(decodedPayload); len(errs) > 0 { + return errOutputEncoding.WithAttributes("errors", strings.Join(errs, ", ")) + } + msg.DecodedPayload, msg.DecodedPayloadWarnings = decodedPayload, output.Decoded.Warnings msg.NormalizedPayload, msg.NormalizedPayloadWarnings = nil, nil @@ -380,14 +385,6 @@ func (*host) decodeUplink( } } - // Roundtrip the message in order to convert special number values such as NaN and Infinity to their string form. - // TODO: Clean up the message and emit warning (https://github.com/TheThingsNetwork/lorawan-stack/issues/6128). - msg.DecodedPayload, err = structpb.NewStruct(decodedPayload.AsMap()) - if err != nil { - return errOutput.WithCause(err) - } - msg.DecodedPayloadWarnings = append(msg.DecodedPayloadWarnings, goproto.ValidateStruct(decodedPayload)...) - return nil } @@ -487,16 +484,12 @@ func (*host) decodeDownlink( if err != nil { return errOutput.WithCause(err) } + if errs := goproto.ValidateStruct(s); len(errs) > 0 { + return errOutputEncoding.WithAttributes("errors", strings.Join(errs, ", ")) + } + msg.DecodedPayload = s msg.DecodedPayloadWarnings = output.Warnings - // Roundtrip the message in order to convert special number values such as NaN and Infinity to their string form. - // TODO: Clean up the message and emit warning (https://github.com/TheThingsNetwork/lorawan-stack/issues/6128). - msg.DecodedPayload, err = structpb.NewStruct(s.AsMap()) - if err != nil { - return errOutput.WithCause(err) - } - msg.DecodedPayloadWarnings = append(msg.DecodedPayloadWarnings, goproto.ValidateStruct(s)...) - return nil } diff --git a/pkg/networkserver/downlink.go b/pkg/networkserver/downlink.go index a2379869dc..686e6a23c4 100644 --- a/pkg/networkserver/downlink.go +++ b/pkg/networkserver/downlink.go @@ -35,6 +35,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" "go.thethings.network/lorawan-stack/v3/pkg/packetbroker" "go.thethings.network/lorawan-stack/v3/pkg/specification/macspec" + "go.thethings.network/lorawan-stack/v3/pkg/specification/relayspec" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/types" "go.thethings.network/lorawan-stack/v3/pkg/unique" @@ -204,9 +205,10 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En maxDownPayloadLen := maxDownLen var ( - fPending bool - genState generateDownlinkState - cmdBuf []byte + fPending bool + genState generateDownlinkState + cmdBuf []byte + relayPayload []byte ) if class == ttnpb.Class_CLASS_A { spec := lorawan.DefaultMACCommands @@ -238,6 +240,18 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En dev.MacState.QueuedResponses = nil dev.MacState.PendingRequests = dev.MacState.PendingRequests[:0] + if relayDownlink := dev.MacState.PendingRelayDownlink; relayDownlink != nil { + // NOTE: We attempt to enqueue the pending relay downlink if the already + // enqueued MAC command responses fit into FOpts and the relay payload + // is smaller than the remaining space. + queuedResponsesLen := maxDownPayloadLen - maxDownLen + relayPayloadLen := uint16(len(relayDownlink.RawPayload)) + if queuedResponsesLen <= fOptsCapacity && relayPayloadLen <= maxDownLen { + relayPayload = relayDownlink.RawPayload + maxDownLen = fOptsCapacity - queuedResponsesLen + } + } + enqueuers := []func(context.Context, *ttnpb.EndDevice, uint16, uint16) mac.EnqueueState{ mac.EnqueueDutyCycleReq, func(ctx context.Context, dev *ttnpb.EndDevice, maxDownLen uint16, maxUpLen uint16) mac.EnqueueState { @@ -273,6 +287,13 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En func(ctx context.Context, dev *ttnpb.EndDevice, maxDownLen uint16, maxUpLen uint16) mac.EnqueueState { return mac.EnqueueDevStatusReq(ctx, dev, maxDownLen, maxUpLen, ns.defaultMACSettings, transmitAt) }, + mac.EnqueueRelayConfReq, + mac.EnqueueRelayEndDeviceConfReq, + func(ctx context.Context, dev *ttnpb.EndDevice, maxDownLen uint16, maxUpLen uint16) mac.EnqueueState { + return mac.EnqueueRelayUpdateUplinkListReq(ctx, dev, maxDownLen, maxUpLen, ns.relayKeyService()) + }, + mac.EnqueueRelayCtrlUplinkListReq, + mac.EnqueueRelayConfigureFwdLimitReq, } for _, f := range enqueuers { @@ -302,6 +323,10 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En cmdBuf = b } ctx = log.NewContext(ctx, logger) + + for i, req := range dev.MacState.PendingRequests { + dev.MacState.PendingRequests[i] = req.Sanitized() + } } var needsDownlink bool @@ -347,7 +372,7 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En ctx = log.NewContext(ctx, logger) cmdsInFOpts := len(cmdBuf) <= fOptsCapacity - if cmdsInFOpts { + if cmdsInFOpts && len(relayPayload) == 0 { appDowns := dev.Session.QueuedApplicationDownlinks[:0:0] outer: for i, down := range dev.Session.QueuedApplicationDownlinks { @@ -465,7 +490,7 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En mType = ttnpb.MType_CONFIRMED_DOWN } - case len(cmdBuf) > 0, needsDownlink: + case len(cmdBuf) > 0, len(relayPayload) > 0, needsDownlink: pld.FullFCnt = func() uint32 { for i := len(dev.MacState.RecentDownlinks) - 1; i >= 0; i-- { down := dev.MacState.RecentDownlinks[i] @@ -495,6 +520,25 @@ func (ns *NetworkServer) generateDataDownlink(ctx context.Context, dev *ttnpb.En } return 0 }() + if len(relayPayload) > 0 { + logger.Debug("Add relay downlink to buffer") + if dev.GetSession().GetKeys().GetNwkSEncKey() == nil { + return nil, genState, errUnknownNwkSEncKey.New() + } + key, err := cryptoutil.UnwrapAES128Key(ctx, dev.Session.Keys.NwkSEncKey, ns.KeyService()) + if err != nil { + logger.WithField("kek_label", dev.Session.Keys.NwkSEncKey.KekLabel).WithError(err).Warn("Failed to unwrap NwkSEncKey") + return nil, genState, err + } + encPayload, err := crypto.EncryptDownlink( + key, types.MustDevAddr(dev.Session.DevAddr).OrZero(), pld.FullFCnt, relayPayload, + ) + if err != nil { + return nil, genState, errEncryptMAC.WithCause(err) + } + pld.FPort = relayspec.FPort + pld.FrmPayload = encPayload + } default: return nil, genState, errNoDownlink.New() @@ -694,6 +738,9 @@ func downlinkPathsFromMetadata( case md.PacketBroker != nil: path.GatewayIdentifiers = packetbroker.GatewayIdentifiers tail = append(tail, path) + case md.Relay != nil: + path.GatewayIdentifiers = relayspec.GatewayIdentifiers + tail = append(tail, path) default: path.GatewayIdentifiers = md.GatewayIds switch md.DownlinkPathConstraint { @@ -891,6 +938,12 @@ func (ns *NetworkServer) scheduleDownlinkByPaths( continue } target = &packetBrokerDownlinkTarget{peer: peer} + case proto.Equal(path.GatewayIdentifiers, relayspec.GatewayIdentifiers): + target = &relayDownlinkTarget{ + servedEndDeviceIDs: req.EndDeviceIdentifiers, + servedSessionKeyID: req.SessionKeyID, + patchServingDevice: ns.relayPatchServingDevice, + } default: logger := logger.WithFields(log.Fields( "target", "gateway_server", @@ -1398,10 +1451,12 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn ctx = events.ContextWithCorrelationID(ctx, slot.Uplink.CorrelationIds...) if !dev.MacState.RxWindowsAvailable { log.FromContext(ctx).Error("RX windows not available, skip class A downlink slot") + dev.MacState.PendingRelayDownlink = nil dev.MacState.QueuedResponses = nil dev.MacState.RxWindowsAvailable = false return downlinkAttemptResult{ SetPaths: []string{ + "mac_state.pending_relay_downlink", "mac_state.queued_responses", "mac_state.rx_windows_available", }, @@ -1432,10 +1487,12 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn ) queuedEvents = append(queuedEvents, rxParametersEvents...) if err != nil { + dev.MacState.PendingRelayDownlink = nil dev.MacState.QueuedResponses = nil dev.MacState.RxWindowsAvailable = false return downlinkAttemptResult{ SetPaths: []string{ + "mac_state.pending_relay_downlink", "mac_state.queued_responses", "mac_state.rx_windows_available", }, @@ -1448,10 +1505,12 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn attemptRX2 = rxParameters.attemptRX2 ) if !attemptRX1 && !attemptRX2 { + dev.MacState.PendingRelayDownlink = nil dev.MacState.QueuedResponses = nil dev.MacState.RxWindowsAvailable = false return downlinkAttemptResult{ SetPaths: []string{ + "mac_state.pending_relay_downlink", "mac_state.queued_responses", "mac_state.rx_windows_available", }, @@ -1496,11 +1555,13 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn attemptRX2 = len(genDown.RawPayload) <= int(rxParameters.rx2MaxMACPayloadSize)+5 if !attemptRX1 && !attemptRX2 { log.FromContext(ctx).Error("Generated downlink payload size does not fit neither RX1, nor RX2, skip class A downlink slot") + dev.MacState.PendingRelayDownlink = nil dev.MacState.QueuedResponses = nil dev.MacState.RxWindowsAvailable = false return downlinkAttemptResult{ DownlinkTaskUpdateStrategy: nextDownlinkTask, SetPaths: ttnpb.AddFields(sets, + "mac_state.pending_relay_downlink", "mac_state.queued_responses", "mac_state.rx_windows_available", ), @@ -1554,10 +1615,12 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn if genState.ApplicationDownlink != nil { dev.Session.QueuedApplicationDownlinks = append([]*ttnpb.ApplicationDownlink{genState.ApplicationDownlink}, dev.Session.QueuedApplicationDownlinks...) } + dev.MacState.PendingRelayDownlink = nil dev.MacState.QueuedResponses = nil dev.MacState.RxWindowsAvailable = false return downlinkAttemptResult{ SetPaths: ttnpb.AddFields(sets, + "mac_state.pending_relay_downlink", "mac_state.queued_responses", "mac_state.rx_windows_available", ), @@ -1572,11 +1635,13 @@ func (ns *NetworkServer) attemptClassADataDownlink(ctx context.Context, dev *ttn dev.Session.QueuedApplicationDownlinks = dev.Session.QueuedApplicationDownlinks[:0:0] } recordDataDownlink(dev, genState, genDown.NeedsMACAnswer, down, ns.defaultMACSettings) + dev.MacState.PendingRelayDownlink = nil return downlinkAttemptResult{ SetPaths: ttnpb.AddFields(sets, "mac_state.last_confirmed_downlink_at", "mac_state.last_downlink_at", "mac_state.pending_application_downlink", + "mac_state.pending_relay_downlink", "mac_state.pending_requests", "mac_state.queued_responses", "mac_state.recent_downlinks", @@ -1979,6 +2044,7 @@ func (ns *NetworkServer) processDownlinkTask(ctx context.Context, consumerID str &scheduleRequest{ TxRequest: req, EndDeviceIdentifiers: dev.Ids, + SessionKeyID: dev.PendingMacState.QueuedJoinAccept.Keys.SessionKeyId, RawPayload: dev.PendingMacState.QueuedJoinAccept.Payload, Payload: &ttnpb.Message{ MHdr: &ttnpb.MHDR{ diff --git a/pkg/networkserver/grpc.go b/pkg/networkserver/grpc.go index dac4c4d99c..e49535dfed 100644 --- a/pkg/networkserver/grpc.go +++ b/pkg/networkserver/grpc.go @@ -79,6 +79,8 @@ func (ns *NetworkServer) GetDefaultMACSettings(ctx context.Context, req *ttnpb.G UplinkDwellTime: mac.DeviceUplinkDwellTime(nil, phy, ns.defaultMACSettings), DownlinkDwellTime: mac.DeviceDownlinkDwellTime(nil, phy, ns.defaultMACSettings), ScheduleDownlinks: &ttnpb.BoolValue{Value: mac.DeviceScheduleDownlinks(nil, ns.defaultMACSettings)}, + Relay: mac.DeviceDefaultRelayParameters(nil, ns.defaultMACSettings), + DesiredRelay: mac.DeviceDesiredRelayParameters(nil, ns.defaultMACSettings), } return settings, nil } diff --git a/pkg/networkserver/grpc_asns.go b/pkg/networkserver/grpc_asns.go index a91accfcac..acd2ee4236 100644 --- a/pkg/networkserver/grpc_asns.go +++ b/pkg/networkserver/grpc_asns.go @@ -40,14 +40,11 @@ type ApplicationUplinkQueue interface { // Implementations must ensure that Add returns fast. Add(ctx context.Context, ups ...*ttnpb.ApplicationUp) error - // Dispatch dispatches the tasks in the queue. - Dispatch(ctx context.Context, consumerID string) error - - // PopApplication calls f on the most recent application uplink task in the schedule, for which timestamp is in range [0, time.Now()], - // if such is available, otherwise it blocks until it is. + // Pop groups up to limit most recent application uplinks in the queue + // by their application ID and calls f on each group. // Context passed to f must be derived from ctx. // Implementations must respect ctx.Done() value on best-effort basis. - Pop(ctx context.Context, consumerID string, f func(context.Context, *ttnpb.ApplicationIdentifiers, ApplicationUplinkQueueDrainFunc) (time.Time, error)) error + Pop(ctx context.Context, consumerID string, limit int, f func(context.Context, []*ttnpb.ApplicationUp) error) error } func applicationJoinAcceptWithoutAppSKey(pld *ttnpb.ApplicationJoinAccept) *ttnpb.ApplicationJoinAccept { @@ -99,29 +96,23 @@ func (ns *NetworkServer) createProcessApplicationUplinkTask(consumerID string) f } func (ns *NetworkServer) processApplicationUplinkTask(ctx context.Context, consumerID string) error { - return ns.applicationUplinks.Pop(ctx, consumerID, func(ctx context.Context, appID *ttnpb.ApplicationIdentifiers, drain ApplicationUplinkQueueDrainFunc) (time.Time, error) { - conn, err := ns.GetPeerConn(ctx, ttnpb.ClusterRole_APPLICATION_SERVER, nil) - if err != nil { - log.FromContext(ctx).WithError(err).Warn("Failed to get Application Server peer") - return time.Now().Add(applicationUplinkTaskRetryInterval), nil - } - - cl := ttnpb.NewNsAsClient(conn) - var sendErr bool - if err := drain(applicationUplinkLimit, func(ups ...*ttnpb.ApplicationUp) error { - err := ns.sendApplicationUplinks(ctx, cl, ups...) + return ns.applicationUplinks.Pop(ctx, consumerID, applicationUplinkLimit, + func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + conn, err := ns.GetPeerConn(ctx, ttnpb.ClusterRole_APPLICATION_SERVER, nil) if err != nil { - sendErr = true + log.FromContext(ctx).WithError(err).Warn("Failed to get Application Server peer") + return err } - return err - }); err != nil { - if !sendErr { - log.FromContext(ctx).WithError(err).Error("Failed to drain application uplinks") + cl := ttnpb.NewNsAsClient(conn) + if err := ns.sendApplicationUplinks(ctx, cl, ups...); err != nil { + log.FromContext(ctx).WithError(err).Warn("Failed to send application uplinks") + if !retryableUplinkError(err) { + return nil + } + return err } - return time.Now().Add(applicationUplinkTaskRetryInterval), nil - } - return time.Time{}, nil - }) + return nil + }) } func minAFCntDown(session *ttnpb.Session, macState *ttnpb.MACState) (uint32, error) { diff --git a/pkg/networkserver/grpc_deviceregistry.go b/pkg/networkserver/grpc_deviceregistry.go index c0e84fcfc9..7861882413 100644 --- a/pkg/networkserver/grpc_deviceregistry.go +++ b/pkg/networkserver/grpc_deviceregistry.go @@ -613,6 +613,29 @@ var ( "pending_mac_state.current_parameters.ping_slot_frequency", "pending_mac_state.current_parameters.rejoin_count_periodicity", "pending_mac_state.current_parameters.rejoin_time_periodicity", + "pending_mac_state.current_parameters.relay.mode.served.backoff", + "pending_mac_state.current_parameters.relay.mode.served.mode.always", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.current_parameters.rx1_data_rate_offset", "pending_mac_state.current_parameters.rx1_delay", "pending_mac_state.current_parameters.rx2_data_rate_index", @@ -632,6 +655,29 @@ var ( "pending_mac_state.desired_parameters.ping_slot_frequency", "pending_mac_state.desired_parameters.rejoin_count_periodicity", "pending_mac_state.desired_parameters.rejoin_time_periodicity", + "pending_mac_state.desired_parameters.relay.mode.served.backoff", + "pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.desired_parameters.rx1_data_rate_offset", "pending_mac_state.desired_parameters.rx1_delay", "pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -697,7 +743,99 @@ var ( ifNotZeroThenZeroFields = map[string][]string{ "multicast": { + "mac_settings.desired_relay.mode.served.backoff", + "mac_settings.desired_relay.mode.served.mode.always", + "mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.served.second_channel.frequency", + "mac_settings.desired_relay.mode.served.serving_device_id", + "mac_settings.desired_relay.mode.serving.cad_periodicity", + "mac_settings.desired_relay.mode.serving.default_channel_index", + "mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.serving.second_channel.frequency", + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", + "mac_settings.relay.mode.served.backoff", + "mac_settings.relay.mode.served.mode.always", + "mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.relay.mode.served.mode.end_device_controlled", + "mac_settings.relay.mode.served.second_channel.ack_offset", + "mac_settings.relay.mode.served.second_channel.data_rate_index", + "mac_settings.relay.mode.served.second_channel.frequency", + "mac_settings.relay.mode.served.serving_device_id", + "mac_settings.relay.mode.serving.cad_periodicity", + "mac_settings.relay.mode.serving.default_channel_index", + "mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.relay.mode.serving.limits.overall.bucket_size", + "mac_settings.relay.mode.serving.limits.overall.reload_rate", + "mac_settings.relay.mode.serving.limits.reset_behavior", + "mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.relay.mode.serving.second_channel.ack_offset", + "mac_settings.relay.mode.serving.second_channel.data_rate_index", + "mac_settings.relay.mode.serving.second_channel.frequency", + "mac_settings.relay.mode.serving.uplink_forwarding_rules", "mac_settings.schedule_downlinks.value", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.last_adr_change_f_cnt_up", "mac_state.last_confirmed_downlink_at", "mac_state.last_dev_status_f_cnt_up", @@ -905,6 +1043,28 @@ var ( "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -924,6 +1084,28 @@ var ( "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -948,40 +1130,39 @@ var ( legacyADRSettingsFields = []string{ "mac_settings.adr_margin", - "mac_settings.use_adr", "mac_settings.use_adr.value", + "mac_settings.use_adr", } adrSettingsFields = []string{ - "mac_settings.adr", - "mac_settings.adr.mode", "mac_settings.adr.mode.disabled", - "mac_settings.adr.mode.dynamic", - "mac_settings.adr.mode.dynamic.channel_steering", - "mac_settings.adr.mode.dynamic.channel_steering.mode", "mac_settings.adr.mode.dynamic.channel_steering.mode.disabled", "mac_settings.adr.mode.dynamic.channel_steering.mode.lora_narrow", + "mac_settings.adr.mode.dynamic.channel_steering.mode", + "mac_settings.adr.mode.dynamic.channel_steering", "mac_settings.adr.mode.dynamic.margin", - "mac_settings.adr.mode.dynamic.max_data_rate_index", "mac_settings.adr.mode.dynamic.max_data_rate_index.value", + "mac_settings.adr.mode.dynamic.max_data_rate_index", "mac_settings.adr.mode.dynamic.max_nb_trans", "mac_settings.adr.mode.dynamic.max_tx_power_index", - "mac_settings.adr.mode.dynamic.min_data_rate_index", "mac_settings.adr.mode.dynamic.min_data_rate_index.value", + "mac_settings.adr.mode.dynamic.min_data_rate_index", "mac_settings.adr.mode.dynamic.min_nb_trans", "mac_settings.adr.mode.dynamic.min_tx_power_index", - "mac_settings.adr.mode.static", + "mac_settings.adr.mode.dynamic", "mac_settings.adr.mode.static.data_rate_index", "mac_settings.adr.mode.static.nb_trans", "mac_settings.adr.mode.static.tx_power_index", + "mac_settings.adr.mode.static", + "mac_settings.adr.mode", + "mac_settings.adr", } dynamicADRSettingsFields = []string{ - "mac_settings.adr.mode.dynamic", - "mac_settings.adr.mode.dynamic.channel_steering", - "mac_settings.adr.mode.dynamic.channel_steering.mode", "mac_settings.adr.mode.dynamic.channel_steering.mode.disabled", "mac_settings.adr.mode.dynamic.channel_steering.mode.lora_narrow", + "mac_settings.adr.mode.dynamic.channel_steering.mode", + "mac_settings.adr.mode.dynamic.channel_steering", "mac_settings.adr.mode.dynamic.margin", "mac_settings.adr.mode.dynamic.max_data_rate_index.value", "mac_settings.adr.mode.dynamic.max_nb_trans", @@ -989,6 +1170,7 @@ var ( "mac_settings.adr.mode.dynamic.min_data_rate_index.value", "mac_settings.adr.mode.dynamic.min_nb_trans", "mac_settings.adr.mode.dynamic.min_tx_power_index", + "mac_settings.adr.mode.dynamic", } ) @@ -1244,55 +1426,73 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest if st.HasSetField( "frequency_plan_id", "lorawan_phy_version", - "mac_settings.adr", - "mac_settings.adr.mode", "mac_settings.adr.mode.disabled", - "mac_settings.adr.mode.dynamic", - "mac_settings.adr.mode.dynamic.channel_steering", - "mac_settings.adr.mode.dynamic.channel_steering.mode", "mac_settings.adr.mode.dynamic.channel_steering.mode.disabled", "mac_settings.adr.mode.dynamic.channel_steering.mode.lora_narrow", + "mac_settings.adr.mode.dynamic.channel_steering.mode", + "mac_settings.adr.mode.dynamic.channel_steering", "mac_settings.adr.mode.dynamic.margin", - "mac_settings.adr.mode.dynamic.max_data_rate_index", "mac_settings.adr.mode.dynamic.max_data_rate_index.value", + "mac_settings.adr.mode.dynamic.max_data_rate_index", "mac_settings.adr.mode.dynamic.max_nb_trans", "mac_settings.adr.mode.dynamic.max_tx_power_index", - "mac_settings.adr.mode.dynamic.min_data_rate_index", "mac_settings.adr.mode.dynamic.min_data_rate_index.value", + "mac_settings.adr.mode.dynamic.min_data_rate_index", "mac_settings.adr.mode.dynamic.min_nb_trans", "mac_settings.adr.mode.dynamic.min_tx_power_index", - "mac_settings.adr.mode.static", + "mac_settings.adr.mode.dynamic", "mac_settings.adr.mode.static.data_rate_index", "mac_settings.adr.mode.static.nb_trans", "mac_settings.adr.mode.static.tx_power_index", + "mac_settings.adr.mode.static", + "mac_settings.adr.mode", + "mac_settings.adr", + "mac_settings.desired_ping_slot_data_rate_index.value", + "mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.serving.default_channel_index", + "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "mac_settings.desired_rx2_data_rate_index.value", + "mac_settings.downlink_dwell_time.value", "mac_settings.factory_preset_frequencies", + "mac_settings.ping_slot_data_rate_index.value", "mac_settings.ping_slot_frequency.value", - "mac_settings.use_adr.value", + "mac_settings.relay.mode.served.second_channel.data_rate_index", + "mac_settings.relay.mode.serving.default_channel_index", + "mac_settings.relay.mode.serving.second_channel.data_rate_index", "mac_settings.rx2_data_rate_index.value", - "mac_settings.desired_rx2_data_rate_index.value", - "mac_settings.ping_slot_data_rate_index.value", - "mac_settings.desired_ping_slot_data_rate_index.value", "mac_settings.uplink_dwell_time.value", - "mac_settings.downlink_dwell_time.value", + "mac_settings.use_adr.value", "mac_state.current_parameters.adr_data_rate_index", "mac_state.current_parameters.adr_tx_power_index", "mac_state.current_parameters.channels", "mac_state.current_parameters.ping_slot_data_rate_index_value.value", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", "mac_state.current_parameters.rx2_data_rate_index", "mac_state.desired_parameters.adr_data_rate_index", "mac_state.desired_parameters.adr_tx_power_index", "mac_state.desired_parameters.channels", "mac_state.desired_parameters.ping_slot_data_rate_index_value.value", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", "mac_state.desired_parameters.rx2_data_rate_index", "pending_mac_state.current_parameters.adr_data_rate_index", "pending_mac_state.current_parameters.adr_tx_power_index", "pending_mac_state.current_parameters.channels", "pending_mac_state.current_parameters.ping_slot_data_rate_index_value.value", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", "pending_mac_state.current_parameters.rx2_data_rate_index", "pending_mac_state.desired_parameters.adr_data_rate_index", "pending_mac_state.desired_parameters.adr_tx_power_index", "pending_mac_state.desired_parameters.channels", "pending_mac_state.desired_parameters.ping_slot_data_rate_index_value.value", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", "pending_mac_state.desired_parameters.rx2_data_rate_index", "supports_class_b", ) { @@ -1333,18 +1533,8 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "frequency_plan_id", "lorawan_phy_version", ) - - hasSetFieldWithFallback := func(field, fallbackField string) (fieldToRetrieve string, validate bool) { - if st.HasSetField(field) { - return field, true - } - return fallbackField, hasPHYUpdate - } hasSetField := func(field string) (fieldToRetrieve string, validate bool) { - return hasSetFieldWithFallback(field, field) - } - hasSetADRField := func(field string) (fieldToRetrieve string, validate bool) { - return hasSetFieldWithFallback(field, "mac_settings.adr.mode") + return field, st.HasSetField(field) || hasPHYUpdate } setFields := func(fields ...string) []string { @@ -1449,7 +1639,61 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.dynamic.max_data_rate_index.value"); validate { + if field, validate := hasSetField("mac_settings.desired_relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetDesiredRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacSettings.DesiredRelay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_settings.desired_relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetDesiredRelay().GetServing() == nil { + return nil + } + chIdx := dev.MacSettings.DesiredRelay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_settings.desired_relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetDesiredRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacSettings.DesiredRelay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_settings.adr.mode.dynamic.max_data_rate_index.value"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetDynamic().GetMaxDataRateIndex() == nil { @@ -1468,7 +1712,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.dynamic.min_data_rate_index.value"); validate { + if field, validate := hasSetField("mac_settings.adr.mode.dynamic.min_data_rate_index.value"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetDynamic().GetMinDataRateIndex() == nil { @@ -1487,7 +1731,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.dynamic.max_tx_power_index"); validate { + if field, validate := hasSetField("mac_settings.adr.mode.dynamic.max_tx_power_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetDynamic().GetMaxTxPowerIndex() == nil { @@ -1504,7 +1748,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.dynamic.min_tx_power_index"); validate { + if field, validate := hasSetField("mac_settings.adr.mode.dynamic.min_tx_power_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetDynamic().GetMinTxPowerIndex() == nil { @@ -1544,7 +1788,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.static.data_rate_index"); validate { + if field, validate := hasSetField("mac_settings.adr.mode.static.data_rate_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetStatic() == nil { @@ -1562,7 +1806,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } - if field, validate := hasSetADRField("mac_settings.adr.mode.static.tx_power_index"); validate { + if field, validate := hasSetField("mac_settings.adr.mode.static.tx_power_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { if dev.GetMacSettings().GetAdr().GetStatic() == nil { @@ -1613,6 +1857,60 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } + if field, validate := hasSetField("mac_settings.relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacSettings.Relay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_settings.relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetRelay().GetServing() == nil { + return nil + } + chIdx := dev.MacSettings.Relay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_settings.relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacSettings().GetRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacSettings.Relay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } if field, validate := hasSetField("mac_state.current_parameters.rx2_data_rate_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { if dev.GetMacState() == nil { @@ -1649,6 +1947,60 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } + if field, validate := hasSetField("pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetCurrentParameters().GetRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.PendingMacState.CurrentParameters.Relay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("pending_mac_state.current_parameters.relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetCurrentParameters().GetRelay().GetServing() == nil { + return nil + } + chIdx := dev.PendingMacState.CurrentParameters.Relay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetCurrentParameters().GetRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.PendingMacState.CurrentParameters.Relay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } if field, validate := hasSetField("pending_mac_state.current_parameters.rx2_data_rate_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { if dev.GetPendingMacState() == nil { @@ -1667,6 +2019,60 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } + if field, validate := hasSetField("pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetDesiredParameters().GetRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.PendingMacState.DesiredParameters.Relay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetDesiredParameters().GetRelay().GetServing() == nil { + return nil + } + chIdx := dev.PendingMacState.DesiredParameters.Relay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetPendingMacState().GetDesiredParameters().GetRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.PendingMacState.DesiredParameters.Relay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } if field, validate := hasSetField("pending_mac_state.desired_parameters.rx2_data_rate_index"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { if dev.GetPendingMacState() == nil { @@ -1703,6 +2109,60 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } + if field, validate := hasSetField("mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetCurrentParameters().GetRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacState.CurrentParameters.Relay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_state.current_parameters.relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetCurrentParameters().GetRelay().GetServing() == nil { + return nil + } + chIdx := dev.MacState.CurrentParameters.Relay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetCurrentParameters().GetRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacState.CurrentParameters.Relay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } if field, validate := hasSetField("mac_state.desired_parameters.ping_slot_data_rate_index_value.value"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { if dev.GetMacState() == nil || dev.MacState.DesiredParameters.PingSlotDataRateIndexValue == nil { @@ -1721,6 +2181,60 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest return nil, err } } + if field, validate := hasSetField("mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetDesiredParameters().GetRelay().GetServed().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacState.DesiredParameters.Relay.GetServed().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_state.desired_parameters.relay.mode.serving.default_channel_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetDesiredParameters().GetRelay().GetServing() == nil { + return nil + } + chIdx := dev.MacState.DesiredParameters.Relay.GetServing().DefaultChannelIndex + if chIdx >= uint32(len(phy.Relay.WORChannels)) { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } + if field, validate := hasSetField("mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index"); validate { + if err := st.WithField(func(dev *ttnpb.EndDevice) error { + return withPHY(func(phy *band.Band, _ *frequencyplans.FrequencyPlan) error { + if dev.GetMacState().GetDesiredParameters().GetRelay().GetServing().GetSecondChannel() == nil { + return nil + } + _, ok := phy.DataRates[dev.MacState.DesiredParameters.Relay.GetServing().SecondChannel.DataRateIndex] + if !ok { + return newInvalidFieldValueError(field) + } + return nil + }) + }, + field, + ); err != nil { + return nil, err + } + } if field, validate := hasSetField("pending_mac_state.current_parameters.ping_slot_data_rate_index_value.value"); validate { if err := st.WithField(func(dev *ttnpb.EndDevice) error { @@ -2137,7 +2651,7 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "pending_mac_state.queued_join_accept.payload": func() bool { return len(st.Device.PendingMacState.QueuedJoinAccept.Payload) == 0 }, "pending_mac_state.queued_join_accept.dev_addr": types.MustDevAddr( st.Device.PendingMacState.QueuedJoinAccept.DevAddr, - ).IsZero, + ).OrZero().IsZero, } { p, isZero := p, isZero if err := st.ValidateSetField(func() bool { return !isZero() }, p); err != nil { @@ -2316,6 +2830,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -2335,6 +2872,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -2356,6 +2916,8 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.pending_application_downlink.frm_payload", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_relay_downlink.raw_payload", + "mac_state.pending_relay_downlink", "mac_state.pending_requests", "mac_state.ping_slot_periodicity.value", "mac_state.queued_responses", @@ -2530,6 +3092,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "pending_mac_state.current_parameters.ping_slot_frequency", "pending_mac_state.current_parameters.rejoin_count_periodicity", "pending_mac_state.current_parameters.rejoin_time_periodicity", + "pending_mac_state.current_parameters.relay.mode.served.backoff", + "pending_mac_state.current_parameters.relay.mode.served.mode.always", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.current_parameters.rx1_data_rate_offset", "pending_mac_state.current_parameters.rx1_delay", "pending_mac_state.current_parameters.rx2_data_rate_index", @@ -2549,6 +3134,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "pending_mac_state.desired_parameters.ping_slot_frequency", "pending_mac_state.desired_parameters.rejoin_count_periodicity", "pending_mac_state.desired_parameters.rejoin_time_periodicity", + "pending_mac_state.desired_parameters.relay.mode.served.backoff", + "pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.desired_parameters.rx1_data_rate_offset", "pending_mac_state.desired_parameters.rx1_delay", "pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -2632,6 +3240,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -2651,6 +3282,29 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -2682,7 +3336,14 @@ func (ns *NetworkServer) Set(ctx context.Context, req *ttnpb.SetEndDeviceRequest } var evt events.Event - dev, ctx, err := ns.devices.SetByID(ctx, st.Device.Ids.ApplicationIds, st.Device.Ids.DeviceId, st.GetFields(), st.SetFunc(func(ctx context.Context, stored *ttnpb.EndDevice) error { + dev, ctx, err := ns.devices.SetByID(ctx, st.Device.Ids.ApplicationIds, st.Device.Ids.DeviceId, ttnpb.EndDeviceFieldPathsTopLevel, st.SetFunc(func(ctx context.Context, stored *ttnpb.EndDevice) error { + if nonZeroFields := ttnpb.NonZeroFields(stored, st.GetFields()...); len(nonZeroFields) > 0 { + newStored := &ttnpb.EndDevice{} + if err := newStored.SetFields(stored, nonZeroFields...); err != nil { + return err + } + stored = newStored + } if hasSession { macVersion := stored.GetMacState().GetLorawanVersion() if stored.GetMacState() == nil && !st.HasSetField("mac_state") { diff --git a/pkg/networkserver/grpc_gsns.go b/pkg/networkserver/grpc_gsns.go index 707991fa7f..8420594734 100644 --- a/pkg/networkserver/grpc_gsns.go +++ b/pkg/networkserver/grpc_gsns.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "runtime/trace" + "slices" clusterauth "go.thethings.network/lorawan-stack/v3/pkg/auth/cluster" "go.thethings.network/lorawan-stack/v3/pkg/band" @@ -32,11 +33,12 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal/time" "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" "go.thethings.network/lorawan-stack/v3/pkg/specification/macspec" + "go.thethings.network/lorawan-stack/v3/pkg/specification/relayspec" + "go.thethings.network/lorawan-stack/v3/pkg/task" "go.thethings.network/lorawan-stack/v3/pkg/toa" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/types" "go.thethings.network/lorawan-stack/v3/pkg/unique" - "golang.org/x/exp/slices" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/emptypb" @@ -57,19 +59,26 @@ const ( // This parameter is separated from the uplink collection period since the JoinRequest may have to be // served by a Join Server which is either geographically far away, or simply slow to respond. joinRequestCollectionWindow = 6 * time.Second + + // DeduplicationLimit is the number of metadata to deduplicate for a single transmission. + deduplicationLimit = 50 ) // UplinkDeduplicator represents an entity, that deduplicates uplinks and accumulates metadata. type UplinkDeduplicator interface { // DeduplicateUplink deduplicates an uplink message for specified time.Duration, in the provided round. // DeduplicateUplink returns true if the uplink is not a duplicate or false and error, if any, otherwise. - DeduplicateUplink(ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, round uint64) (first bool, err error) + DeduplicateUplink( + ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, limit int, round uint64, + ) (first bool, err error) // AccumulatedMetadata returns accumulated metadata for specified uplink message in the provided round and error, if any. AccumulatedMetadata(ctx context.Context, up *ttnpb.UplinkMessage, round uint64) (mds []*ttnpb.RxMetadata, err error) } -func (ns *NetworkServer) deduplicateUplink(ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, round uint64) (bool, error) { - ok, err := ns.uplinkDeduplicator.DeduplicateUplink(ctx, up, window, round) +func (ns *NetworkServer) deduplicateUplink( + ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, limit int, round uint64, +) (bool, error) { + ok, err := ns.uplinkDeduplicator.DeduplicateUplink(ctx, up, window, limit, round) if err != nil { log.FromContext(ctx).WithError(err).Error("Failed to deduplicate uplink") return false, err @@ -605,6 +614,18 @@ macLoop: evs, err = mac.HandleBeaconFreqAns(ctx, dev, cmd.GetBeaconFreqAns()) case ttnpb.MACCommandIdentifier_CID_DEVICE_MODE: evs, err = mac.HandleDeviceModeInd(ctx, dev, cmd.GetDeviceModeInd()) + case ttnpb.MACCommandIdentifier_CID_RELAY_CONF: + evs, err = mac.HandleRelayConfAns(ctx, dev, cmd.GetRelayConfAns()) + case ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF: + evs, err = mac.HandleRelayEndDeviceConfAns(ctx, dev, cmd.GetRelayEndDeviceConfAns()) + case ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST: + evs, err = mac.HandleRelayUpdateUplinkListAns(ctx, dev, cmd.GetRelayUpdateUplinkListAns()) + case ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST: + evs, err = mac.HandleRelayCtrlUplinkListAns(ctx, dev, cmd.GetRelayCtrlUplinkListAns()) + case ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT: + evs, err = mac.HandleRelayConfigureFwdLimitAns(ctx, dev, cmd.GetRelayConfigureFwdLimitAns()) + case ttnpb.MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE: + evs, err = mac.HandleRelayNotifyNewEndDeviceReq(ctx, dev, cmd.GetRelayNotifyNewEndDeviceReq()) default: _, known := lorawan.DefaultMACCommands[cmd.Cid] logger.WithField("known", known).Debug("Unknown MAC command received") @@ -641,6 +662,7 @@ macLoop: // TODO: Notify AS of session recovery(https://github.com/TheThingsNetwork/lorawan-stack/issues/594) } dev.MacState.PendingJoinRequest = nil + dev.MacState.PendingRelayDownlink = nil dev.PendingMacState = nil dev.PendingSession = nil @@ -746,9 +768,14 @@ func toMACStateRxMetadata(mds []*ttnpb.RxMetadata) []*ttnpb.MACState_UplinkMessa if md.PacketBroker != nil { pbMD = &ttnpb.MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata{} } + var relayMD *ttnpb.MACState_UplinkMessage_RxMetadata_RelayMetadata + if md.Relay != nil { + relayMD = &ttnpb.MACState_UplinkMessage_RxMetadata_RelayMetadata{} + } recentMDs = append(recentMDs, &ttnpb.MACState_UplinkMessage_RxMetadata{ GatewayIds: md.GatewayIds, PacketBroker: pbMD, + Relay: relayMD, ChannelRssi: md.ChannelRssi, Snr: md.Snr, DownlinkPathConstraint: md.DownlinkPathConstraint, @@ -790,10 +817,17 @@ func appendRecentUplink( up *ttnpb.UplinkMessage, window int, ) []*ttnpb.MACState_UplinkMessage { + ups := toMACStateUplinkMessages(up) if n := len(recent); n > 0 { recent[n-1].CorrelationIds = nil + if len(downlinkPathsFromRecentUplinks(ups...)) > 0 { + for _, md := range recent[n-1].RxMetadata { + md.UplinkToken = nil + md.DownlinkPathConstraint = ttnpb.DownlinkPathConstraint_DOWNLINK_PATH_CONSTRAINT_NEVER + } + } } - recent = append(recent, toMACStateUplinkMessages(up)...) + recent = append(recent, ups...) if extra := len(recent) - window; extra > 0 { recent = recent[extra:] } @@ -880,7 +914,7 @@ func (ns *NetworkServer) handleDataUplink(ctx context.Context, up *ttnpb.UplinkM "uplink_f_cnt", pld.FHdr.FCnt, )) - ok, err := ns.deduplicateUplink(ctx, up, ns.collectionWindow(ctx), initialDeduplicationRound) + ok, err := ns.deduplicateUplink(ctx, up, ns.collectionWindow(ctx), deduplicationLimit, initialDeduplicationRound) if err != nil { return err } @@ -1081,7 +1115,25 @@ func (ns *NetworkServer) handleDataUplink(ctx context.Context, up *ttnpb.UplinkM } if !matched.IsRetransmission { var frmPayload []byte - if pld.FPort != 0 { + switch pld.FPort { + case 0: + case relayspec.FPort: + relayUp, relayEvents, err := handleRelayForwardingProtocol( + ctx, matched.Device, matched.FullFCnt, matched.phy, up, ns.KeyService(), + ) + queuedEvents = append(queuedEvents, relayEvents...) + if err != nil { + log.FromContext(ctx).WithError(err).Warn("Failed to handle relay forwarding protocol") + } else { + ns.StartTask(&task.Config{ + Context: ns.FromRequestContext(ctx), + ID: "loopback_relay_uplink", + Func: relayLoopbackFunc(ns.LoopbackConn(), relayUp, ns.WithClusterAuth()), + Restart: task.RestartNever, + Backoff: task.DefaultBackoffConfig, + }) + } + default: frmPayload = pld.FrmPayload } queuedApplicationUplinks = append(queuedApplicationUplinks, &ttnpb.ApplicationUp{ @@ -1175,7 +1227,7 @@ func (ns *NetworkServer) handleJoinRequest(ctx context.Context, up *ttnpb.Uplink "join_eui", types.MustEUI64(pld.JoinEui).OrZero(), )) - ok, err := ns.deduplicateUplink(ctx, up, joinRequestCollectionWindow, initialDeduplicationRound) + ok, err := ns.deduplicateUplink(ctx, up, joinRequestCollectionWindow, deduplicationLimit, initialDeduplicationRound) if err != nil { return err } @@ -1337,6 +1389,10 @@ func (ns *NetworkServer) handleJoinRequest(ctx context.Context, up *ttnpb.Uplink macState.RxWindowsAvailable = true ctx = events.ContextWithCorrelationID(ctx, resp.CorrelationIds...) + if err := ns.deliverRelaySessionKeys(ctx, matched, keys.SessionKeyId); err != nil { + return err + } + publishEvents(ctx, queuedEvents...) queuedEvents = nil up = ttnpb.Clone(up) @@ -1389,7 +1445,7 @@ func (ns *NetworkServer) handleJoinRequest(ctx context.Context, up *ttnpb.Uplink return nil } -var errRejoinRequest = errors.DefineUnimplemented("rejoin_request", "rejoin-request handling is not implemented") +var errRejoinRequest = errors.DefineUnavailable("rejoin_request", "rejoin-request handling is not implemented") func (ns *NetworkServer) handleRejoinRequest(ctx context.Context, up *ttnpb.UplinkMessage) error { defer trace.StartRegion(ctx, "handle rejoin request").End() diff --git a/pkg/networkserver/grpc_gsns_internal_test.go b/pkg/networkserver/grpc_gsns_internal_test.go index 2452eb8eee..0318dc935b 100644 --- a/pkg/networkserver/grpc_gsns_internal_test.go +++ b/pkg/networkserver/grpc_gsns_internal_test.go @@ -26,15 +26,30 @@ import ( ) func TestAppendRecentUplink(t *testing.T) { + t.Parallel() + dataRate := (&ttnpb.LoRaDataRate{ + SpreadingFactor: uint32(7), + Bandwidth: 125_000, + CodingRate: "4/5", + }).DataRate() + macSettings := &ttnpb.MACState_UplinkMessage_TxSettings{ + DataRate: dataRate, + } + settings := &ttnpb.TxSettings{ + DataRate: dataRate, + } ups := [...]*ttnpb.MACState_UplinkMessage{ { DeviceChannelIndex: 1, + Settings: macSettings, }, { DeviceChannelIndex: 2, + Settings: macSettings, }, { DeviceChannelIndex: 3, + Settings: macSettings, }, } for _, tc := range []struct { @@ -46,6 +61,7 @@ func TestAppendRecentUplink(t *testing.T) { { Up: &ttnpb.UplinkMessage{ DeviceChannelIndex: 1, + Settings: settings, }, Window: 1, Expected: ups[:1], @@ -54,6 +70,7 @@ func TestAppendRecentUplink(t *testing.T) { Recent: ups[:1], Up: &ttnpb.UplinkMessage{ DeviceChannelIndex: 2, + Settings: settings, }, Window: 1, Expected: ups[1:2], @@ -62,6 +79,7 @@ func TestAppendRecentUplink(t *testing.T) { Recent: ups[:2], Up: &ttnpb.UplinkMessage{ DeviceChannelIndex: 3, + Settings: settings, }, Window: 1, Expected: ups[2:3], @@ -70,6 +88,7 @@ func TestAppendRecentUplink(t *testing.T) { Recent: ups[:1], Up: &ttnpb.UplinkMessage{ DeviceChannelIndex: 2, + Settings: settings, }, Window: 2, Expected: ups[:2], @@ -78,6 +97,7 @@ func TestAppendRecentUplink(t *testing.T) { Recent: ups[:2], Up: &ttnpb.UplinkMessage{ DeviceChannelIndex: 3, + Settings: settings, }, Window: 2, Expected: ups[1:3], diff --git a/pkg/networkserver/internal/test/shared/application_uplink_queue.go b/pkg/networkserver/internal/test/shared/application_uplink_queue.go deleted file mode 100644 index fc809fee2d..0000000000 --- a/pkg/networkserver/internal/test/shared/application_uplink_queue.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright © 2019 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 test - -import ( - "bytes" - "context" - "testing" - "time" - - "github.com/smarty/assertions" - "go.thethings.network/lorawan-stack/v3/pkg/errors" - . "go.thethings.network/lorawan-stack/v3/pkg/networkserver" - "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" - "google.golang.org/protobuf/proto" -) - -// handleApplicationUplinkQueueTest runs a test suite on q. -func handleApplicationUplinkQueueTest(ctx context.Context, q ApplicationUplinkQueue, consumerIDs []string) { - assertAdd := func(ctx context.Context, ups ...*ttnpb.ApplicationUp) bool { - t, a := test.MustNewTFromContext(ctx) - t.Helper() - - errCh := make(chan error, 1) - go func() { - errCh <- q.Add(ctx, ups...) - }() - select { - case <-ctx.Done(): - t.Error("Timed out while waiting for Add to return") - return false - - case err := <-errCh: - return a.So(err, should.BeNil) - } - } - - assertDrainApplication := func(ctx context.Context, withError bool, expected ...*ttnpb.ApplicationUp) bool { - t, a := test.MustNewTFromContext(ctx) - t.Helper() - - dispatchErrCh := make(chan error, len(consumerIDs)) - - dispatchCtx, cancelDispatchCtx := context.WithCancel(ctx) - defer cancelDispatchCtx() - for _, consumerID := range consumerIDs { - go func(consumerID string) { - select { - case <-ctx.Done(): - case dispatchErrCh <- q.Dispatch(dispatchCtx, consumerID): - } - }(consumerID) - } - defer func() { - cancelDispatchCtx() - - for range consumerIDs { - select { - case <-ctx.Done(): - case err := <-dispatchErrCh: - a.So(errors.IsCanceled(err), should.BeTrue) - } - } - }() - - type popFuncReq struct { - Context context.Context - ApplicationIdentifiers *ttnpb.ApplicationIdentifiers - Func ApplicationUplinkQueueDrainFunc - Response chan<- TaskPopFuncResponse - } - reqCh := make(chan popFuncReq, 1) - errCh := make(chan error, 1) - popCtx, cancelPopCtx := context.WithCancel(ctx) - defer cancelPopCtx() - for _, consumerID := range consumerIDs { - go func(consumerID string) { - errCh <- q.Pop(popCtx, consumerID, func(ctx context.Context, appID *ttnpb.ApplicationIdentifiers, f ApplicationUplinkQueueDrainFunc) (time.Time, error) { - respCh := make(chan TaskPopFuncResponse, 1) - select { - case <-popCtx.Done(): - return time.Time{}, popCtx.Err() - case reqCh <- popFuncReq{ - Context: ctx, - ApplicationIdentifiers: appID, - Func: f, - Response: respCh, - }: - } - select { - case <-popCtx.Done(): - return time.Time{}, popCtx.Err() - case resp := <-respCh: - return resp.Time, resp.Error - } - }) - }(consumerID) - } - - var collected []*ttnpb.ApplicationUp - var requests int - for ; len(collected) < len(expected); requests++ { - select { - case <-ctx.Done(): - t.Error("Timed out while waiting for Pop callback to be called") - return false - - case req := <-reqCh: - if !test.AllTrue( - a.So(req.Context, should.HaveParentContextOrEqual, ctx), - a.So(req.ApplicationIdentifiers, should.Resemble, expected[0].EndDeviceIds.ApplicationIds), - ) { - t.Error("Pop callback assertion failed") - return false - } - - if withError { - if !a.So(req.Func(2, func(ups ...*ttnpb.ApplicationUp) error { - a.So(ups, should.NotBeEmpty) - return test.ErrInternal - }), should.HaveSameErrorDefinitionAs, test.ErrInternal) { - return false - } - } - - if !a.So(req.Func(2, func(ups ...*ttnpb.ApplicationUp) error { - a.So(ups, should.NotBeEmpty) - collected = append(collected, ups...) - return nil - }), should.BeNil) { - return false - } - close(req.Response) - } - } - - for i := 0; i < requests; i++ { - select { - case <-ctx.Done(): - t.Error("Timed out while waiting for Pop to return") - return false - case err := <-errCh: - if !a.So(err, should.BeNil) { - return false - } - } - } - - cancelPopCtx() - - for i := requests; i < len(consumerIDs); i++ { - select { - case <-ctx.Done(): - t.Error("Timed out while waiting for Pop to return") - return false - case err := <-errCh: - if !a.So(errors.IsCanceled(err), should.BeTrue) { - return false - } - } - } - - if a.So(len(collected), should.Equal, len(expected)) { - for _, ex := range expected { - expectedB, err := proto.Marshal(ex) - if !a.So(err, should.BeNil) { - return false - } - - var found bool - for _, coll := range collected { - collectedB, err := proto.Marshal(coll) - if !a.So(err, should.BeNil) { - return false - } - - if bytes.Equal(expectedB, collectedB) { - found = true - } - } - - if !a.So(found, should.BeTrue) { - return false - } - } - } - - return true - } - - appID1 := &ttnpb.ApplicationIdentifiers{ - ApplicationId: "application-uplink-queue-app-1", - } - - appID2 := &ttnpb.ApplicationIdentifiers{ - ApplicationId: "application-uplink-queue-app-2", - } - - invalidations := [...]*ttnpb.ApplicationUp{ - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"invalidations[0]"}, - Up: &ttnpb.ApplicationUp_DownlinkQueueInvalidated{ - DownlinkQueueInvalidated: &ttnpb.ApplicationInvalidatedDownlinks{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"invalidations[1]"}, - Up: &ttnpb.ApplicationUp_DownlinkQueueInvalidated{ - DownlinkQueueInvalidated: &ttnpb.ApplicationInvalidatedDownlinks{}, - }, - }, - } - joinAccepts := [...]*ttnpb.ApplicationUp{ - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev", - }, - CorrelationIds: []string{"joinAccepts[0]"}, - Up: &ttnpb.ApplicationUp_JoinAccept{ - JoinAccept: &ttnpb.ApplicationJoinAccept{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"joinAccepts[1]"}, - Up: &ttnpb.ApplicationUp_JoinAccept{ - JoinAccept: &ttnpb.ApplicationJoinAccept{}, - }, - }, - } - genericApp1Ups := [...]*ttnpb.ApplicationUp{ - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev", - }, - CorrelationIds: []string{"genericApp1Ups[0]"}, - Up: &ttnpb.ApplicationUp_DownlinkFailed{ - DownlinkFailed: &ttnpb.ApplicationDownlinkFailed{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev", - }, - CorrelationIds: []string{"genericApp1Ups[1]"}, - Up: &ttnpb.ApplicationUp_LocationSolved{ - LocationSolved: &ttnpb.ApplicationLocation{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"genericApp1Ups[2]"}, - Up: &ttnpb.ApplicationUp_DownlinkFailed{ - DownlinkFailed: &ttnpb.ApplicationDownlinkFailed{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev", - }, - CorrelationIds: []string{"genericApp1Ups[3]"}, - Up: &ttnpb.ApplicationUp_DownlinkAck{ - DownlinkAck: &ttnpb.ApplicationDownlink{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID1, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"genericApp1Ups[4]"}, - Up: &ttnpb.ApplicationUp_DownlinkAck{ - DownlinkAck: &ttnpb.ApplicationDownlink{}, - }, - }, - } - - genericApp2Ups := [...]*ttnpb.ApplicationUp{ - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID2, - DeviceId: "test-dev2", - }, - CorrelationIds: []string{"genericApp2Ups[0]"}, - Up: &ttnpb.ApplicationUp_LocationSolved{ - LocationSolved: &ttnpb.ApplicationLocation{}, - }, - }, - { - EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ - ApplicationIds: appID2, - DeviceId: "test-dev", - }, - CorrelationIds: []string{"genericApp2Ups[1]"}, - Up: &ttnpb.ApplicationUp_DownlinkFailed{ - DownlinkFailed: &ttnpb.ApplicationDownlinkFailed{}, - }, - }, - } - - _, a := test.MustNewTFromContext(ctx) - switch { - case - !a.So(assertAdd(ctx, - genericApp1Ups[0], - ), should.BeTrue), - !a.So(assertDrainApplication(ctx, false, - genericApp1Ups[0], - ), should.BeTrue), - - !a.So(assertAdd(ctx, - genericApp2Ups[0], - ), should.BeTrue), - !a.So(assertAdd(ctx, - genericApp2Ups[1], - ), should.BeTrue), - !a.So(assertDrainApplication(ctx, true, - genericApp2Ups[0], - genericApp2Ups[1], - ), should.BeTrue), - - !a.So(assertAdd(ctx, - genericApp1Ups[1], - genericApp1Ups[2], - invalidations[0], - genericApp1Ups[3], - invalidations[1], - joinAccepts[0], - ), should.BeTrue), - !a.So(assertAdd(ctx, - genericApp1Ups[4], - joinAccepts[1], - ), should.BeTrue), - !a.So(assertDrainApplication(ctx, false, - joinAccepts[0], - joinAccepts[1], - invalidations[0], - invalidations[1], - genericApp1Ups[1], - genericApp1Ups[2], - genericApp1Ups[3], - genericApp1Ups[4], - ), should.BeTrue): - } -} - -// HandleApplicationUplinkQueueTest runs a ApplicationUplinkQueue test suite on reg. -func HandleApplicationUplinkQueueTest(t *testing.T, q ApplicationUplinkQueue, consumerIDs []string) { - t.Helper() - test.RunTest(t, test.TestConfig{ - Func: func(ctx context.Context, a *assertions.Assertion) { - t.Helper() - test.RunSubtestFromContext(ctx, test.SubtestConfig{ - Name: "1st run", - Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { - handleApplicationUplinkQueueTest(ctx, q, consumerIDs) - }, - }) - if t.Failed() { - t.Skip("Skipping 2nd run") - } - test.RunSubtestFromContext(ctx, test.SubtestConfig{ - Name: "2nd run", - Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { - handleApplicationUplinkQueueTest(ctx, q, consumerIDs) - }, - }) - }, - }) -} diff --git a/pkg/networkserver/internal/test/shared/device_registry.go b/pkg/networkserver/internal/test/shared/device_registry.go index bc99b37aac..558778ef9f 100644 --- a/pkg/networkserver/internal/test/shared/device_registry.go +++ b/pkg/networkserver/internal/test/shared/device_registry.go @@ -150,6 +150,16 @@ func handleDeviceRegistryTest(ctx context.Context, reg DeviceRegistry) { return false } + batchStored, err := reg.BatchGetByID( + ctx, pb.Ids.ApplicationIds, []string{pb.Ids.DeviceId}, ttnpb.EndDeviceFieldPathsTopLevel, + ) + if !test.AllTrue( + a.So(err, should.BeNil) || a.So(errors.Stack(err), should.BeEmpty), + a.So(batchStored, should.HaveLength, 1) && a.So(batchStored[0], should.BeNil), + ) { + t.Error("BatchGetByID assertion failed with empty registry") + } + stored, storedCtx, err = reg.GetByEUI( ctx, types.MustEUI64(pb.Ids.JoinEui).OrZero(), @@ -222,6 +232,17 @@ func handleDeviceRegistryTest(ctx context.Context, reg DeviceRegistry) { } ctx = storedCtx + batchStored, err := reg.BatchGetByID( + ctx, pb.Ids.ApplicationIds, []string{pb.Ids.DeviceId}, ttnpb.EndDeviceFieldPathsTopLevel, + ) + if !test.AllTrue( + a.So(err, should.BeNil) || a.So(errors.Stack(err), should.BeEmpty), + a.So(batchStored, should.HaveLength, 1) && a.So(batchStored[0], should.Resemble, pb), + ) { + t.Error("BatchGetByID assertion failed with non-empty registry") + return false + } + stored, storedCtx, err = reg.GetByEUI( ctx, types.MustEUI64(pb.Ids.JoinEui).OrZero(), diff --git a/pkg/networkserver/internal/test/shared/redis.go b/pkg/networkserver/internal/test/shared/redis.go index fb40f1102b..5ffccf960a 100644 --- a/pkg/networkserver/internal/test/shared/redis.go +++ b/pkg/networkserver/internal/test/shared/redis.go @@ -36,7 +36,7 @@ func testStreamBlockLimit() time.Duration { func NewRedisApplicationUplinkQueue(ctx context.Context) (ApplicationUplinkQueue, func()) { tb := test.MustTBFromContext(ctx) cl, flush := test.NewRedis(ctx, append(redisNamespace[:], "application-uplinks")...) - q := redis.NewApplicationUplinkQueue(cl, 100, redisConsumerGroup, 0, testStreamBlockLimit()) + q := redis.NewApplicationUplinkQueue(cl, 100, redisConsumerGroup, 0) if err := q.Init(ctx); err != nil { tb.Fatalf("Failed to initialize Redis application uplink queue: %s", test.FormatError(err)) } diff --git a/pkg/networkserver/internal/utils.go b/pkg/networkserver/internal/utils.go index 90fcde3c5b..3d09fd1f1e 100644 --- a/pkg/networkserver/internal/utils.go +++ b/pkg/networkserver/internal/utils.go @@ -109,10 +109,12 @@ func RXMetadataStats(ctx context.Context, mds []*ttnpb.RxMetadata) (gateways int md.PacketBroker.ForwarderNetId, md.PacketBroker.ForwarderTenantId, )] = struct{}{} + case md.Relay != nil: + gtws[fmt.Sprintf("relay:%s", md.Relay.DeviceId)] = struct{}{} case md.GatewayIds != nil: gtws[unique.ID(ctx, md.GatewayIds)] = struct{}{} default: - continue // Metadata without PB or Gateway IDs should be invalid so skipping. + continue // Metadata without PB, Relay or Gateway IDs should be invalid so skipping. } if md.Snr > maxSNR { maxSNR = md.Snr diff --git a/pkg/networkserver/mac/rekey.go b/pkg/networkserver/mac/rekey.go index cba67a0923..0561c33bbe 100644 --- a/pkg/networkserver/mac/rekey.go +++ b/pkg/networkserver/mac/rekey.go @@ -42,10 +42,12 @@ func HandleRekeyInd(ctx context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCom evs := events.Builders{ EvtReceiveRekeyIndication.With(events.WithData(pld)), } - if !dev.SupportsJoin { + if !dev.SupportsJoin || !macspec.UseRekeyInd(dev.LorawanVersion) { return evs, nil } - if dev.PendingSession != nil && dev.MacState.PendingJoinRequest != nil && types.MustDevAddr(dev.PendingSession.DevAddr).OrZero().Equal(devAddr) { + if dev.PendingSession != nil && + dev.MacState.PendingJoinRequest != nil && + types.MustDevAddr(dev.PendingSession.DevAddr).OrZero().Equal(devAddr) { dev.Ids.DevAddr = dev.PendingSession.DevAddr dev.Session = dev.PendingSession } diff --git a/pkg/networkserver/mac/rekey_test.go b/pkg/networkserver/mac/rekey_test.go index 7c976167fa..9fe3d1a584 100644 --- a/pkg/networkserver/mac/rekey_test.go +++ b/pkg/networkserver/mac/rekey_test.go @@ -28,6 +28,7 @@ import ( ) func TestHandleRekeyInd(t *testing.T) { + t.Parallel() for _, tc := range []struct { Name string Device, Expected *ttnpb.EndDevice @@ -48,8 +49,9 @@ func TestHandleRekeyInd(t *testing.T) { { Name: "empty queue/original", Device: &ttnpb.EndDevice{ - SupportsJoin: true, - Ids: &ttnpb.EndDeviceIdentifiers{}, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, + Ids: &ttnpb.EndDeviceIdentifiers{}, PendingSession: &ttnpb.Session{ DevAddr: test.DefaultDevAddr.Bytes(), LastFCntUp: 42, @@ -62,7 +64,8 @@ func TestHandleRekeyInd(t *testing.T) { }, }, Expected: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, @@ -95,7 +98,8 @@ func TestHandleRekeyInd(t *testing.T) { { Name: "empty queue/retransmission/non-matching pending session", Device: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, @@ -116,7 +120,8 @@ func TestHandleRekeyInd(t *testing.T) { }, }, Expected: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, @@ -149,7 +154,8 @@ func TestHandleRekeyInd(t *testing.T) { { Name: "empty queue/retransmission/no pending session", Device: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, @@ -161,7 +167,8 @@ func TestHandleRekeyInd(t *testing.T) { MacState: &ttnpb.MACState{}, }, Expected: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, @@ -194,8 +201,9 @@ func TestHandleRekeyInd(t *testing.T) { { Name: "non-empty queue", Device: &ttnpb.EndDevice{ - SupportsJoin: true, - Ids: &ttnpb.EndDeviceIdentifiers{}, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, + Ids: &ttnpb.EndDeviceIdentifiers{}, PendingSession: &ttnpb.Session{ DevAddr: test.DefaultDevAddr.Bytes(), LastFCntUp: 42, @@ -212,7 +220,8 @@ func TestHandleRekeyInd(t *testing.T) { }, }, Expected: &ttnpb.EndDevice{ - SupportsJoin: true, + LorawanVersion: ttnpb.MACVersion_MAC_V1_1, + SupportsJoin: true, Ids: &ttnpb.EndDeviceIdentifiers{ DevAddr: test.DefaultDevAddr.Bytes(), }, diff --git a/pkg/networkserver/mac/relay.go b/pkg/networkserver/mac/relay.go new file mode 100644 index 0000000000..ea32f2f604 --- /dev/null +++ b/pkg/networkserver/mac/relay.go @@ -0,0 +1,152 @@ +// Copyright © 2023 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 mac + +import ( + "context" + "fmt" + + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/types" +) + +// RelayKeyService provides common relay related cryptographic operations. +type RelayKeyService interface { + // BatchDeriveRootWorSKey derives the RootWorSKey for the provided end devices. + // For devices with a pending session, the derived RootWorSKey is derived rom the + // pending NwkSEncKey. For devices with an active session, the derived RootWorSKey + // is derived from the active NwkSEncKey. + BatchDeriveRootWorSKey( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, deviceIDs []string, sessionKeyIDs [][]byte, + ) (devAddrs []*types.DevAddr, keys []*types.AES128Key, err error) +} + +func secondChFields(secondCh *ttnpb.RelaySecondChannel) []any { + if secondCh == nil { + return nil + } + return []any{ + "relay_second_ch_ack_offset", secondCh.AckOffset, + "relay_second_ch_data_rate_index", secondCh.DataRateIndex, + "relay_second_ch_frequency", secondCh.Frequency, + } +} + +func servingRelayFields(serving *ttnpb.ServingRelayParameters) log.Fielder { + if serving == nil { + return log.Fields() + } + return log.Fields( + append( + secondChFields(serving.SecondChannel), + "relay_default_ch_index", serving.DefaultChannelIndex, + "relay_cad_periodicity", serving.CadPeriodicity, + )..., + ) +} + +func relayForwardLimitsFields(limits *ttnpb.RelayForwardLimits, prefix string) []any { + if limits == nil { + return nil + } + return []any{ + fmt.Sprintf("relay_%v_limit_bucket_size", prefix), limits.BucketSize, + fmt.Sprintf("relay_%v_limit_reload_rate", prefix), limits.ReloadRate, + } +} + +func relayConfigureForwardLimitsFields(limits *ttnpb.ServingRelayForwardingLimits) log.Fielder { + if limits == nil { + return log.Fields() + } + fields := []any{"relay_limit_reset_behavior", limits.ResetBehavior} + fields = append(fields, relayForwardLimitsFields(limits.JoinRequests, "join_requests")...) + fields = append(fields, relayForwardLimitsFields(limits.Notifications, "notifications")...) + fields = append(fields, relayForwardLimitsFields(limits.UplinkMessages, "uplink_messages")...) + fields = append(fields, relayForwardLimitsFields(limits.Overall, "overall")...) + return log.Fields(fields...) +} + +func servedRelayFields(served *ttnpb.ServedRelayParameters) log.Fielder { + if served == nil { + return log.Fields() + } + fields := []any{} + switch { + case served.GetAlways() != nil: + fields = append(fields, "relay_mode", "always") + case served.GetDynamic() != nil: + fields = append( + fields, + "relay_mode", "dynamic", + "relay_smart_enable_level", served.GetDynamic().SmartEnableLevel, + ) + case served.GetEndDeviceControlled() != nil: + fields = append(fields, "relay_mode", "end_device_controlled") + default: + panic("unreachable") + } + fields = append(fields, "relay_backoff", served.Backoff) + fields = append(fields, secondChFields(served.SecondChannel)...) + return log.Fields(fields...) +} + +func relayUpdateUplinkListReqFields(req *ttnpb.MACCommand_RelayUpdateUplinkListReq) log.Fielder { + fields := []any{ + "relay_rule_index", req.RuleIndex, + "relay_served_dev_addr", types.MustDevAddr(req.DevAddr), + "relay_served_w_f_cnt", req.WFCnt, + "relay_served_session_key_id", req.SessionKeyId, + } + if limits := req.ForwardLimits; limits != nil { + fields = append(fields, + "relay_served_bucket_size", limits.BucketSize, + "relay_served_reload_rate", limits.ReloadRate, + ) + } + return log.Fields(fields...) +} + +func relayCtrlUplinkListReqFields(req *ttnpb.MACCommand_RelayCtrlUplinkListReq) log.Fielder { + return log.Fields( + "relay_rule_index", req.RuleIndex, + "relay_ctrl_action", req.Action, + ) +} + +// DeviceDefaultRelayParameters returns the default relay parameters for the given device. +func DeviceDefaultRelayParameters(dev *ttnpb.EndDevice, defaults *ttnpb.MACSettings) *ttnpb.RelayParameters { + switch { + case dev.GetMacSettings().GetRelay() != nil: + return dev.MacSettings.Relay + case defaults.Relay != nil: + return defaults.Relay + default: + return nil + } +} + +// DeviceDesiredRelayParameters returns the desired relay parameters for the given device. +func DeviceDesiredRelayParameters(dev *ttnpb.EndDevice, defaults *ttnpb.MACSettings) *ttnpb.RelayParameters { + switch { + case dev.GetMacSettings().GetDesiredRelay() != nil: + return dev.MacSettings.DesiredRelay + case defaults.DesiredRelay != nil: + return defaults.DesiredRelay + default: + return DeviceDefaultRelayParameters(dev, defaults) + } +} diff --git a/pkg/networkserver/mac/relay_conf.go b/pkg/networkserver/mac/relay_conf.go new file mode 100644 index 0000000000..73ad57f131 --- /dev/null +++ b/pkg/networkserver/mac/relay_conf.go @@ -0,0 +1,164 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/protobuf/proto" +) + +var ( + // EvtEnqueueRelayConfRequest is emitted when a relay configuration request is enqueued. + EvtEnqueueRelayConfRequest = defineEnqueueMACRequestEvent( + "relay_conf", "relay configuration", + events.WithDataType(&ttnpb.MACCommand_RelayConfReq{}), + )() + // EvtReceiveRelayConfAccept is emitted when a relay configuration request is accepted. + EvtReceiveRelayConfAccept = defineReceiveMACAcceptEvent( + "relay_conf", "relay configuration", + events.WithDataType(&ttnpb.MACCommand_RelayConfAns{}), + )() + // EvtReceiveRelayConfReject is emitted when a relay configuration request is rejected. + EvtReceiveRelayConfReject = defineReceiveMACRejectEvent( + "relay_conf", "relay configuration", + events.WithDataType(&ttnpb.MACCommand_RelayConfAns{}), + )() +) + +// DeviceNeedsRelayConfReq returns true iff the device needs a relay configuration request. +func DeviceNeedsRelayConfReq(dev *ttnpb.EndDevice) bool { + if dev.GetMulticast() || dev.GetMacState() == nil { + return false + } + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + desiredServing := dev.MacState.GetDesiredParameters().GetRelay().GetServing() + if desiredServing == nil && currentServing == nil { + return false + } + if (desiredServing == nil) != (currentServing == nil) { + return true + } + // NOTE: The forwarding rules are handled by UpdateUplinkListReq, not RelayConfReq. + // NOTE: The limits are handled by ConfigureFwdLimitReq, not RelayConfReq. + return !proto.Equal(&ttnpb.ServingRelayParameters{ + SecondChannel: desiredServing.SecondChannel, + DefaultChannelIndex: desiredServing.DefaultChannelIndex, + CadPeriodicity: desiredServing.CadPeriodicity, + }, &ttnpb.ServingRelayParameters{ + SecondChannel: currentServing.SecondChannel, + DefaultChannelIndex: currentServing.DefaultChannelIndex, + CadPeriodicity: currentServing.CadPeriodicity, + }) +} + +// EnqueueRelayConfReq enqueues a relay configuration request if needed. +func EnqueueRelayConfReq(ctx context.Context, dev *ttnpb.EndDevice, maxDownLen, maxUpLen uint16) EnqueueState { + if !DeviceNeedsRelayConfReq(dev) { + return EnqueueState{ + MaxDownLen: maxDownLen, + MaxUpLen: maxUpLen, + Ok: true, + } + } + var st EnqueueState + dev.MacState.PendingRequests, st = enqueueMACCommand( + ttnpb.MACCommandIdentifier_CID_RELAY_CONF, + maxDownLen, maxUpLen, + func(nDown, nUp uint16) ([]*ttnpb.MACCommand, uint16, events.Builders, bool) { + if nDown < 1 || nUp < 1 { + return nil, 0, nil, false + } + desiredServing := dev.MacState.GetDesiredParameters().GetRelay().GetServing() + req := &ttnpb.MACCommand_RelayConfReq{} + if desiredServing != nil { + req.Configuration = &ttnpb.MACCommand_RelayConfReq_Configuration{ + CadPeriodicity: desiredServing.CadPeriodicity, + DefaultChannelIndex: desiredServing.DefaultChannelIndex, + SecondChannel: desiredServing.SecondChannel, + } + } + log.FromContext(ctx).WithFields(servingRelayFields(desiredServing)).Debug("Enqueued RelayConfReq") + return []*ttnpb.MACCommand{ + req.MACCommand(), + }, + 1, + events.Builders{ + EvtEnqueueRelayConfRequest.With(events.WithData(req)), + }, + true + }, + dev.MacState.PendingRequests..., + ) + return st +} + +// HandleRelayConfAns handles a relay configuration answer. +func HandleRelayConfAns( + _ context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayConfAns, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + rejected := !pld.SecondChannelFrequencyAck || + !pld.SecondChannelAckOffsetAck || + !pld.SecondChannelDataRateIndexAck || + !pld.SecondChannelIndexAck || + !pld.DefaultChannelIndexAck || + !pld.CadPeriodicityAck + var err error + dev.MacState.PendingRequests, err = handleMACResponse( + ttnpb.MACCommandIdentifier_CID_RELAY_CONF, + false, + func(cmd *ttnpb.MACCommand) error { + if rejected { + return nil + } + req := cmd.GetRelayConfReq() + currentParameters := dev.MacState.CurrentParameters + if req.Configuration == nil { + currentParameters.Relay = nil + return nil + } + relay := currentParameters.Relay + if relay == nil { + relay = &ttnpb.RelayParameters{} + currentParameters.Relay = relay + } + serving := relay.GetServing() + if serving == nil { + serving = &ttnpb.ServingRelayParameters{} + relay.Mode = &ttnpb.RelayParameters_Serving{ + Serving: serving, + } + } + serving.CadPeriodicity = req.Configuration.CadPeriodicity + serving.DefaultChannelIndex = req.Configuration.DefaultChannelIndex + serving.SecondChannel = req.Configuration.SecondChannel + return nil + }, + dev.MacState.PendingRequests..., + ) + ev := EvtReceiveRelayConfAccept + if rejected { + ev = EvtReceiveRelayConfReject + } + return events.Builders{ + ev.With(events.WithData(pld)), + }, err +} diff --git a/pkg/networkserver/mac/relay_conf_test.go b/pkg/networkserver/mac/relay_conf_test.go new file mode 100644 index 0000000000..898c32b134 --- /dev/null +++ b/pkg/networkserver/mac/relay_conf_test.go @@ -0,0 +1,911 @@ +// Copyright © 2023 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 mac_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "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 TestDeviceNeedsRelayConfReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice *ttnpb.EndDevice + Needs bool + }{ + { + Name: "no MAC state", + InputDevice: &ttnpb.EndDevice{}, + }, + { + Name: "no relay", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + }, + { + Name: "disable serving", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + Needs: true, + }, + { + Name: "enable serving", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "enable second channel", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "no change", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + }, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + res := mac.DeviceNeedsRelayConfReq(dev) + if tc.Needs { + a.So(res, should.BeTrue) + } else { + a.So(res, should.BeFalse) + } + a.So(dev, should.Resemble, tc.InputDevice) + }, + }) + } +} + +func TestEnqueueRelayConfReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice, ExpectedDevice *ttnpb.EndDevice + MaxDownlinkLength uint16 + MaxUplinkLength uint16 + State mac.EnqueueState + }{ + { + Name: "enable serving", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + })), + }, + Ok: true, + }, + }, + { + Name: "disable serving", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: nil, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayConfReq{ + Configuration: nil, + })), + }, + Ok: true, + }, + }, + { + Name: "disable second channel", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: nil, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: nil, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + })), + }, + Ok: true, + }, + }, + { + Name: "enable second channel", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS, + }, + })), + }, + Ok: true, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + st := mac.EnqueueRelayConfReq(ctx, dev, tc.MaxDownlinkLength, tc.MaxUplinkLength) + a.So(dev, should.Resemble, tc.ExpectedDevice) + a.So(st.QueuedEvents, should.ResembleEventBuilders, tc.State.QueuedEvents) + st.QueuedEvents = tc.State.QueuedEvents + a.So(st, should.Resemble, tc.State) + }, + }) + } +} + +func TestHandleRelayConfAns(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + Device, Expected *ttnpb.EndDevice + Payload *ttnpb.MACCommand_RelayConfAns + Events events.Builders + Error error + }{ + { + Name: "reject serving", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfAns{}, + Events: events.Builders{ + mac.EvtReceiveRelayConfReject.With(events.WithData(&ttnpb.MACCommand_RelayConfAns{})), + }, + }, + { + Name: "enable serving", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + })), + }, + }, + { + Name: "disable serving", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + PendingRequests: []*ttnpb.MACCommand{(&ttnpb.MACCommand_RelayConfReq{}).MACCommand()}, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + })), + }, + }, + { + Name: "enable second channel", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + })), + }, + }, + { + Name: "disable second channel", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + SecondChannel: &ttnpb.RelaySecondChannel{ + AckOffset: ttnpb.RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200, + DataRateIndex: ttnpb.DataRateIndex_DATA_RATE_1, + Frequency: 123, + }, + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfReq{ + Configuration: &ttnpb.MACCommand_RelayConfReq_Configuration{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + DefaultChannelIndex: 1, + CadPeriodicity: ttnpb.RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayConfAns{ + SecondChannelFrequencyAck: true, + SecondChannelAckOffsetAck: true, + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + DefaultChannelIndexAck: true, + CadPeriodicityAck: true, + })), + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.Device) + evs, err := mac.HandleRelayConfAns(ctx, dev, tc.Payload) + if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || + tc.Error == nil && !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(dev, should.Resemble, tc.Expected) + a.So(evs, should.ResembleEventBuilders, tc.Events) + }, + }) + } +} diff --git a/pkg/networkserver/mac/relay_configure_fwd_limit.go b/pkg/networkserver/mac/relay_configure_fwd_limit.go new file mode 100644 index 0000000000..1064f649fb --- /dev/null +++ b/pkg/networkserver/mac/relay_configure_fwd_limit.go @@ -0,0 +1,159 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/protobuf/proto" +) + +var ( + // defaultRelayForwardingLimits is the default relay forward limits, based on the contents of the + // relay specification. + defaultRelayForwardingLimits = &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 4, + }, + Notifications: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 4, + }, + UplinkMessages: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 8, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 8, + }, + } + + // EvtEnqueueRelayConfigureFwdLimitRequest is emitted when a relay forward limits configuration request is enqueued. + EvtEnqueueRelayConfigureFwdLimitRequest = defineEnqueueMACRequestEvent( + "relay_configure_fwd_limit", "relay configure forward limit", + events.WithDataType(&ttnpb.MACCommand_RelayConfigureFwdLimitReq{}), + )() + // EvtReceiveRelayConfigureFwdLimitAnswer is emitted when a relay forward limits configuration request is answered. + EvtReceiveRelayConfigureFwdLimitAnswer = defineReceiveMACAnswerEvent( + "relay_configure_fwd_limit", "relay configure forward limit", + events.WithDataType(&ttnpb.MACCommand_RelayConfigureFwdLimitAns{}), + )() +) + +// DeviceNeedsRelayConfigureFwdLimitReq returns true iff the device needs a relay forward limits configuration request. +func DeviceNeedsRelayConfigureFwdLimitReq(dev *ttnpb.EndDevice) bool { + if dev.GetMulticast() || dev.GetMacState() == nil { + return false + } + currentLimits := dev.MacState.GetCurrentParameters().GetRelay().GetServing().GetLimits() + desiredLimits := dev.MacState.GetDesiredParameters().GetRelay().GetServing().GetLimits() + if desiredLimits == nil && currentLimits == nil { + return false + } + if currentLimits == nil { + currentLimits = defaultRelayForwardingLimits + } + if desiredLimits == nil { + desiredLimits = defaultRelayForwardingLimits + } + return !proto.Equal(desiredLimits, currentLimits) +} + +// EnqueueRelayConfigureFwdLimitReq enqueues a relay forward limits configuration request if needed. +func EnqueueRelayConfigureFwdLimitReq( + ctx context.Context, dev *ttnpb.EndDevice, maxDownLen, maxUpLen uint16, +) EnqueueState { + if !DeviceNeedsRelayConfigureFwdLimitReq(dev) { + return EnqueueState{ + MaxDownLen: maxDownLen, + MaxUpLen: maxUpLen, + Ok: true, + } + } + var st EnqueueState + dev.MacState.PendingRequests, st = enqueueMACCommand( + ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + maxDownLen, maxUpLen, + func(nDown, nUp uint16) ([]*ttnpb.MACCommand, uint16, events.Builders, bool) { + if nDown < 1 || nUp < 1 { + return nil, 0, nil, false + } + desiredLimits := dev.MacState.GetDesiredParameters().GetRelay().GetServing().GetLimits() + if desiredLimits == nil { + desiredLimits = defaultRelayForwardingLimits + } + req := &ttnpb.MACCommand_RelayConfigureFwdLimitReq{ + ResetLimitCounter: desiredLimits.ResetBehavior, + JoinRequestLimits: desiredLimits.JoinRequests, + NotifyLimits: desiredLimits.Notifications, + GlobalUplinkLimits: desiredLimits.UplinkMessages, + OverallLimits: desiredLimits.Overall, + } + log.FromContext(ctx).WithFields(relayConfigureForwardLimitsFields(desiredLimits)). + Debug("Enqueued RelayConfigureFwdLimitReq") + return []*ttnpb.MACCommand{ + req.MACCommand(), + }, + 1, + events.Builders{ + EvtEnqueueRelayConfigureFwdLimitRequest.With(events.WithData(req)), + }, + true + }, + dev.MacState.PendingRequests..., + ) + return st +} + +// HandleRelayConfigureFwdLimitAns handles a relay forward limits configuration answer. +func HandleRelayConfigureFwdLimitAns( + _ context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayConfigureFwdLimitAns, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + var err error + dev.MacState.PendingRequests, err = handleMACResponse( + ttnpb.MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + false, + func(cmd *ttnpb.MACCommand) error { + req := cmd.GetRelayConfigureFwdLimitReq() + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + if currentServing == nil { + // NOTE: EnqueueRelayConfigureFwdLimitReq is optimistic and assumes that EnqueueRelayConfReq + // has enqueued the desired relay parameters, and that the end device will accept them. If + // either of these conditions is not true, the current serving parameters will be nil. + return nil + } + currentServing.Limits = &ttnpb.ServingRelayForwardingLimits{ + ResetBehavior: req.ResetLimitCounter, + JoinRequests: req.JoinRequestLimits, + Notifications: req.NotifyLimits, + UplinkMessages: req.GlobalUplinkLimits, + Overall: req.OverallLimits, + } + return nil + }, + dev.MacState.PendingRequests..., + ) + return events.Builders{ + EvtReceiveRelayConfigureFwdLimitAnswer.With(events.WithData(pld)), + }, err +} diff --git a/pkg/networkserver/mac/relay_configure_fwd_limit_test.go b/pkg/networkserver/mac/relay_configure_fwd_limit_test.go new file mode 100644 index 0000000000..ef541b4886 --- /dev/null +++ b/pkg/networkserver/mac/relay_configure_fwd_limit_test.go @@ -0,0 +1,519 @@ +// Copyright © 2023 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 mac_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "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 TestDeviceNeedsRelayConfigureFwdLimitReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice *ttnpb.EndDevice + Needs bool + }{ + { + Name: "no MAC state", + InputDevice: &ttnpb.EndDevice{}, + }, + { + Name: "no relay", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + }, + { + Name: "no limits", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "some limits", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "no change", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + res := mac.DeviceNeedsRelayConfigureFwdLimitReq(dev) + if tc.Needs { + a.So(res, should.BeTrue) + } else { + a.So(res, should.BeFalse) + } + a.So(dev, should.Resemble, tc.InputDevice) + }, + }) + } +} + +func TestEnqueueRelayConfigureFwdLimitReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice, ExpectedDevice *ttnpb.EndDevice + MaxDownlinkLength uint16 + MaxUplinkLength uint16 + State mac.EnqueueState + }{ + { + Name: "no limits", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfigureFwdLimitReq{}).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 49, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfigureFwdLimitRequest.With(events.WithData( + &ttnpb.MACCommand_RelayConfigureFwdLimitReq{}, + )), + }, + Ok: true, + }, + }, + { + Name: "some limits", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfigureFwdLimitReq{ + JoinRequestLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + OverallLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 44, + MaxUpLen: 49, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayConfigureFwdLimitRequest.With(events.WithData( + &ttnpb.MACCommand_RelayConfigureFwdLimitReq{ + JoinRequestLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + OverallLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + )), + }, + Ok: true, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + st := mac.EnqueueRelayConfigureFwdLimitReq(ctx, dev, tc.MaxDownlinkLength, tc.MaxUplinkLength) + a.So(dev, should.Resemble, tc.ExpectedDevice) + a.So(st.QueuedEvents, should.ResembleEventBuilders, tc.State.QueuedEvents) + st.QueuedEvents = tc.State.QueuedEvents + a.So(st, should.Resemble, tc.State) + }, + }) + } +} + +func TestHandleRelayConfigureFwdLimitAns(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + Device, Expected *ttnpb.EndDevice + Payload *ttnpb.MACCommand_RelayConfigureFwdLimitAns + Events events.Builders + Error error + }{ + { + Name: "no limits", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfigureFwdLimitReq{}).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{}, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + Events: events.Builders{ + mac.EvtReceiveRelayConfigureFwdLimitAnswer.With(events.WithData( + &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + )), + }, + }, + { + Name: "some limits", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayConfigureFwdLimitReq{ + JoinRequestLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + OverallLimits: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + Limits: &ttnpb.ServingRelayForwardingLimits{ + JoinRequests: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2, + ReloadRate: 12, + }, + Overall: &ttnpb.RelayForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4, + ReloadRate: 23, + }, + }, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + Events: events.Builders{ + mac.EvtReceiveRelayConfigureFwdLimitAnswer.With(events.WithData( + &ttnpb.MACCommand_RelayConfigureFwdLimitAns{}, + )), + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.Device) + evs, err := mac.HandleRelayConfigureFwdLimitAns(ctx, dev, tc.Payload) + if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || + tc.Error == nil && !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(dev, should.Resemble, tc.Expected) + a.So(evs, should.ResembleEventBuilders, tc.Events) + }, + }) + } +} diff --git a/pkg/networkserver/mac/relay_ctrl_uplink_list.go b/pkg/networkserver/mac/relay_ctrl_uplink_list.go new file mode 100644 index 0000000000..448aea44c4 --- /dev/null +++ b/pkg/networkserver/mac/relay_ctrl_uplink_list.go @@ -0,0 +1,171 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/protobuf/proto" +) + +var ( + // EvtEnqueueRelayCtrlUplinkListRequest is emitted when a relay control uplink list request is enqueued. + EvtEnqueueRelayCtrlUplinkListRequest = defineEnqueueMACRequestEvent( + "relay_ctrl_uplink_list", "relay control uplink list", + events.WithDataType(&ttnpb.MACCommand_RelayCtrlUplinkListReq{}), + )() + // EvtReceiveRelayCtrlUplinkListAccept is emitted when a relay control uplink list request is accepted. + EvtReceiveRelayCtrlUplinkListAccept = defineReceiveMACAcceptEvent( + "relay_ctrl_uplink_list", "relay control uplink list", + events.WithDataType(&ttnpb.MACCommand_RelayCtrlUplinkListAns{}), + )() + // EvtReceiveRelayCtrlUplinkListReject is emitted when a relay control uplink list request is rejected. + EvtReceiveRelayCtrlUplinkListReject = defineReceiveMACRejectEvent( + "relay_ctrl_uplink_list", "relay control uplink list", + events.WithDataType(&ttnpb.MACCommand_RelayCtrlUplinkListAns{}), + )() +) + +// DeviceNeedsRelayCtrlUplinkListReqAtIndex returns true iff the device needs a relay +// control uplink list request at the given index. +func DeviceNeedsRelayCtrlUplinkListReqAtIndex(dev *ttnpb.EndDevice, i int) bool { + currentRules := dev.GetMacState().GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules() + desiredRules := dev.GetMacState().GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules() + switch { + case i >= len(currentRules) && i >= len(desiredRules): + case i >= len(desiredRules), proto.Equal(desiredRules[i], emptyRelayUplinkForwardingRule): + // A rule is desired to be deleted. + return !proto.Equal(currentRules[i], emptyRelayUplinkForwardingRule) + case i >= len(currentRules), proto.Equal(currentRules[i], emptyRelayUplinkForwardingRule): + // A rule is desired to be created. + // NOTE: CtrlUplinkListReq cannot delete a forwarding rule. + default: + // NOTE: CtrlUplinkListReq cannot update a forwarding rule. + } + return false +} + +// DeviceNeedsRelayCtrlUplinkListReq returns true iff the device needs a relay control uplink list request. +func DeviceNeedsRelayCtrlUplinkListReq(dev *ttnpb.EndDevice) bool { + if dev.GetMulticast() || dev.GetMacState() == nil { + return false + } + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + desiredServing := dev.MacState.GetDesiredParameters().GetRelay().GetServing() + if desiredServing == nil { + return false + } + for i := range currentServing.GetUplinkForwardingRules() { + if DeviceNeedsRelayCtrlUplinkListReqAtIndex(dev, i) { + return true + } + } + return false +} + +// EnqueueRelayCtrlUplinkListReq enqueues a relay control uplink list request. +func EnqueueRelayCtrlUplinkListReq( + ctx context.Context, dev *ttnpb.EndDevice, maxDownLen, maxUpLen uint16, +) EnqueueState { + if !DeviceNeedsRelayCtrlUplinkListReq(dev) { + return EnqueueState{ + MaxDownLen: maxDownLen, + MaxUpLen: maxUpLen, + Ok: true, + } + } + var st EnqueueState + dev.MacState.PendingRequests, st = enqueueMACCommand( + ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + maxDownLen, maxUpLen, + func(nDown, nUp uint16) ([]*ttnpb.MACCommand, uint16, events.Builders, bool) { + if nDown < 1 || nUp < 1 { + return nil, 0, nil, false + } + currentRules := dev.MacState.GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules() + desiredRules := dev.MacState.DesiredParameters.Relay.GetServing().UplinkForwardingRules + var reqs []*ttnpb.MACCommand_RelayCtrlUplinkListReq + for i := 0; i < len(currentRules); i++ { + switch { + case !DeviceNeedsRelayCtrlUplinkListReqAtIndex(dev, i): + case i >= len(desiredRules), proto.Equal(desiredRules[i], emptyRelayUplinkForwardingRule): + reqs = append(reqs, &ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: uint32(i), + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE, + }) + } + } + cmds := make([]*ttnpb.MACCommand, 0, len(reqs)) + evs := make(events.Builders, 0, len(reqs)) + for _, req := range reqs { + if nDown < 1 || nUp < 1 { + return cmds, uint16(len(cmds)), evs, false + } + nDown-- + nUp-- + log.FromContext(ctx).WithFields(relayCtrlUplinkListReqFields(req)). + Debug("Enqueued RelayCtrlUplinkListReq") + cmds = append(cmds, req.MACCommand()) + evs = append(evs, EvtEnqueueRelayCtrlUplinkListRequest.With(events.WithData(req))) + } + return cmds, uint16(len(cmds)), evs, true + }, + dev.MacState.PendingRequests..., + ) + return st +} + +// HandleRelayCtrlUplinkListAns handles a relay control uplink list answer. +func HandleRelayCtrlUplinkListAns( + _ context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayCtrlUplinkListAns, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + var err error + dev.MacState.PendingRequests, err = handleMACResponse( + ttnpb.MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + false, + func(cmd *ttnpb.MACCommand) error { + if !pld.RuleIndexAck { + return nil + } + req := cmd.GetRelayCtrlUplinkListReq() + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + if currentServing == nil || req.RuleIndex >= uint32(len(currentServing.UplinkForwardingRules)) { + return nil + } + switch req.Action { + case ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT: + case ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE: + currentServing.UplinkForwardingRules[req.RuleIndex] = &ttnpb.RelayUplinkForwardingRule{} + default: + panic("unreachable") + } + return nil + }, + dev.MacState.PendingRequests..., + ) + ev := EvtReceiveRelayCtrlUplinkListAccept + if !pld.RuleIndexAck { + ev = EvtReceiveRelayCtrlUplinkListReject + } + return []events.Builder{ + ev.With(events.WithData(pld)), + }, err +} diff --git a/pkg/networkserver/mac/relay_ctrl_uplink_list_test.go b/pkg/networkserver/mac/relay_ctrl_uplink_list_test.go new file mode 100644 index 0000000000..135c33fd76 --- /dev/null +++ b/pkg/networkserver/mac/relay_ctrl_uplink_list_test.go @@ -0,0 +1,451 @@ +// Copyright © 2023 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 mac_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "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 TestDeviceNeedsRelayCtrlUplinkListReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice *ttnpb.EndDevice + Needs bool + }{ + { + Name: "no MAC state", + InputDevice: &ttnpb.EndDevice{}, + }, + { + Name: "no relay", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + }, + { + Name: "add rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Name: "update rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 12, + + DeviceId: "foo", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + Limits: &ttnpb.RelayUplinkForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_12, + ReloadRate: 24, + }, + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + Name: "remove rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 12, + + DeviceId: "foo", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + { + LastWFCnt: 12, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 12, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + res := mac.DeviceNeedsRelayCtrlUplinkListReq(dev) + if tc.Needs { + a.So(res, should.BeTrue) + } else { + a.So(res, should.BeFalse) + } + a.So(dev, should.Resemble, tc.InputDevice) + }, + }) + } +} + +func TestEnqueueRelayCtrlUplinkListReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice, ExpectedDevice *ttnpb.EndDevice + MaxDownlinkLength uint16 + MaxUplinkLength uint16 + State mac.EnqueueState + }{ + { + Name: "remove rule", + InputDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 24, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 24, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: 0, + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 48, + MaxUpLen: 44, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayCtrlUplinkListRequest.With(events.WithData( + &ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: 0, + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE, + }, + )), + }, + Ok: true, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + st := mac.EnqueueRelayCtrlUplinkListReq(ctx, dev, tc.MaxDownlinkLength, tc.MaxUplinkLength) + a.So(dev, should.Resemble, tc.ExpectedDevice) + a.So(st.QueuedEvents, should.ResembleEventBuilders, tc.State.QueuedEvents) + st.QueuedEvents = tc.State.QueuedEvents + a.So(st, should.Resemble, tc.State) + }, + }) + } +} + +func TestHandleRelayCtrlUplinkListAns(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + Device, Expected *ttnpb.EndDevice + Payload *ttnpb.MACCommand_RelayCtrlUplinkListAns + Events events.Builders + Error error + }{ + { + Name: "remove rule", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayCtrlUplinkListReq{ + RuleIndex: 0, + Action: ttnpb.RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 42, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayCtrlUplinkListAns{ + RuleIndexAck: true, + WFCnt: 0x11223344, + }, + Events: events.Builders{ + mac.EvtReceiveRelayCtrlUplinkListAccept.With(events.WithData( + &ttnpb.MACCommand_RelayCtrlUplinkListAns{ + RuleIndexAck: true, + WFCnt: 0x11223344, + }, + )), + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.Device) + evs, err := mac.HandleRelayCtrlUplinkListAns(ctx, dev, tc.Payload) + if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || + tc.Error == nil && !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(dev, should.Resemble, tc.Expected) + a.So(evs, should.ResembleEventBuilders, tc.Events) + }, + }) + } +} diff --git a/pkg/networkserver/mac/relay_end_device_conf.go b/pkg/networkserver/mac/relay_end_device_conf.go new file mode 100644 index 0000000000..0af64f6ba7 --- /dev/null +++ b/pkg/networkserver/mac/relay_end_device_conf.go @@ -0,0 +1,190 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/protobuf/proto" +) + +var ( + // EvtEnqueueRelayEndDeviceConfRequest is emitted when a relay end device configuration request is enqueued. + EvtEnqueueRelayEndDeviceConfRequest = defineEnqueueMACRequestEvent( + "relay_end_device_conf", "relay end device configuration", + events.WithDataType(&ttnpb.MACCommand_RelayEndDeviceConfReq{}), + )() + // EvtReceiveRelayEndDeviceConfAccept is emitted when a relay end device configuration request is accepted. + EvtReceiveRelayEndDeviceConfAccept = defineReceiveMACAcceptEvent( + "relay_end_device_conf", "relay end device configuration", + events.WithDataType(&ttnpb.MACCommand_RelayEndDeviceConfAns{}), + )() + // EvtReceiveRelayEndDeviceConfReject is emitted when a relay end device configuration request is rejected. + EvtReceiveRelayEndDeviceConfReject = defineReceiveMACRejectEvent( + "relay_end_device_conf", "relay end device configuration", + events.WithDataType(&ttnpb.MACCommand_RelayEndDeviceConfAns{}), + )() +) + +// DeviceNeedsRelayEndDeviceConfReq returns true iff the device needs a relay end device configuration request. +func DeviceNeedsRelayEndDeviceConfReq(dev *ttnpb.EndDevice) bool { + if dev.GetMulticast() || dev.GetMacState() == nil { + return false + } + currentServed := dev.MacState.GetCurrentParameters().GetRelay().GetServed() + desiredServed := dev.MacState.GetDesiredParameters().GetRelay().GetServed() + return !proto.Equal( + &ttnpb.ServedRelayParameters{ + Mode: desiredServed.GetMode(), + Backoff: desiredServed.GetBackoff(), + SecondChannel: desiredServed.GetSecondChannel(), + }, + &ttnpb.ServedRelayParameters{ + Mode: currentServed.GetMode(), + Backoff: currentServed.GetBackoff(), + SecondChannel: currentServed.GetSecondChannel(), + }, + ) +} + +// EnqueueRelayEndDeviceConfReq enqueues a relay end device configuration request if needed. +func EnqueueRelayEndDeviceConfReq(ctx context.Context, dev *ttnpb.EndDevice, maxDownLen, maxUpLen uint16) EnqueueState { + if !DeviceNeedsRelayEndDeviceConfReq(dev) { + return EnqueueState{ + MaxDownLen: maxDownLen, + MaxUpLen: maxUpLen, + Ok: true, + } + } + var st EnqueueState + dev.MacState.PendingRequests, st = enqueueMACCommand( + ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + maxDownLen, maxUpLen, + func(nDown, nUp uint16) ([]*ttnpb.MACCommand, uint16, events.Builders, bool) { + if nDown < 1 || nUp < 1 { + return nil, 0, nil, false + } + desiredServed := dev.MacState.GetDesiredParameters().GetRelay().GetServed() + req := &ttnpb.MACCommand_RelayEndDeviceConfReq{} + if desiredServed != nil { + req.Configuration = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Backoff: desiredServed.Backoff, + SecondChannel: desiredServed.SecondChannel, + ServingDeviceId: desiredServed.ServingDeviceId, + } + switch { + case desiredServed.GetAlways() != nil: + req.Configuration.Mode = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{ + Always: desiredServed.GetAlways(), + } + case desiredServed.GetDynamic() != nil: + req.Configuration.Mode = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic{ + Dynamic: desiredServed.GetDynamic(), + } + case desiredServed.GetEndDeviceControlled() != nil: + req.Configuration.Mode = &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled{ + EndDeviceControlled: desiredServed.GetEndDeviceControlled(), + } + default: + panic("unreachable") + } + } + log.FromContext(ctx).WithFields(servedRelayFields(desiredServed)).Debug("Enqueued RelayEndDeviceConfReq") + return []*ttnpb.MACCommand{ + req.MACCommand(), + }, + 1, + events.Builders{ + EvtEnqueueRelayEndDeviceConfRequest.With(events.WithData(req)), + }, + true + }, + dev.MacState.PendingRequests..., + ) + return st +} + +// HandleRelayEndDeviceConfAns handles a relay end device configuration answer. +func HandleRelayEndDeviceConfAns( + _ context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayEndDeviceConfAns, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + rejected := !pld.SecondChannelFrequencyAck || + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + !pld.SecondChannelDataRateIndexAck || + !pld.SecondChannelIndexAck || + !pld.BackoffAck + var err error + dev.MacState.PendingRequests, err = handleMACResponse( + ttnpb.MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + false, + func(cmd *ttnpb.MACCommand) error { + if rejected { + return nil + } + conf := cmd.GetRelayEndDeviceConfReq().Configuration + currentParameters := dev.MacState.CurrentParameters + if conf == nil { + currentParameters.Relay = nil + return nil + } + relay := currentParameters.Relay + if relay == nil { + relay = &ttnpb.RelayParameters{} + currentParameters.Relay = relay + } + served := relay.GetServed() + if served == nil { + served = &ttnpb.ServedRelayParameters{} + relay.Mode = &ttnpb.RelayParameters_Served{ + Served: served, + } + } + switch { + case conf.GetAlways() != nil: + served.Mode = &ttnpb.ServedRelayParameters_Always{ + Always: conf.GetAlways(), + } + case conf.GetDynamic() != nil: + served.Mode = &ttnpb.ServedRelayParameters_Dynamic{ + Dynamic: conf.GetDynamic(), + } + case conf.GetEndDeviceControlled() != nil: + served.Mode = &ttnpb.ServedRelayParameters_EndDeviceControlled{ + EndDeviceControlled: conf.GetEndDeviceControlled(), + } + default: + panic("unreachable") + } + served.Backoff = conf.Backoff + served.SecondChannel = conf.SecondChannel + served.ServingDeviceId = conf.ServingDeviceId + return nil + }, + dev.MacState.PendingRequests..., + ) + ev := EvtReceiveRelayEndDeviceConfAccept + if rejected { + ev = EvtReceiveRelayEndDeviceConfReject + } + return events.Builders{ + ev.With(events.WithData(pld)), + }, err +} diff --git a/pkg/networkserver/mac/relay_end_device_conf_test.go b/pkg/networkserver/mac/relay_end_device_conf_test.go new file mode 100644 index 0000000000..d9699ae5cd --- /dev/null +++ b/pkg/networkserver/mac/relay_end_device_conf_test.go @@ -0,0 +1,495 @@ +// Copyright © 2023 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 mac_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "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 TestDeviceNeedsRelayEndDeviceConfReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice *ttnpb.EndDevice + Needs bool + }{ + { + Name: "no MAC state", + InputDevice: &ttnpb.EndDevice{}, + }, + { + Name: "no relay", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + }, + { + Name: "disable served", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + Needs: true, + }, + { + Name: "enable served", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "always to dynamic mode", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Dynamic{ + Dynamic: &ttnpb.RelayEndDeviceDynamicMode{ + SmartEnableLevel: ttnpb.RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_32, + }, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + }, + }, + Needs: true, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + res := mac.DeviceNeedsRelayEndDeviceConfReq(dev) + if tc.Needs { + a.So(res, should.BeTrue) + } else { + a.So(res, should.BeFalse) + } + a.So(dev, should.Resemble, tc.InputDevice) + }, + }) + } +} + +func TestEnqueueRelayEndDeviceConfReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice, ExpectedDevice *ttnpb.EndDevice + MaxDownlinkLength uint16 + MaxUplinkLength uint16 + State mac.EnqueueState + }{ + { + Name: "enable served", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 43, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayEndDeviceConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + })), + }, + Ok: true, + }, + }, + { + Name: "disable served", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayEndDeviceConfReq{}).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + State: mac.EnqueueState{ + MaxDownLen: 43, + MaxUpLen: 48, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayEndDeviceConfRequest.With(events.WithData(&ttnpb.MACCommand_RelayEndDeviceConfReq{})), + }, + Ok: true, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + st := mac.EnqueueRelayEndDeviceConfReq(ctx, dev, tc.MaxDownlinkLength, tc.MaxUplinkLength) + a.So(dev, should.Resemble, tc.ExpectedDevice) + a.So(st.QueuedEvents, should.ResembleEventBuilders, tc.State.QueuedEvents) + st.QueuedEvents = tc.State.QueuedEvents + a.So(st, should.Resemble, tc.State) + }, + }) + } +} + +func TestHandleRelayEndDeviceConfAns(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + Device, Expected *ttnpb.EndDevice + Payload *ttnpb.MACCommand_RelayEndDeviceConfAns + Events events.Builders + Error error + }{ + { + Name: "reject served", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: false, + SecondChannelIndexAck: true, + BackoffAck: false, + }, + Events: events.Builders{ + mac.EvtReceiveRelayEndDeviceConfReject.With(events.WithData(&ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: false, + SecondChannelIndexAck: true, + BackoffAck: false, + })), + }, + }, + { + Name: "enable served", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayEndDeviceConfReq{ + Configuration: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration{ + Mode: &ttnpb.MACCommand_RelayEndDeviceConfReq_Configuration_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + BackoffAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayEndDeviceConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + BackoffAck: true, + })), + }, + }, + { + Name: "disable served", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Served{ + Served: &ttnpb.ServedRelayParameters{ + Mode: &ttnpb.ServedRelayParameters_Always{ + Always: &ttnpb.RelayEndDeviceAlwaysMode{}, + }, + ServingDeviceId: "foo", + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{}, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayEndDeviceConfReq{}).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + Payload: &ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + BackoffAck: true, + }, + Events: events.Builders{ + mac.EvtReceiveRelayEndDeviceConfAccept.With(events.WithData(&ttnpb.MACCommand_RelayEndDeviceConfAns{ + SecondChannelFrequencyAck: true, + // NOTE: SecondChannelAckOffsetAck is not defined in the specification. + SecondChannelDataRateIndexAck: true, + SecondChannelIndexAck: true, + BackoffAck: true, + })), + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.Device) + evs, err := mac.HandleRelayEndDeviceConfAns(ctx, dev, tc.Payload) + if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || + tc.Error == nil && !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(dev, should.Resemble, tc.Expected) + a.So(evs, should.ResembleEventBuilders, tc.Events) + }, + }) + } +} diff --git a/pkg/networkserver/mac/relay_notify_new_end_device.go b/pkg/networkserver/mac/relay_notify_new_end_device.go new file mode 100644 index 0000000000..d43a358951 --- /dev/null +++ b/pkg/networkserver/mac/relay_notify_new_end_device.go @@ -0,0 +1,40 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" +) + +// EvtReceiveRelayNotifyNewEndDeviceIndication is emitted when a relay notify new end device +// indication is received. +var EvtReceiveRelayNotifyNewEndDeviceIndication = defineReceiveMACIndicationEvent( + "relay_notify_new_end_device", "relay notify new end device", +)() + +// HandleRelayNotifyNewEndDeviceReq handles a relay notify new end device request. +func HandleRelayNotifyNewEndDeviceReq( + _ context.Context, _ *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayNotifyNewEndDeviceReq, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + return events.Builders{ + EvtReceiveRelayNotifyNewEndDeviceIndication.With(events.WithData(pld)), + }, nil +} diff --git a/pkg/networkserver/mac/relay_update_uplink_list.go b/pkg/networkserver/mac/relay_update_uplink_list.go new file mode 100644 index 0000000000..f6bb1c5104 --- /dev/null +++ b/pkg/networkserver/mac/relay_update_uplink_list.go @@ -0,0 +1,201 @@ +// Copyright © 2023 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 mac + +import ( + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "google.golang.org/protobuf/proto" +) + +var ( + emptyRelayUplinkForwardingRule = &ttnpb.RelayUplinkForwardingRule{} + + // EvtEnqueueRelayUpdateUplinkListRequest is emitted when a relay update uplink list request is enqueued. + EvtEnqueueRelayUpdateUplinkListRequest = defineEnqueueMACRequestEvent( + "relay_update_uplink_list", "relay update uplink list", + events.WithDataType(&ttnpb.MACCommand_RelayUpdateUplinkListReq{}), + )() + // EvtReceiveRelayUpdateUplinkListAnswer is emitted when a relay update uplink list request is answered. + EvtReceiveRelayUpdateUplinkListAnswer = defineReceiveMACAnswerEvent( + "relay_update_uplink_list", "relay update uplink list", + events.WithDataType(&ttnpb.MACCommand_RelayUpdateUplinkListAns{}), + )() +) + +// DeviceNeedsRelayUpdateUplinkListReqAtIndex returns true iff the device needs a relay +// update uplink list request at the given index. +func DeviceNeedsRelayUpdateUplinkListReqAtIndex(dev *ttnpb.EndDevice, i int) bool { + currentRules := dev.GetMacState().GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules() + desiredRules := dev.GetMacState().GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules() + switch { + case i >= len(currentRules) && i >= len(desiredRules): + case i >= len(desiredRules), proto.Equal(desiredRules[i], emptyRelayUplinkForwardingRule): + // A rule is desired to be deleted. + // NOTE: UpdateUplinkListReq cannot delete a forwarding rule. + case i >= len(currentRules), proto.Equal(currentRules[i], emptyRelayUplinkForwardingRule): + // A rule is desired to be created. + return true + default: + // A rule is desired to be updated. + return !proto.Equal(desiredRules[i], currentRules[i]) + } + return false +} + +// DeviceNeedsRelayUpdateUplinkListReq returns true iff the device needs a relay update uplink list request. +func DeviceNeedsRelayUpdateUplinkListReq(dev *ttnpb.EndDevice) bool { + if dev.GetMulticast() || dev.GetMacState() == nil { + return false + } + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + desiredServing := dev.MacState.GetDesiredParameters().GetRelay().GetServing() + if desiredServing == nil { + return false + } + if len(desiredServing.GetUplinkForwardingRules()) > len(currentServing.GetUplinkForwardingRules()) { + return true + } + for i := range desiredServing.GetUplinkForwardingRules() { + if DeviceNeedsRelayUpdateUplinkListReqAtIndex(dev, i) { + return true + } + } + return false +} + +// EnqueueRelayUpdateUplinkListReq enqueues a relay update uplink list request. +func EnqueueRelayUpdateUplinkListReq( + ctx context.Context, dev *ttnpb.EndDevice, maxDownLen, maxUpLen uint16, keyService RelayKeyService, +) EnqueueState { + if !DeviceNeedsRelayUpdateUplinkListReq(dev) { + return EnqueueState{ + MaxDownLen: maxDownLen, + MaxUpLen: maxUpLen, + Ok: true, + } + } + var st EnqueueState + dev.MacState.PendingRequests, st = enqueueMACCommand( + ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + maxDownLen, maxUpLen, + func(nDown, nUp uint16) ([]*ttnpb.MACCommand, uint16, events.Builders, bool) { + if nDown < 1 || nUp < 1 { + return nil, 0, nil, false + } + currentRules := dev.MacState.GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules() + desiredRules := dev.MacState.DesiredParameters.Relay.GetServing().UplinkForwardingRules + pendingRuleIndices := make([]int, 0, len(desiredRules)) + pendingDeviceIDs := make([]string, 0, len(desiredRules)) + pendingSessionKeyIDs := make([][]byte, 0, len(desiredRules)) + var reqs []*ttnpb.MACCommand_RelayUpdateUplinkListReq + for i := 0; i < len(desiredRules) || i < len(currentRules); i++ { + if DeviceNeedsRelayUpdateUplinkListReqAtIndex(dev, i) { + pendingRuleIndices = append(pendingRuleIndices, i) + pendingDeviceIDs = append(pendingDeviceIDs, desiredRules[i].DeviceId) + pendingSessionKeyIDs = append(pendingSessionKeyIDs, desiredRules[i].SessionKeyId) + } + } + devAddrs, keys, err := keyService.BatchDeriveRootWorSKey( + ctx, dev.Ids.ApplicationIds, pendingDeviceIDs, pendingSessionKeyIDs, + ) + if err != nil { + log.FromContext(ctx).WithError(err).Warn("Root relay session keys derivation failed") + return nil, 0, nil, true + } + for i, ruleIdx := range pendingRuleIndices { + if devAddrs[i] == nil || keys[i] == nil { + continue + } + desiredRule := desiredRules[ruleIdx] + reqs = append(reqs, &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: uint32(ruleIdx), + ForwardLimits: desiredRule.Limits, + DevAddr: devAddrs[i][:], + WFCnt: desiredRule.LastWFCnt, + RootWorSKey: keys[i][:], + + DeviceId: desiredRule.DeviceId, + SessionKeyId: desiredRule.SessionKeyId, + }) + } + cmds := make([]*ttnpb.MACCommand, 0, len(reqs)) + evs := make(events.Builders, 0, len(reqs)) + for _, req := range reqs { + if nDown < 1 || nUp < 1 { + return cmds, uint16(len(cmds)), evs, false + } + nDown-- + nUp-- + log.FromContext(ctx).WithFields(relayUpdateUplinkListReqFields(req)). + Debug("Enqueued RelayUpdateUplinkListReq") + cmds = append(cmds, req.MACCommand()) + evs = append(evs, EvtEnqueueRelayUpdateUplinkListRequest.With(events.WithData(req.Sanitized()))) + } + return cmds, uint16(len(cmds)), evs, true + }, + dev.MacState.PendingRequests..., + ) + return st +} + +// HandleRelayUpdateUplinkListAns handles a relay update uplink list answer. +func HandleRelayUpdateUplinkListAns( + _ context.Context, dev *ttnpb.EndDevice, pld *ttnpb.MACCommand_RelayUpdateUplinkListAns, +) (events.Builders, error) { + if pld == nil { + return nil, ErrNoPayload.New() + } + var err error + dev.MacState.PendingRequests, err = handleMACResponse( + ttnpb.MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + false, + func(cmd *ttnpb.MACCommand) error { + req := cmd.GetRelayUpdateUplinkListReq() + currentServing := dev.MacState.GetCurrentParameters().GetRelay().GetServing() + if currentServing == nil { + // NOTE: EnqueueRelayUpdateUplinkListReq is optimistic and assumes that EnqueueRelayConfReq + // has enqueued the desired relay parameters, and that the end device will accept them. If + // either of these conditions is not true, the current serving parameters will be nil. + return nil + } + if n := len(currentServing.UplinkForwardingRules); uint(req.RuleIndex) >= uint(n) { + currentServing.UplinkForwardingRules = append( + currentServing.UplinkForwardingRules, + make( + []*ttnpb.RelayUplinkForwardingRule, + 1+int(req.RuleIndex-uint32(n)), + )..., + ) + for i := n; i < len(currentServing.UplinkForwardingRules); i++ { + currentServing.UplinkForwardingRules[i] = &ttnpb.RelayUplinkForwardingRule{} + } + } + rule := currentServing.UplinkForwardingRules[req.RuleIndex] + rule.Limits = req.ForwardLimits + rule.LastWFCnt = req.WFCnt + rule.DeviceId = req.DeviceId + rule.SessionKeyId = req.SessionKeyId + return nil + }, + dev.MacState.PendingRequests..., + ) + return []events.Builder{ + EvtReceiveRelayUpdateUplinkListAnswer.With(events.WithData(pld)), + }, err +} diff --git a/pkg/networkserver/mac/relay_update_uplink_list_test.go b/pkg/networkserver/mac/relay_update_uplink_list_test.go new file mode 100644 index 0000000000..32a7bdb9bd --- /dev/null +++ b/pkg/networkserver/mac/relay_update_uplink_list_test.go @@ -0,0 +1,670 @@ +// Copyright © 2023 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 mac_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/types" + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +type relayKeyServiceFunc func( + context.Context, *ttnpb.ApplicationIdentifiers, []string, [][]byte, +) ([]*types.DevAddr, []*types.AES128Key, error) + +var _ (mac.RelayKeyService) = relayKeyServiceFunc(nil) + +// BatchDeriveRootWorSKey implements mac.RelayKeyService. +func (f relayKeyServiceFunc) BatchDeriveRootWorSKey( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, deviceIDs []string, sessionKeyIDs [][]byte, +) ([]*types.DevAddr, []*types.AES128Key, error) { + return f(ctx, appID, deviceIDs, sessionKeyIDs) +} + +func TestDeviceNeedsRelayUpdateUplinkListReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice *ttnpb.EndDevice + Needs bool + }{ + { + Name: "no MAC state", + InputDevice: &ttnpb.EndDevice{}, + }, + { + Name: "no relay", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{}, + }, + }, + }, + { + Name: "add rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "update rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 12, + + DeviceId: "foo", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + Limits: &ttnpb.RelayUplinkForwardLimits{ + BucketSize: ttnpb.RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_12, + ReloadRate: 24, + }, + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + Needs: true, + }, + { + Name: "remove rule", + InputDevice: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 12, + + DeviceId: "foo", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + { + LastWFCnt: 12, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + {}, + { + LastWFCnt: 12, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + res := mac.DeviceNeedsRelayUpdateUplinkListReq(dev) + if tc.Needs { + a.So(res, should.BeTrue) + } else { + a.So(res, should.BeFalse) + } + a.So(dev, should.Resemble, tc.InputDevice) + }, + }) + } +} + +func TestEnqueueRelayUpdateUplinkListReq(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + InputDevice, ExpectedDevice *ttnpb.EndDevice + MaxDownlinkLength uint16 + MaxUplinkLength uint16 + RelayKeyService relayKeyServiceFunc + State mac.EnqueueState + }{ + { + Name: "add rule", + InputDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{}, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 0, + DevAddr: types.DevAddr{0x42, 0x43, 0x44, 0x45}.Bytes(), + WFCnt: 42, + RootWorSKey: types.AES128Key{0x01, 0x02, 0x03, 0x04}.Bytes(), + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + RelayKeyService: func( + context.Context, *ttnpb.ApplicationIdentifiers, []string, [][]byte, + ) ([]*types.DevAddr, []*types.AES128Key, error) { + return []*types.DevAddr{{0x42, 0x43, 0x44, 0x45}}, []*types.AES128Key{{0x01, 0x02, 0x03, 0x04}}, nil + }, + State: mac.EnqueueState{ + MaxDownLen: 23, + MaxUpLen: 49, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayUpdateUplinkListRequest.With(events.WithData( + &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 0, + DevAddr: types.DevAddr{0x42, 0x43, 0x44, 0x45}.Bytes(), + WFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + )), + }, + Ok: true, + }, + }, + { + Name: "update rule", + InputDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 24, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + }, + }, + ExpectedDevice: &ttnpb.EndDevice{ + Ids: test.MakeEndDeviceIdentifiers(), + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 24, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 1, + DevAddr: types.DevAddr{0x43, 0x44, 0x45, 0x46}.Bytes(), + WFCnt: 42, + RootWorSKey: types.AES128Key{0x02, 0x03, 0x04, 0x05}.Bytes(), + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }).MACCommand(), + }, + }, + }, + MaxDownlinkLength: 50, + MaxUplinkLength: 50, + RelayKeyService: func( + context.Context, *ttnpb.ApplicationIdentifiers, []string, [][]byte, + ) ([]*types.DevAddr, []*types.AES128Key, error) { + return []*types.DevAddr{{0x43, 0x44, 0x45, 0x46}}, []*types.AES128Key{{0x02, 0x03, 0x04, 0x05}}, nil + }, + State: mac.EnqueueState{ + MaxDownLen: 23, + MaxUpLen: 49, + QueuedEvents: events.Builders{ + mac.EvtEnqueueRelayUpdateUplinkListRequest.With(events.WithData( + &ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 1, + DevAddr: types.DevAddr{0x43, 0x44, 0x45, 0x46}.Bytes(), + WFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + )), + }, + Ok: true, + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.InputDevice) + st := mac.EnqueueRelayUpdateUplinkListReq( + ctx, dev, tc.MaxDownlinkLength, tc.MaxUplinkLength, tc.RelayKeyService, + ) + a.So(dev, should.Resemble, tc.ExpectedDevice) + a.So(st.QueuedEvents, should.ResembleEventBuilders, tc.State.QueuedEvents) + st.QueuedEvents = tc.State.QueuedEvents + a.So(st, should.Resemble, tc.State) + }, + }) + } +} + +func TestHandleRelayUpdateUplinkListAns(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + Name string + Device, Expected *ttnpb.EndDevice + Payload *ttnpb.MACCommand_RelayUpdateUplinkListAns + Events events.Builders + Error error + }{ + { + Name: "add rule", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{}, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 0, + DevAddr: types.DevAddr{0x42, 0x43, 0x44, 0x45}.Bytes(), + WFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + }, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + Events: events.Builders{ + mac.EvtReceiveRelayUpdateUplinkListAnswer.With(events.WithData( + &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + )), + }, + }, + { + Name: "update rule", + Device: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 24, + + DeviceId: "bar", + SessionKeyId: []byte{0x02, 0x03, 0x04}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + PendingRequests: []*ttnpb.MACCommand{ + (&ttnpb.MACCommand_RelayUpdateUplinkListReq{ + RuleIndex: 1, + DevAddr: types.DevAddr{0x43, 0x44, 0x45, 0x46}.Bytes(), + WFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }).MACCommand(), + }, + }, + }, + Expected: &ttnpb.EndDevice{ + MacState: &ttnpb.MACState{ + CurrentParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + DesiredParameters: &ttnpb.MACParameters{ + Relay: &ttnpb.RelayParameters{ + Mode: &ttnpb.RelayParameters_Serving{ + Serving: &ttnpb.ServingRelayParameters{ + UplinkForwardingRules: []*ttnpb.RelayUplinkForwardingRule{ + { + LastWFCnt: 42, + + DeviceId: "foo", + SessionKeyId: []byte{0x01, 0x02, 0x03}, + }, + { + LastWFCnt: 42, + + DeviceId: "foobar", + SessionKeyId: []byte{0x03, 0x04, 0x05}, + }, + }, + }, + }, + }, + }, + }, + }, + Payload: &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + Events: events.Builders{ + mac.EvtReceiveRelayUpdateUplinkListAnswer.With(events.WithData( + &ttnpb.MACCommand_RelayUpdateUplinkListAns{}, + )), + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + dev := ttnpb.Clone(tc.Device) + evs, err := mac.HandleRelayUpdateUplinkListAns(ctx, dev, tc.Payload) + if tc.Error != nil && !a.So(err, should.EqualErrorOrDefinition, tc.Error) || + tc.Error == nil && !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(dev, should.Resemble, tc.Expected) + a.So(evs, should.ResembleEventBuilders, tc.Events) + }, + }) + } +} diff --git a/pkg/networkserver/mac/utils.go b/pkg/networkserver/mac/utils.go index 50269c9331..922fc5c227 100644 --- a/pkg/networkserver/mac/utils.go +++ b/pkg/networkserver/mac/utils.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "math" + "slices" "go.thethings.network/lorawan-stack/v3/pkg/band" "go.thethings.network/lorawan-stack/v3/pkg/crypto" @@ -31,7 +32,6 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/specification/macspec" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/types" - "golang.org/x/exp/slices" ) func channelDataRateRange( @@ -713,6 +713,7 @@ func NewState(dev *ttnpb.EndDevice, fps *frequencyplans.Store, defaults *ttnpb.M AdrAckLimitExponent: &ttnpb.ADRAckLimitExponentValue{Value: phy.ADRAckLimit}, AdrAckDelayExponent: &ttnpb.ADRAckDelayExponentValue{Value: phy.ADRAckDelay}, PingSlotDataRateIndexValue: DeviceDefaultPingSlotDataRateIndexValue(dev, phy, defaults), + Relay: DeviceDefaultRelayParameters(dev, defaults), } desired := current if !dev.Multicast { @@ -735,6 +736,7 @@ func NewState(dev *ttnpb.EndDevice, fps *frequencyplans.Store, defaults *ttnpb.M AdrAckLimitExponent: DeviceDesiredADRAckLimitExponent(dev, phy, defaults), AdrAckDelayExponent: DeviceDesiredADRAckDelayExponent(dev, phy, defaults), PingSlotDataRateIndexValue: DeviceDesiredPingSlotDataRateIndexValue(dev, phy, fp, defaults), + Relay: DeviceDesiredRelayParameters(dev, defaults), } } // TODO: Support rejoins. (https://github.com/TheThingsNetwork/lorawan-stack/issues/8) diff --git a/pkg/networkserver/networkserver.go b/pkg/networkserver/networkserver.go index 8ff73d33ea..306df5244b 100644 --- a/pkg/networkserver/networkserver.go +++ b/pkg/networkserver/networkserver.go @@ -20,7 +20,6 @@ import ( "crypto/rand" "fmt" "os" - "sync" "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "go.thethings.network/lorawan-stack/v3/pkg/cluster" @@ -167,7 +166,6 @@ type NetworkServer struct { newDevAddr newDevAddrFunc devAddrPrefixes devAddrPrefixesFunc - applicationServers *sync.Map // string -> *applicationUpStream applicationUplinks ApplicationUplinkQueue downlinkTasks DownlinkTaskQueue @@ -282,7 +280,6 @@ func New(c *component.Component, conf *Config, opts ...Option) (*NetworkServer, clusterID: conf.ClusterID, newDevAddr: makeNewDevAddrFunc(devAddrPrefixes...), devAddrPrefixes: makeDevAddrPrefixesFunc(devAddrPrefixes...), - applicationServers: &sync.Map{}, applicationUplinks: conf.ApplicationUplinkQueue.Queue, deduplicationWindow: makeWindowDurationFunc(conf.DeduplicationWindow), collectionWindow: makeWindowDurationFunc(conf.DeduplicationWindow + conf.CooldownWindow), @@ -349,8 +346,7 @@ func New(c *component.Component, conf *Config, opts ...Option) (*NetworkServer, for id, dispatcher := range map[string]interface { Dispatch(context.Context, string) error }{ - downlinkDispatchTaskName: ns.downlinkTasks, - applicationUplinkDispatchTaskName: ns.applicationUplinks, + downlinkDispatchTaskName: ns.downlinkTasks, } { dispatcher := dispatcher ns.RegisterTask(&task.Config{ diff --git a/pkg/networkserver/networkserver_util_internal_test.go b/pkg/networkserver/networkserver_util_internal_test.go index 4c615527ed..dd7f1dc7cc 100644 --- a/pkg/networkserver/networkserver_util_internal_test.go +++ b/pkg/networkserver/networkserver_util_internal_test.go @@ -2523,6 +2523,12 @@ type MockDeviceRegistry struct { paths []string, f func(context.Context, *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), ) (*ttnpb.EndDevice, context.Context, error) + BatchGetByIDFunc func( + ctx context.Context, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) BatchDeleteFunc func( ctx context.Context, appIDs *ttnpb.ApplicationIdentifiers, @@ -2561,6 +2567,16 @@ func (m MockDeviceRegistry) Range(ctx context.Context, paths []string, f func(co panic("Range must not be called") } +// BatchGetByID panics. +func (m MockDeviceRegistry) BatchGetByID( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, devIDs []string, paths []string, +) ([]*ttnpb.EndDevice, error) { + if m.BatchGetByIDFunc == nil { + panic("BatchGetByIDFunc called, but not set") + } + return m.BatchGetByIDFunc(ctx, appID, devIDs, paths) +} + // GetByID calls GetByIDFunc if set and panics otherwise. func (m MockDeviceRegistry) BatchDelete( ctx context.Context, diff --git a/pkg/networkserver/observability.go b/pkg/networkserver/observability.go index d2f3acbeb6..53777c2743 100644 --- a/pkg/networkserver/observability.go +++ b/pkg/networkserver/observability.go @@ -56,6 +56,16 @@ var ( Up: &ttnpb.ApplicationUp_UplinkMessage{UplinkMessage: &ttnpb.ApplicationUplink{}}, }), ) + evtDropRelayUplink = events.Define( + "ns.up.relay.drop", "drop relay message", + events.WithVisibility(ttnpb.Right_RIGHT_APPLICATION_TRAFFIC_READ), + events.WithErrorDataType(), + ) + evtProcessRelayUplink = events.Define( + "ns.up.relay.process", "successfully processed relay message", + events.WithVisibility(ttnpb.Right_RIGHT_APPLICATION_TRAFFIC_READ), + events.WithDataType(&ttnpb.UplinkMessage{}), + ) evtScheduleDataDownlinkAttempt = events.Define( "ns.down.data.schedule.attempt", "schedule data downlink for transmission on Gateway Server", events.WithVisibility(ttnpb.Right_RIGHT_APPLICATION_TRAFFIC_READ), diff --git a/pkg/networkserver/redis/application_uplink_queue.go b/pkg/networkserver/redis/application_uplink_queue.go index 87630eca76..ec9042ab8a 100644 --- a/pkg/networkserver/redis/application_uplink_queue.go +++ b/pkg/networkserver/redis/application_uplink_queue.go @@ -16,51 +16,59 @@ package redis import ( "context" + "sync" "github.com/redis/go-redis/v9" "go.thethings.network/lorawan-stack/v3/pkg/errors" - "go.thethings.network/lorawan-stack/v3/pkg/networkserver" + "go.thethings.network/lorawan-stack/v3/pkg/log" "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal/time" 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" ) -type ApplicationUplinkQueue struct { - applicationQueue *ttnredis.TaskQueue - - redis *ttnredis.Client - maxLen int64 - group string - key string - minIdle time.Duration +type contextualUplinkBatch struct { + ctx context.Context + confirmIDs []string + uplinks []*ttnpb.ApplicationUp } const ( - payloadKey = "payload" + payloadKey = "payload" + payloadUIDKey = "uid" +) + +var ( + errMissingPayload = errors.DefineDataLoss("missing_payload", "missing payload") + errInvalidPayload = errors.DefineCorruption("invalid_payload", "invalid payload") + errMissingUID = errors.DefineDataLoss("missing_uid", "missing UID") + errInvalidUID = errors.DefineCorruption("invalid_uid", "invalid UID") ) +// ApplicationUplinkQueue is an implementation of ApplicationUplinkQueue. +type ApplicationUplinkQueue struct { + redis *ttnredis.Client + maxLen int64 + groupID string + streamID string + minIdle time.Duration + consumers sync.Map +} + // NewApplicationUplinkQueue returns new application uplink queue. func NewApplicationUplinkQueue( cl *ttnredis.Client, maxLen int64, - group string, + groupID string, minIdle time.Duration, - streamBlockLimit time.Duration, ) *ApplicationUplinkQueue { return &ApplicationUplinkQueue{ - applicationQueue: &ttnredis.TaskQueue{ - Redis: cl, - MaxLen: maxLen, - Group: group, - Key: cl.Key("application"), - StreamBlockLimit: streamBlockLimit, - }, - redis: cl, - maxLen: maxLen, - group: group, - key: cl.Key("application-uplink"), - minIdle: minIdle, + redis: cl, + maxLen: maxLen, + groupID: groupID, + streamID: cl.Key("uplinks"), + minIdle: minIdle, + consumers: sync.Map{}, } } @@ -68,68 +76,48 @@ func ApplicationUplinkQueueUIDGenericUplinkKey(r keyer, uid string) string { return ttnredis.Key(UIDKey(r, uid), "uplinks") } -func (q *ApplicationUplinkQueue) uidGenericUplinkKey(uid string) string { - return ApplicationUplinkQueueUIDGenericUplinkKey(q.redis, uid) -} - -func (q *ApplicationUplinkQueue) uidInvalidationKey(uid string) string { - return ttnredis.Key(q.uidGenericUplinkKey(uid), "invalidation") -} - -func (q *ApplicationUplinkQueue) uidJoinAcceptKey(uid string) string { - return ttnredis.Key(q.uidGenericUplinkKey(uid), "join-accept") -} - // Init initializes the ApplicationUplinkQueue. func (q *ApplicationUplinkQueue) Init(ctx context.Context) error { - return q.applicationQueue.Init(ctx) + cmd := q.redis.XGroupCreateMkStream(ctx, q.streamID, q.groupID, "0") + if err := cmd.Err(); err != nil && !ttnredis.IsConsumerGroupExistsErr(err) { + return ttnredis.ConvertError(err) + } + return nil } -// Close closes the ApplicationUplinkQueue. +// Close removes all consumers from the consumer group. func (q *ApplicationUplinkQueue) Close(ctx context.Context) error { - return q.applicationQueue.Close(ctx) + pipeline := q.redis.Pipeline() + q.consumers.Range(func(key, value any) bool { + pipeline.XGroupDelConsumer(ctx, q.streamID, q.groupID, key.(string)) + return true + }) + if _, err := pipeline.Exec(ctx); err != nil { + return ttnredis.ConvertError(err) + } + return nil } +// Add implements ApplicationUplinkQueue interface. func (q *ApplicationUplinkQueue) Add(ctx context.Context, ups ...*ttnpb.ApplicationUp) error { if len(ups) == 0 { return nil } _, err := q.redis.Pipelined(ctx, func(p redis.Pipeliner) error { - now := time.Now() - taskMap := map[string]time.Time{} for _, up := range ups { - uid := unique.ID(ctx, up.EndDeviceIds.ApplicationIds) - s, err := ttnredis.MarshalProto(up) if err != nil { return err } - - var uidStreamID string - switch up.Up.(type) { - case *ttnpb.ApplicationUp_JoinAccept: - uidStreamID = q.uidJoinAcceptKey(uid) - case *ttnpb.ApplicationUp_DownlinkQueueInvalidated: - uidStreamID = q.uidInvalidationKey(uid) - default: - uidStreamID = q.uidGenericUplinkKey(uid) - } p.XAdd(ctx, &redis.XAddArgs{ - Stream: uidStreamID, + Stream: q.streamID, MaxLen: q.maxLen, Approx: true, Values: map[string]any{ - payloadKey: s, + payloadUIDKey: unique.ID(ctx, up.EndDeviceIds), + payloadKey: s, }, }) - if _, ok := taskMap[uid]; !ok { - taskMap[uid] = now - } - } - for uid, t := range taskMap { - if err := q.applicationQueue.Add(ctx, p, uid, t, false); err != nil { - return err - } } return nil }) @@ -139,83 +127,111 @@ func (q *ApplicationUplinkQueue) Add(ctx context.Context, ups ...*ttnpb.Applicat return nil } -var ( - errInvalidPayload = errors.DefineCorruption("invalid_payload", "invalid payload") - errMissingPayload = errors.DefineDataLoss("missing_payload", "missing payload") -) +func uidStrFrom(values map[string]any) (string, error) { + uidValue, ok := values[payloadUIDKey] + if !ok { + return "", errMissingUID.New() + } + uid, ok := uidValue.(string) + if !ok { + return "", errInvalidUID.New() + } + return uid, nil +} + +func applicationUpFrom(values map[string]any) (*ttnpb.ApplicationUp, error) { + payloadValue, ok := values[payloadKey] + if !ok { + return nil, errMissingPayload.New() + } + payload, ok := payloadValue.(string) + if !ok { + return nil, errInvalidPayload.New() + } + up := &ttnpb.ApplicationUp{} + if err := ttnredis.UnmarshalProto(payload, up); err != nil { + return nil, errInvalidPayload.WithCause(err) + } + return up, nil +} -func (q *ApplicationUplinkQueue) Dispatch(ctx context.Context, consumerID string) error { - return q.applicationQueue.Dispatch(ctx, consumerID, nil) +func addToBatch( + ctx context.Context, + m map[string]*contextualUplinkBatch, + confirmID string, + uid string, + up *ttnpb.ApplicationUp, +) error { + ctx, err := unique.WithContext(ctx, uid) + if err != nil { + return errInvalidUID.WithCause(err) + } + ids, err := unique.ToDeviceID(uid) + if err != nil { + return errInvalidUID.WithCause(err) + } + key := unique.ID(ctx, ids.ApplicationIds) + batch, ok := m[key] + if !ok { + batch = &contextualUplinkBatch{ + ctx: ctx, + confirmIDs: make([]string, 0), + uplinks: make([]*ttnpb.ApplicationUp, 0), + } + m[key] = batch + } + batch.uplinks = append(batch.uplinks, up) + batch.confirmIDs = append(batch.confirmIDs, confirmID) + return nil } -func (q *ApplicationUplinkQueue) Pop(ctx context.Context, consumerID string, f func(context.Context, *ttnpb.ApplicationIdentifiers, networkserver.ApplicationUplinkQueueDrainFunc) (time.Time, error)) error { - return q.applicationQueue.Pop(ctx, consumerID, nil, func(p redis.Pipeliner, uid string, _ time.Time) error { - appID, err := unique.ToApplicationID(uid) +func (*ApplicationUplinkQueue) processMessages( + ctx context.Context, + msgs []redis.XMessage, + ack func(...string) error, + f func(context.Context, []*ttnpb.ApplicationUp) error, +) error { + batches := map[string]*contextualUplinkBatch{} + for _, msg := range msgs { + uid, err := uidStrFrom(msg.Values) if err != nil { return err } - ctx, err := unique.WithContext(ctx, uid) + up, err := applicationUpFrom(msg.Values) if err != nil { return err } - joinAcceptUpStream := q.uidJoinAcceptKey(uid) - invalidationUpStream := q.uidInvalidationKey(uid) - genericUpStream := q.uidGenericUplinkKey(uid) - - streams := [...]string{ - joinAcceptUpStream, - invalidationUpStream, - genericUpStream, - } - - cmds, err := q.redis.Pipelined(ctx, func(pp redis.Pipeliner) error { - for _, stream := range streams { - pp.XGroupCreateMkStream(ctx, stream, q.group, "0") - } - return nil - }) - if err != nil && !ttnredis.IsConsumerGroupExistsErr(err) { - return ttnredis.ConvertError(err) - } - var initErr error - for i, cmd := range cmds { - if err := cmd.Err(); err != nil && !ttnredis.IsConsumerGroupExistsErr(err) { - initErr = err - continue - } - p.XGroupDelConsumer(ctx, streams[i], q.group, consumerID) + if err := addToBatch(ctx, batches, msg.ID, uid, up); err != nil { + return err } - if initErr != nil { - return ttnredis.ConvertError(initErr) + } + processedIDs := make([]string, 0, len(msgs)) + for _, batch := range batches { + if err := f(batch.ctx, batch.uplinks); err != nil { + log.FromContext(ctx).WithError(err).Warn("Failed to process uplink batch") + continue // Do not confirm messages that failed to process. } + processedIDs = append(processedIDs, batch.confirmIDs...) + } + return ack(processedIDs...) +} - t, err := f(ctx, appID, func(limit int, g func(...*ttnpb.ApplicationUp) error) error { - ups := make([]*ttnpb.ApplicationUp, 0, limit) - - processMessages := func(stream string, msgs ...redis.XMessage) error { - ups = ups[:0] - for _, msg := range msgs { - v, ok := msg.Values[payloadKey] - if !ok { - return errMissingPayload.New() - } - s, ok := v.(string) - if !ok { - return errInvalidPayload.New() - } - up := &ttnpb.ApplicationUp{} - if err = ttnredis.UnmarshalProto(s, up); err != nil { - return err - } - ups = append(ups, up) - } - return g(ups...) - } - return ttnredis.RangeStreams(ctx, q.redis, q.group, consumerID, int64(limit), q.minIdle, processMessages, streams[:]...) - }) - if err != nil || t.IsZero() { - return err - } - return q.applicationQueue.Add(ctx, p, uid, t, true) - }) +// Pop implements ApplicationUplinkQueue interface. +func (q *ApplicationUplinkQueue) Pop( + ctx context.Context, consumerID string, limit int, + f func(context.Context, []*ttnpb.ApplicationUp) error, +) error { + q.consumers.Store(consumerID, struct{}{}) + return ttnredis.RangeStreams( + ctx, + q.redis, + q.groupID, + consumerID, + int64(limit), + q.minIdle, + func(_ string, ack func(...string) error, msgs ...redis.XMessage) error { + return q.processMessages(ctx, msgs, ack, f) + }, + q.streamID, + ) } diff --git a/pkg/networkserver/redis/application_uplink_queue_test.go b/pkg/networkserver/redis/application_uplink_queue_test.go index 4b5adc0a04..f66834ebca 100644 --- a/pkg/networkserver/redis/application_uplink_queue_test.go +++ b/pkg/networkserver/redis/application_uplink_queue_test.go @@ -15,28 +15,417 @@ package redis_test import ( + "context" "fmt" + "sync" "testing" + "time" + "github.com/redis/go-redis/v9" + "github.com/smarty/assertions" "go.thethings.network/lorawan-stack/v3/pkg/networkserver" - . "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal/test/shared" - . "go.thethings.network/lorawan-stack/v3/pkg/networkserver/redis" + nsredis "go.thethings.network/lorawan-stack/v3/pkg/networkserver/redis" + 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" "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" ) -var _ networkserver.ApplicationUplinkQueue = &ApplicationUplinkQueue{} - -func TestApplicationUplinkQueue(t *testing.T) { - for _, consumers := range []int{1, 2, 4, 8} { - t.Run(fmt.Sprintf("Consumers=%d", consumers), func(t *testing.T) { - _, ctx := test.New(t) - consumerIDs := make([]string, 0, consumers) - for i := 0; i < consumers; i++ { - consumerIDs = append(consumerIDs, fmt.Sprintf("consumer-%d-%d", consumers, i)) - } - q, closeFn := NewRedisApplicationUplinkQueue(ctx) - defer closeFn() - HandleApplicationUplinkQueueTest(t, q, consumerIDs) - }) +var _ networkserver.ApplicationUplinkQueue = &nsredis.ApplicationUplinkQueue{} + +var ( + redisNamespace = [...]string{ + "redis_test_uplink_queue", + } + readLimit = 7 + maxLen = int64(100) + groupID = "ns-test" + minIdle = (1 << 8) * test.Delay + + appCount = 5 + devCountPerApp = 3 +) + +func setupRedisApplicationUplinkQueue( + t *testing.T, cl *ttnredis.Client, minIdle time.Duration, +) (*nsredis.ApplicationUplinkQueue, func()) { + t.Helper() + + _, ctx := test.New(t) + + q := nsredis.NewApplicationUplinkQueue(cl, maxLen, groupID, minIdle) + + return q, func() { + if err := q.Close(ctx); err != nil { + t.Errorf("Failed to close Redis application uplink queue: %s", err) + } + } +} + +func TestApplicationUplinkQueueInit(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "init")...) + t.Cleanup(redisCloseFn) + + q, qCloseFn := setupRedisApplicationUplinkQueue(t, cl, minIdle) + t.Cleanup(qCloseFn) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + streamID := cl.Key("uplinks") + groups, err := cl.XInfoGroups(ctx, streamID).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(groups, should.HaveLength, 1) + a.So(groups[0].Name, should.Equal, groupID) + a.So(groups[0].Consumers, should.Equal, 0) +} + +func TestApplicationUplinkQueueClose(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "close")...) + t.Cleanup(redisCloseFn) + + q, _ := setupRedisApplicationUplinkQueue(t, cl, minIdle) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + consumerIDs := []string{"test-consumer-1", "test-consumer-2"} + up := &ttnpb.ApplicationUp{ + EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ + DeviceId: "test-device", + ApplicationIds: &ttnpb.ApplicationIdentifiers{ + ApplicationId: "test-application", + }, + }, + } + for _, consumerID := range consumerIDs { + if err := q.Add(ctx, up); !a.So(err, should.BeNil) { + t.FailNow() + } + if err := q.Pop(ctx, consumerID, 1, func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + return nil + }); !a.So(err, should.BeNil) { + t.FailNow() + } + } + + streamID := cl.Key("uplinks") + consumers, err := cl.XInfoConsumers(ctx, streamID, groupID).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(consumers, should.HaveLength, 2) + + if !a.So(q.Close(ctx), should.BeNil) { + t.FailNow() + } + + consumers, err = cl.XInfoConsumers(ctx, streamID, groupID).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(consumers, should.HaveLength, 0) +} + +func generateRandomUplinks(t *testing.T, applicationCount, deviceCount int) []*ttnpb.ApplicationUp { + t.Helper() + + ups := make([]*ttnpb.ApplicationUp, 0, applicationCount*deviceCount) + for i := 0; i < applicationCount; i++ { + applicationID := fmt.Sprintf("test-application-%d", i) + for j := 0; j < deviceCount; j++ { + deviceID := fmt.Sprintf("test-device-%d", j) + ups = append(ups, &ttnpb.ApplicationUp{ + EndDeviceIds: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: &ttnpb.ApplicationIdentifiers{ + ApplicationId: applicationID, + }, + DeviceId: deviceID, + }, + }) + } + } + return ups +} + +func assertAllEqualAppIDs(t *testing.T, ups []*ttnpb.ApplicationUp) { + t.Helper() + + a := assertions.New(t) + if !a.So(ups, should.NotBeEmpty) { + t.FailNow() + } + + expected := ups[0].EndDeviceIds.ApplicationIds + for _, up := range ups[1:] { + actual := up.EndDeviceIds.ApplicationIds + if !a.So(actual, should.Resemble, expected) { + t.FailNow() + } + } +} + +func assertStreamUplinkCount(t *testing.T, cl *ttnredis.Client, expected int) { + t.Helper() + + a, ctx := test.New(t) + streamID := cl.Key("uplinks") + entries, err := cl.XRange(ctx, streamID, "-", "+").Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(entries, should.HaveLength, expected) +} + +func TestApplicationUplinkQueueAdd(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "add")...) + t.Cleanup(redisCloseFn) + + q, qCloseFn := setupRedisApplicationUplinkQueue(t, cl, minIdle) + t.Cleanup(qCloseFn) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + expectedUps := generateRandomUplinks(t, appCount, devCountPerApp) + expectedUIDs := make([]string, 0, len(expectedUps)) + for _, up := range expectedUps { + expectedUIDs = append(expectedUIDs, unique.ID(ctx, up.EndDeviceIds)) } + + if err := q.Add(ctx, expectedUps...); !a.So(err, should.BeNil) { + t.FailNow() + } + + streamID := cl.Key("uplinks") + entries, err := cl.XRange(ctx, streamID, "-", "+").Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + if !a.So(entries, should.HaveLength, len(expectedUps)) { + t.FailNow() + } + + actualUIDs := make([]string, 0, len(entries)) + actualUps := make([]*ttnpb.ApplicationUp, 0, 4) + for _, entry := range entries { + a.So(entry.Values, should.HaveLength, 2) + a.So(entry.Values["payload"], should.NotBeEmpty) + a.So(entry.Values["uid"], should.NotBeEmpty) + actualUIDs = append(actualUIDs, entry.Values["uid"].(string)) + up := &ttnpb.ApplicationUp{} + if err := ttnredis.UnmarshalProto(entry.Values["payload"].(string), up); !a.So(err, should.BeNil) { + t.FailNow() + } + actualUps = append(actualUps, up) + } + a.So(actualUIDs, should.HaveSameElementsDeep, expectedUIDs) + a.So(actualUps, should.HaveSameElementsDeep, expectedUps) +} + +func TestApplicationUplinkQueuePopAll(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "pop_all")...) + t.Cleanup(redisCloseFn) + + q, qCloseFn := setupRedisApplicationUplinkQueue(t, cl, minIdle) + t.Cleanup(qCloseFn) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + expected := generateRandomUplinks(t, appCount, devCountPerApp) + if err := q.Add(ctx, expected...); !a.So(err, should.BeNil) { + t.FailNow() + } + + consumerCount := 3 + uplinkCh := make(chan []*ttnpb.ApplicationUp, consumerCount*appCount) + wg := sync.WaitGroup{} + + for i := 0; i < consumerCount; i++ { + consumerID := fmt.Sprintf("test-consumer-%d", i) + wg.Add(1) + go func() { + defer wg.Done() + + a.So(q.Pop(ctx, consumerID, readLimit, func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + assertAllEqualAppIDs(t, ups) + select { + case <-ctx.Done(): + return ctx.Err() + case uplinkCh <- ups: + } + return nil + }), should.BeNil) + }() + } + wg.Wait() + + actual := make([]*ttnpb.ApplicationUp, 0, len(expected)) +outer: + for { + select { + case <-ctx.Done(): + break outer + case ups := <-uplinkCh: + actual = append(actual, ups...) + default: + break outer + } + } + + a.So(actual, should.HaveLength, len(expected)) + assertStreamUplinkCount(t, cl, 0) +} + +func TestApplicationUplinkQueuePopErr(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "pop_err")...) + t.Cleanup(redisCloseFn) + + q, qCloseFn := setupRedisApplicationUplinkQueue(t, cl, minIdle) + t.Cleanup(qCloseFn) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + generateError := func(ups []*ttnpb.ApplicationUp) error { + appID := ups[0].EndDeviceIds.ApplicationIds.ApplicationId + if appID == "test-application-1" || appID == "test-application-2" { + return fmt.Errorf("test error") + } + return nil + } + + expected := generateRandomUplinks(t, appCount, devCountPerApp) + if err := q.Add(ctx, expected...); !a.So(err, should.BeNil) { + t.FailNow() + } + + consumerCount := 3 + uplinkCh := make(chan []*ttnpb.ApplicationUp, consumerCount*appCount) + wg := sync.WaitGroup{} + + for i := 0; i < consumerCount; i++ { + consumerID := fmt.Sprintf("test-consumer-%d", i) + wg.Add(1) + go func() { + defer wg.Done() + + a.So(q.Pop(ctx, consumerID, readLimit, func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + assertAllEqualAppIDs(t, ups) + select { + case <-ctx.Done(): + return ctx.Err() + case uplinkCh <- ups: + } + return generateError(ups) + }), should.BeNil) + }() + } + wg.Wait() + + actual := make([]*ttnpb.ApplicationUp, 0, len(expected)) +outer: + for { + select { + case <-ctx.Done(): + break outer + case ups := <-uplinkCh: + actual = append(actual, ups...) + default: + break outer + } + } + + expectedFailCount := devCountPerApp * 2 + + a.So(actual, should.HaveLength, len(expected)) // All uplinks should have been processed + assertStreamUplinkCount(t, cl, expectedFailCount) // Only failed uplinks should remain in the stream +} + +func TestApplicationUplinkQueueClaiming(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + + cl, redisCloseFn := test.NewRedis(ctx, append(redisNamespace[:], "claiming")...) + t.Cleanup(redisCloseFn) + + q, qCloseFn := setupRedisApplicationUplinkQueue(t, cl, 0) + t.Cleanup(qCloseFn) + + if !a.So(q.Init(ctx), should.BeNil) { + t.FailNow() + } + + expected := generateRandomUplinks(t, appCount, devCountPerApp) + totalCount := len(expected) + subsetCount := totalCount / 2 + subset, rest := expected[:subsetCount], expected[subsetCount:] + + if err := q.Add(ctx, subset...); !a.So(err, should.BeNil) { + t.FailNow() + } + + consumerID1 := fmt.Sprintf("test-consumer-%d", 1) + err := q.Pop(ctx, consumerID1, totalCount, func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + return fmt.Errorf("consumer error") + }) + if !a.So(err, should.BeNil) { + t.FailNow() + } + + streamID := cl.Key("uplinks") + pending, err := cl.XPendingExt(ctx, &redis.XPendingExtArgs{ + Stream: streamID, + Group: groupID, + Start: "-", + End: "+", + Count: int64(totalCount), + }).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(len(pending), should.Equal, subsetCount) + + if err := q.Add(ctx, rest...); !a.So(err, should.BeNil) { + t.FailNow() + } + + actual := make([]*ttnpb.ApplicationUp, 0, len(expected)) + consumerID2 := fmt.Sprintf("test-consumer-%d", 2) + err = q.Pop(ctx, consumerID2, 100, func(ctx context.Context, ups []*ttnpb.ApplicationUp) error { + assertAllEqualAppIDs(t, ups) + actual = append(actual, ups...) + return nil + }) + if !a.So(err, should.BeNil) { + t.FailNow() + } + + a.So(err, should.BeNil) + a.So(actual, should.HaveLength, len(expected)) + assertStreamUplinkCount(t, cl, 0) } diff --git a/pkg/networkserver/redis/registry.go b/pkg/networkserver/redis/registry.go index 6efbc2e99b..f6661b536c 100644 --- a/pkg/networkserver/redis/registry.go +++ b/pkg/networkserver/redis/registry.go @@ -30,6 +30,7 @@ import ( "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/types" "go.thethings.network/lorawan-stack/v3/pkg/unique" + "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -38,6 +39,8 @@ var ( errInvalidFieldmask = errors.DefineInvalidArgument("invalid_fieldmask", "invalid fieldmask") errInvalidIdentifiers = errors.DefineInvalidArgument("invalid_identifiers", "invalid identifiers") errReadOnlyField = errors.DefineInvalidArgument("read_only_field", "read-only field `{field}`") + + errRelayServed = errors.DefineAlreadyExists("relay_served", "`{served}` is already served by `{serving}`") ) // DeviceSchemaVersion is the Network Server database schema version regarding the devices namespace. @@ -78,6 +81,34 @@ func (r *DeviceRegistry) euiKey(joinEUI, devEUI types.EUI64) string { return r.Redis.Key("eui", joinEUI.String(), devEUI.String()) } +func (r *DeviceRegistry) relayRulesMapping(ctx context.Context, dev *ttnpb.EndDevice) map[string]string { + m := make(map[string]string) + add := func(rules []*ttnpb.RelayUplinkForwardingRule) { + for _, rule := range rules { + if rule.GetDeviceId() == "" { + continue + } + servedUID := unique.ID(ctx, &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: dev.Ids.ApplicationIds, + DeviceId: rule.DeviceId, + }) + path := r.Redis.Key("relay", "rules", servedUID) + m[path] = servedUID + } + } + for _, rules := range [][]*ttnpb.RelayUplinkForwardingRule{ + dev.GetMacSettings().GetRelay().GetServing().GetUplinkForwardingRules(), + dev.GetMacSettings().GetDesiredRelay().GetServing().GetUplinkForwardingRules(), + dev.GetMacState().GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules(), + dev.GetMacState().GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules(), + dev.GetPendingMacState().GetCurrentParameters().GetRelay().GetServing().GetUplinkForwardingRules(), + dev.GetPendingMacState().GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules(), + } { + add(rules) + } + return m +} + // GetByID gets device by appID, devID. func (r *DeviceRegistry) GetByID(ctx context.Context, appID *ttnpb.ApplicationIdentifiers, devID string, paths []string) (*ttnpb.EndDevice, context.Context, error) { defer trace.StartRegion(ctx, "get end device by id").End() @@ -101,6 +132,48 @@ func (r *DeviceRegistry) GetByID(ctx context.Context, appID *ttnpb.ApplicationId return pb, ctx, nil } +// BatchGetByID gets devices by appID, deviceIDs. +func (r *DeviceRegistry) BatchGetByID( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, deviceIDs []string, paths []string, +) ([]*ttnpb.EndDevice, error) { + defer trace.StartRegion(ctx, "batch get end device by id").End() + + keys := make([]string, len(deviceIDs)) + for i, devID := range deviceIDs { + ids := &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: appID, + DeviceId: devID, + } + if err := ids.ValidateContext(ctx); err != nil { + return nil, err + } + keys[i] = r.uidKey(unique.ID(ctx, ids)) + } + + results, err := r.Redis.MGet(ctx, keys...).Result() + if err != nil { + return nil, ttnredis.ConvertError(err) + } + + protos := make([]*ttnpb.EndDevice, len(deviceIDs)) + for i, result := range results { + switch cmd := result.(type) { + case nil: + case string: + dev := &ttnpb.EndDevice{} + if err := ttnredis.UnmarshalProto(cmd, dev); err != nil { + return nil, err + } + dev, err = ttnpb.FilterGetEndDevice(dev, paths...) + if err != nil { + return nil, err + } + protos[i] = dev + } + } + return protos, nil +} + // GetByEUI gets device by joinEUI, devEUI. func (r *DeviceRegistry) GetByEUI(ctx context.Context, joinEUI, devEUI types.EUI64, paths []string) (*ttnpb.EndDevice, context.Context, error) { defer trace.StartRegion(ctx, "get end device by eui").End() @@ -658,6 +731,9 @@ func (r *DeviceRegistry) SetByID(ctx context.Context, appID *ttnpb.ApplicationId uid, ) } + if relayRulesMapping := r.relayRulesMapping(ctx, stored); len(relayRulesMapping) > 0 { + p.Del(ctx, maps.Keys(relayRulesMapping)...) + } return nil } @@ -689,6 +765,28 @@ func (r *DeviceRegistry) SetByID(ctx context.Context, appID *ttnpb.ApplicationId return registry.UniqueEUIViolationErr(ctx, joinEUI, devEUI, storedUIDStr) } } + if relayRulesMapping := r.relayRulesMapping(ctx, pb); len(relayRulesMapping) > 0 { + keys := maps.Keys(relayRulesMapping) + if err := tx.Watch(ctx, keys...).Err(); err != nil { + return err + } + ruleUIDs, err := tx.MGet(ctx, keys...).Result() + if err != nil { + return err + } + for i, ruleUID := range ruleUIDs { + switch ruleUID := ruleUID.(type) { + case nil: + case string: + return errRelayServed.WithAttributes( + "served", relayRulesMapping[keys[i]], + "serving", ruleUID, + ) + default: + panic("unreachable") + } + } + } } else { if ttnpb.HasAnyField(sets, "ids.application_ids.application_id") && pb.Ids.ApplicationIds.ApplicationId != stored.Ids.ApplicationIds.ApplicationId { return errReadOnlyField.WithAttributes("field", "ids.application_ids.application_id") @@ -848,6 +946,56 @@ func (r *DeviceRegistry) SetByID(ctx context.Context, appID *ttnpb.ApplicationId } } + storedRelayRulesMapping := r.relayRulesMapping(ctx, stored) + updatedRelayRulesMapping := r.relayRulesMapping(ctx, updated) + if !maps.Equal(storedRelayRulesMapping, updatedRelayRulesMapping) { + storedRelayRulesKeys := maps.Keys(storedRelayRulesMapping) + updatedRelayRulesKeys := maps.Keys(updatedRelayRulesMapping) + if err := tx.Watch(ctx, append(storedRelayRulesKeys, updatedRelayRulesKeys...)...).Err(); err != nil { + return err + } + + removed := make([]string, 0, len(storedRelayRulesKeys)) + for _, storedKey := range storedRelayRulesKeys { + if _, ok := updatedRelayRulesMapping[storedKey]; !ok { + removed = append(removed, storedKey) + } + } + if len(removed) > 0 { + p.Del(ctx, removed...) + } + + added := make([]string, 0, len(updatedRelayRulesKeys)) + for _, updatedKey := range updatedRelayRulesKeys { + if _, ok := storedRelayRulesMapping[updatedKey]; !ok { + added = append(added, updatedKey) + } + } + if len(added) > 0 { + ruleUIDs, err := tx.MGet(ctx, added...).Result() + if err != nil { + return err + } + for i, ruleUID := range ruleUIDs { + switch ruleUID := ruleUID.(type) { + case nil: + case string: + return errRelayServed.WithAttributes( + "served", updatedRelayRulesMapping[added[i]], + "serving", ruleUID, + ) + default: + panic("unreachable") + } + } + addedMapping := make(map[string]string, len(added)) + for _, addedKey := range added { + addedMapping[addedKey] = uid + } + p.MSet(ctx, addedMapping) + } + } + _, err := ttnredis.SetProto(ctx, p, uk, updated, 0) if err != nil { return err @@ -930,6 +1078,7 @@ func (r *DeviceRegistry) BatchDelete( return err } euiKeys := make([]string, 0, len(raw)) + relayRulesKeys := make([]string, 0, len(raw)) for _, raw := range raw { switch val := raw.(type) { case nil: @@ -964,6 +1113,7 @@ func (r *DeviceRegistry) BatchDelete( )), }...) } + relayRulesKeys = append(relayRulesKeys, maps.Keys(r.relayRulesMapping(ctx, dev))...) } } // If the provided end device identifiers are not registered, it is possible @@ -974,8 +1124,13 @@ func (r *DeviceRegistry) BatchDelete( return err } } + if len(relayRulesKeys) > 0 { + if err := tx.Watch(ctx, relayRulesKeys...).Err(); err != nil { + return err + } + } if _, err := tx.TxPipelined(ctx, func(p redis.Pipeliner) error { - p.Del(ctx, append(uidKeys, euiKeys...)...) + p.Del(ctx, append(append(uidKeys, euiKeys...), relayRulesKeys...)...) for uid, keys := range addrMapping { for _, key := range keys { removeAddrMapping(ctx, p, key, uid) diff --git a/pkg/networkserver/redis/uplink_deduplicator.go b/pkg/networkserver/redis/uplink_deduplicator.go index 2f747cdca4..7af56d81a4 100644 --- a/pkg/networkserver/redis/uplink_deduplicator.go +++ b/pkg/networkserver/redis/uplink_deduplicator.go @@ -52,7 +52,9 @@ func uplinkHash(ctx context.Context, up *ttnpb.UplinkMessage, round uint64) (str } // DeduplicateUplink deduplicates up for window. Since highest precision allowed by Redis is milliseconds, window is truncated to milliseconds. -func (d *UplinkDeduplicator) DeduplicateUplink(ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, round uint64) (bool, error) { +func (d *UplinkDeduplicator) DeduplicateUplink( + ctx context.Context, up *ttnpb.UplinkMessage, window time.Duration, limit int, round uint64, +) (bool, error) { h, err := uplinkHash(ctx, up, round) if err != nil { return false, err @@ -61,7 +63,7 @@ func (d *UplinkDeduplicator) DeduplicateUplink(ctx context.Context, up *ttnpb.Up for _, md := range up.RxMetadata { msgs = append(msgs, md) } - return ttnredis.DeduplicateProtos(ctx, d.Redis, d.Redis.Key(h), window, msgs...) + return ttnredis.DeduplicateProtos(ctx, d.Redis, d.Redis.Key(h), window, limit, msgs...) } // AccumulatedMetadata returns accumulated metadata for up. diff --git a/pkg/networkserver/registry.go b/pkg/networkserver/registry.go index 2c58d582f9..e76eedfc77 100644 --- a/pkg/networkserver/registry.go +++ b/pkg/networkserver/registry.go @@ -43,6 +43,9 @@ type DeviceRegistry interface { RangeByUplinkMatches(ctx context.Context, up *ttnpb.UplinkMessage, f func(context.Context, *UplinkMatch) (bool, error)) error SetByID(ctx context.Context, appID *ttnpb.ApplicationIdentifiers, devID string, paths []string, f func(context.Context, *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error)) (*ttnpb.EndDevice, context.Context, error) Range(ctx context.Context, paths []string, f func(context.Context, *ttnpb.EndDeviceIdentifiers, *ttnpb.EndDevice) bool) error + BatchGetByID( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, deviceIDs []string, paths []string, + ) ([]*ttnpb.EndDevice, error) BatchDelete( ctx context.Context, appIDs *ttnpb.ApplicationIdentifiers, diff --git a/pkg/networkserver/relay.go b/pkg/networkserver/relay.go new file mode 100644 index 0000000000..f52776bd97 --- /dev/null +++ b/pkg/networkserver/relay.go @@ -0,0 +1,446 @@ +// Copyright © 2023 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 networkserver + +import ( + "bytes" + "context" + + "go.thethings.network/lorawan-stack/v3/pkg/band" + "go.thethings.network/lorawan-stack/v3/pkg/crypto" + "go.thethings.network/lorawan-stack/v3/pkg/crypto/cryptoutil" + "go.thethings.network/lorawan-stack/v3/pkg/encoding/lorawan" + "go.thethings.network/lorawan-stack/v3/pkg/errors" + "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/log" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal/time" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" + "go.thethings.network/lorawan-stack/v3/pkg/specification/relayspec" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/types" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/timestamppb" +) + +var ( + errRelaySchedule = errors.DefineAborted("relay_schedule", "relay schedule") + errRelayInvalidUplinkToken = errors.DefineInvalidArgument("relay_uplink_token", "invalid relay uplink token") + errRelayNoSession = errors.DefineNotFound("relay_session", "relay session not found") + errRelayNoSessionKeyID = errors.DefineNotFound("relay_session_key_id", "relay session key ID not found") + errRelayNoRecentUplinks = errors.DefineNotFound("relay_recent_uplinks", "recent uplinks not found") + errRelayRXWindowUnavailable = errors.DefineUnavailable("relay_rx_windows_available", "no RX windows available") + errRelayMTYpe = errors.DefineInvalidArgument("relay_m_type", "invalid MType") + errRelayFullFCnt = errors.DefineInvalidArgument("relay_full_f_cnt", "invalid full FCnt") + errRelayNotServing = errors.DefineUnavailable("relay_serving", "relay not serving") +) + +type relayKeyService struct { + devices DeviceRegistry + keys crypto.KeyService +} + +var _ mac.RelayKeyService = (*relayKeyService)(nil) + +// BatchDeriveRootWorSKey implements mac.RelayKeyService. +func (r *relayKeyService) BatchDeriveRootWorSKey( + ctx context.Context, appID *ttnpb.ApplicationIdentifiers, deviceIDs []string, sessionKeyIDs [][]byte, +) (devAddrs []*types.DevAddr, keys []*types.AES128Key, err error) { + if len(deviceIDs) != len(sessionKeyIDs) { + panic("device IDs and session key IDs must have the same length") + } + if len(deviceIDs) == 0 { + return nil, nil, nil + } + devices, err := r.devices.BatchGetByID( + ctx, + appID, + deviceIDs, + []string{ + "pending_session.dev_addr", + "pending_session.keys.nwk_s_enc_key.encrypted_key", + "pending_session.keys.nwk_s_enc_key.kek_label", + "pending_session.keys.nwk_s_enc_key.key", + "pending_session.keys.session_key_id", + "session.dev_addr", + "session.keys.nwk_s_enc_key.encrypted_key", + "session.keys.nwk_s_enc_key.kek_label", + "session.keys.nwk_s_enc_key.key", + "session.keys.session_key_id", + }, + ) + if err != nil { + return nil, nil, err + } + devAddrs, keys = make([]*types.DevAddr, len(deviceIDs)), make([]*types.AES128Key, len(deviceIDs)) + for i, dev := range devices { + var devAddr types.DevAddr + var keyEnvelope *ttnpb.KeyEnvelope + switch { + case dev.GetPendingSession().GetKeys().GetNwkSEncKey() != nil && + bytes.Equal(dev.PendingSession.Keys.SessionKeyId, sessionKeyIDs[i]): + copy(devAddr[:], dev.PendingSession.DevAddr) + keyEnvelope = dev.PendingSession.Keys.NwkSEncKey + case dev.GetSession().GetKeys().GetNwkSEncKey() != nil && + bytes.Equal(dev.Session.Keys.SessionKeyId, sessionKeyIDs[i]): + copy(devAddr[:], dev.Session.DevAddr) + keyEnvelope = dev.Session.Keys.NwkSEncKey + default: + continue + } + key, err := cryptoutil.UnwrapAES128Key(ctx, keyEnvelope, r.keys) + if err != nil { + return nil, nil, err + } + key = crypto.DeriveRootWorSKey(key) + devAddrs[i], keys[i] = &devAddr, &key + } + return devAddrs, keys, nil +} + +func (ns *NetworkServer) relayKeyService() mac.RelayKeyService { + return &relayKeyService{ns.devices, ns.KeyService()} +} + +func relayUplinkToken(ids *ttnpb.EndDeviceIdentifiers, sessionKeyID []byte, fullFCnt uint32) ([]byte, error) { + token := &ttnpb.RelayUplinkToken{ + Ids: ids, + SessionKeyId: sessionKeyID, + FullFCnt: fullFCnt, + } + if err := token.ValidateFields(); err != nil { + return nil, err + } + return proto.Marshal(token) +} + +func handleRelayForwardingProtocol( + ctx context.Context, + dev *ttnpb.EndDevice, + fullFCnt uint32, + phy *band.Band, + up *ttnpb.UplinkMessage, + keyService crypto.KeyService, +) (_ *ttnpb.UplinkMessage, queuedEvents []events.Event, err error) { + defer func() { + if err != nil { + queuedEvents = append(queuedEvents, evtDropRelayUplink.NewWithIdentifiersAndData(ctx, dev.Ids, err)) + } + }() + session := dev.Session + nwkSEncKey := session.Keys.NwkSEncKey + key, err := cryptoutil.UnwrapAES128Key(ctx, nwkSEncKey, keyService) + if err != nil { + return nil, queuedEvents, err + } + rawPayload, err := crypto.DecryptUplink( + key, types.DevAddr(session.DevAddr), fullFCnt, up.Payload.GetMacPayload().FrmPayload, + ) + if err != nil { + return nil, queuedEvents, err + } + req := &ttnpb.RelayForwardUplinkReq{} + if err := lorawan.UnmarshalRelayForwardUplinkReq(phy, rawPayload, req); err != nil { + return nil, queuedEvents, err + } + uplinkToken, err := relayUplinkToken(dev.Ids, session.Keys.SessionKeyId, fullFCnt) + if err != nil { + return nil, queuedEvents, err + } + mdTime, mdReceivedAt := up.ReceivedAt, up.ReceivedAt + var mdGPSTime *timestamppb.Timestamp + for _, md := range up.RxMetadata { + if md.GpsTime != nil { + mdTime, mdGPSTime, mdReceivedAt = md.Time, md.GpsTime, md.ReceivedAt + break + } + if mdReceivedAt == nil { + mdTime, mdGPSTime, mdReceivedAt = md.Time, md.GpsTime, md.ReceivedAt + continue + } + if md.ReceivedAt != nil && md.ReceivedAt.AsTime().Before(mdReceivedAt.AsTime()) { + mdTime, mdGPSTime, mdReceivedAt = md.Time, md.GpsTime, md.ReceivedAt + } + } + adjustTime := func(ts *timestamppb.Timestamp) *timestamppb.Timestamp { + if ts == nil { + return nil + } + t := ts.AsTime().Add(-(up.ConsumedAirtime.AsDuration() + phy.RelayForwardDelay)) + return timestamppb.New(t) + } + up = &ttnpb.UplinkMessage{ + RawPayload: req.RawPayload, + Settings: &ttnpb.TxSettings{ + DataRate: req.DataRate, + Frequency: req.Frequency, + Time: adjustTime(up.Settings.Time), + }, + RxMetadata: []*ttnpb.RxMetadata{ + { + GatewayIds: relayspec.GatewayIdentifiers, + Relay: &ttnpb.RelayMetadata{ + DeviceId: dev.Ids.DeviceId, + WorChannel: req.WorChannel, + }, + Time: adjustTime(mdTime), + Rssi: float32(req.Rssi), + ChannelRssi: float32(req.Rssi), + Snr: float32(req.Snr), + UplinkToken: uplinkToken, + GpsTime: adjustTime(mdGPSTime), + ReceivedAt: adjustTime(mdReceivedAt), + }, + }, + ReceivedAt: up.ReceivedAt, + CorrelationIds: events.CorrelationIDsFromContext(ctx), + } + if err := up.ValidateFields(); err != nil { + return nil, queuedEvents, err + } + up.Payload = &ttnpb.Message{} + if err := lorawan.UnmarshalMessage(up.RawPayload, up.Payload); err != nil { + return nil, queuedEvents, err + } + if err := up.Payload.ValidateFields(); err != nil { + return nil, queuedEvents, err + } + queuedEvents = append(queuedEvents, evtProcessRelayUplink.NewWithIdentifiersAndData(ctx, dev.Ids, up)) + return up, queuedEvents, nil +} + +func relayLoopbackFunc( + conn *grpc.ClientConn, + up *ttnpb.UplinkMessage, + callOpts ...grpc.CallOption, +) func(context.Context) error { + client := ttnpb.NewGsNsClient(conn) + return func(ctx context.Context) error { + switch _, err := client.HandleUplink(ctx, up, callOpts...); { + case err == nil, errors.IsNotFound(err), errors.IsAlreadyExists(err): + return nil + default: + return err + } + } +} + +func relayUpdateRules( + deviceID string, sessionKeyID []byte, rules []*ttnpb.RelayUplinkForwardingRule, +) bool { + for _, rule := range rules { + if rule.DeviceId != deviceID || bytes.Equal(rule.SessionKeyId, sessionKeyID) { + continue + } + rule.LastWFCnt = 0 + rule.SessionKeyId = sessionKeyID + return true + } + return false +} + +var relayDeliverSessionKeysPaths = ttnpb.AddFields( + deviceDownlinkFullPaths[:], + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", +) + +func (ns *NetworkServer) deliverRelaySessionKeys(ctx context.Context, dev *ttnpb.EndDevice, sessionKeyID []byte) error { + for _, served := range []*ttnpb.ServedRelayParameters{ + dev.MacSettings.GetRelay().GetServed(), + dev.MacSettings.GetDesiredRelay().GetServed(), + } { + if served == nil { + continue + } + serving, ctx, err := ns.devices.SetByID( + ctx, + dev.Ids.ApplicationIds, + served.ServingDeviceId, + relayDeliverSessionKeysPaths, + func(ctx context.Context, serving *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + if serving == nil { + return nil, nil, nil + } + var paths []string + for path, rules := range map[string][]*ttnpb.RelayUplinkForwardingRule{ + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules": serving.MacSettings.GetDesiredRelay().GetServing().GetUplinkForwardingRules(), // nolint:lll + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules": serving.MacState.GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules(), // nolint:lll + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules": serving.PendingMacState.GetDesiredParameters().GetRelay().GetServing().GetUplinkForwardingRules(), // nolint:lll + } { + if relayUpdateRules(dev.Ids.DeviceId, sessionKeyID, rules) { + paths = ttnpb.AddFields(paths, path) + } + } + return serving, paths, nil + }, + ) + if err != nil { + return err + } + if err := ns.updateDataDownlinkTask(ctx, serving, time.Time{}); err != nil { + log.FromContext(ctx).WithError(err).Error("Failed to update downlink task queue after session key delivery") + } + } + return nil +} + +func parseRelayUplinkToken(b []byte) (*ttnpb.RelayUplinkToken, error) { + token := &ttnpb.RelayUplinkToken{} + if err := proto.Unmarshal(b, token); err != nil { + return nil, err + } + if err := token.ValidateFields(); err != nil { + return nil, err + } + return token, nil +} + +func (ns *NetworkServer) relayPatchServingDevice( + ctx context.Context, + appID *ttnpb.ApplicationIdentifiers, + devID string, + gets []string, + f func(context.Context, *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), +) error { + fullGets := ttnpb.AddFields(gets, deviceDownlinkFullPaths[:]...) + filteredF := func(ctx context.Context, dev *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + dev, err := ttnpb.FilterGetEndDevice(dev, gets...) + if err != nil { + return nil, nil, err + } + dev, sets, err := f(ctx, dev) + if err != nil { + return nil, nil, err + } + if dev == nil { + panic("nil device returned") + } + return dev, sets, nil + } + dev, ctx, err := ns.devices.SetByID(ctx, appID, devID, fullGets, filteredF) + if err != nil { + return err + } + return ns.updateDataDownlinkTask(ctx, dev, time.Time{}) +} + +type relayDownlinkTarget struct { + servedEndDeviceIDs *ttnpb.EndDeviceIdentifiers + servedSessionKeyID []byte + + patchServingDevice func( + ctx context.Context, + appID *ttnpb.ApplicationIdentifiers, + devID string, + paths []string, + f func(context.Context, *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error), + ) error +} + +var _ downlinkTarget = (*relayDownlinkTarget)(nil) + +// Equal implements downlinkTarget. +func (*relayDownlinkTarget) Equal(downlinkTarget) bool { + return false +} + +// Schedule implements downlinkTarget. +func (r *relayDownlinkTarget) Schedule( + ctx context.Context, down *ttnpb.DownlinkMessage, _ ...grpc.CallOption, +) (*ttnpb.ScheduleDownlinkResponse, error) { + request := down.GetRequest() + if request == nil { + panic("downlink without request") + } + if len(request.DownlinkPaths) != 1 { + panic("invalid downlink paths length") + } + path := request.DownlinkPaths[0].GetUplinkToken() + if len(path) == 0 { + panic("invalid downlink path") + } + token, err := parseRelayUplinkToken(path) + if err != nil { + return nil, err + } + if !proto.Equal(token.Ids.ApplicationIds, r.servedEndDeviceIDs.ApplicationIds) { + return nil, errRelaySchedule.WithCause(errRelayInvalidUplinkToken) + } + f := func(ctx context.Context, dev *ttnpb.EndDevice) (*ttnpb.EndDevice, []string, error) { + session, macState := dev.GetSession(), dev.GetMacState() + if session == nil || macState == nil { + log.FromContext(ctx).Debug("Nil session or MAC state") + return dev, nil, errRelaySchedule.WithCause(errRelayNoSession) + } + if !bytes.Equal(session.Keys.SessionKeyId, token.SessionKeyId) { + log.FromContext(ctx).Debug("Invalid session key ID") + return dev, nil, errRelaySchedule.WithCause(errRelayNoSessionKeyID) + } + if len(macState.RecentUplinks) == 0 { + log.FromContext(ctx).Debug("No recent uplinks") + return dev, nil, errRelaySchedule.WithCause(errRelayNoRecentUplinks) + } + if !macState.RxWindowsAvailable { + log.FromContext(ctx).Debug("No RX windows available") + return dev, nil, errRelaySchedule.WithCause(errRelayRXWindowUnavailable) + } + lastPayload := internal.LastUplink(macState.RecentUplinks...).Payload + if mType := lastPayload.MHdr.MType; mType != ttnpb.MType_UNCONFIRMED_UP && mType != ttnpb.MType_CONFIRMED_UP { + log.FromContext(ctx).Debug("Invalid MType") + return dev, nil, errRelaySchedule.WithCause(errRelayMTYpe) + } + if lastPayload.GetMacPayload().FullFCnt != token.FullFCnt { + log.FromContext(ctx).Debug("Invalid full FCnt") + return dev, nil, errRelaySchedule.WithCause(errRelayFullFCnt) + } + if macState.CurrentParameters.Relay.GetServing() == nil { + log.FromContext(ctx).Debug("Not serving relay") + return dev, nil, errRelaySchedule.WithCause(errRelayNotServing) + } + log.FromContext(ctx).Debug("Relay downlink enqueued") + macState.PendingRelayDownlink = &ttnpb.RelayForwardDownlinkReq{ + RawPayload: down.RawPayload, + } + return dev, []string{"mac_state.pending_relay_downlink.raw_payload"}, nil + } + if err := r.patchServingDevice( + ctx, + token.Ids.ApplicationIds, + token.Ids.DeviceId, + []string{ + "mac_state.current_parameters.relay.mode.serving", + "mac_state.recent_uplinks", + "mac_state.rx_windows_available", + "session.keys.session_key_id", + }, + f, + ); err != nil { + return nil, err + } + return &ttnpb.ScheduleDownlinkResponse{ + Delay: durationpb.New(peeringScheduleDelay), + DownlinkPath: &ttnpb.DownlinkPath{ + Path: &ttnpb.DownlinkPath_Fixed{ + Fixed: &ttnpb.GatewayAntennaIdentifiers{ + GatewayIds: relayspec.GatewayIdentifiers, + }, + }, + }, + }, nil +} diff --git a/pkg/networkserver/relay_test.go b/pkg/networkserver/relay_test.go new file mode 100644 index 0000000000..cda20e0769 --- /dev/null +++ b/pkg/networkserver/relay_test.go @@ -0,0 +1,279 @@ +// Copyright © 2023 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 networkserver_test + +import ( + "context" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/crypto" + "go.thethings.network/lorawan-stack/v3/pkg/crypto/cryptoutil" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver" + "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + "go.thethings.network/lorawan-stack/v3/pkg/types" + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +func TestBatchDeriveRootWorSKey(t *testing.T) { + t.Parallel() + keyVault := cryptoutil.NewMemKeyVault(nil) + keyService := crypto.NewKeyService(keyVault) + filterFields := func( + t *testing.T, a *assertions.Assertion, devices []*ttnpb.EndDevice, paths []string, + ) []*ttnpb.EndDevice { + t.Helper() + devices = append(devices[:0:0], devices...) + for i, dev := range devices { + var err error + devices[i], err = ttnpb.FilterGetEndDevice(dev, paths...) + if !a.So(err, should.BeNil) { + t.FailNow() + } + } + return devices + } + for _, tc := range []struct { + Name string + + ApplicationIDs *ttnpb.ApplicationIdentifiers + DeviceIDs []string + SessionKeyIDs [][]byte + + DevAddrs []*types.DevAddr + Keys []*types.AES128Key + + BatchGetByIDFunc func( + ctx context.Context, + t *testing.T, + a *assertions.Assertion, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) + }{ + { + Name: "no devices", + + ApplicationIDs: test.DefaultApplicationIdentifiers, + + BatchGetByIDFunc: func( + ctx context.Context, + t *testing.T, + a *assertions.Assertion, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) { + t.Helper() + t.Fatal("BatchGetByID must not be called") + return nil, nil + }, + }, + { + Name: "no sessions", + + ApplicationIDs: test.DefaultApplicationIdentifiers, + DeviceIDs: []string{"device1", "device2"}, + SessionKeyIDs: [][]byte{{0x01}, {0x02}}, + + DevAddrs: []*types.DevAddr{nil, nil}, + Keys: []*types.AES128Key{nil, nil}, + + BatchGetByIDFunc: func( + ctx context.Context, + t *testing.T, + a *assertions.Assertion, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) { + t.Helper() + a.So(appIDs, should.Resemble, test.DefaultApplicationIdentifiers) + a.So(devIDs, should.Resemble, []string{"device1", "device2"}) + return filterFields(t, a, []*ttnpb.EndDevice{ + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device1", + }, + }, + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device2", + }, + }, + }, paths), nil + }, + }, + { + Name: "only sessions", + + ApplicationIDs: test.DefaultApplicationIdentifiers, + DeviceIDs: []string{"device1", "device2"}, + SessionKeyIDs: [][]byte{{0x01}, {0x02}}, + + DevAddrs: []*types.DevAddr{{0x42, 0x42, 0x42, 0x42}, {0x43, 0x43, 0x43, 0x43}}, + Keys: []*types.AES128Key{ + {0xEE, 0x91, 0xDC, 0x1A, 0x66, 0x66, 0xC0, 0x6E, 0x82, 0x77, 0xDE, 0x6D, 0xB4, 0xDB, 0x94, 0x5F}, + {0xC2, 0x7E, 0x77, 0x4E, 0x20, 0x73, 0x18, 0x96, 0xFE, 0x20, 0x5D, 0x77, 0x1D, 0x7B, 0xC1, 0xF1}, + }, + + BatchGetByIDFunc: func( + ctx context.Context, + t *testing.T, + a *assertions.Assertion, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) { + t.Helper() + a.So(appIDs, should.Resemble, test.DefaultApplicationIdentifiers) + a.So(devIDs, should.Resemble, []string{"device1", "device2"}) + return filterFields(t, a, []*ttnpb.EndDevice{ + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device1", + }, + Session: &ttnpb.Session{ + DevAddr: types.DevAddr{0x42, 0x42, 0x42, 0x42}.Bytes(), + Keys: &ttnpb.SessionKeys{ + SessionKeyId: []byte{0x01}, + NwkSEncKey: &ttnpb.KeyEnvelope{ + Key: []byte{0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0B}, // nolint:lll + }, + }, + }, + }, + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device2", + }, + Session: &ttnpb.Session{ + DevAddr: types.DevAddr{0x43, 0x43, 0x43, 0x43}.Bytes(), + Keys: &ttnpb.SessionKeys{ + SessionKeyId: []byte{0x02}, + NwkSEncKey: &ttnpb.KeyEnvelope{ + Key: []byte{0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0C}, // nolint:lll + }, + }, + }, + }, + }, paths), nil + }, + }, + { + Name: "with pending sessions", + + ApplicationIDs: test.DefaultApplicationIdentifiers, + DeviceIDs: []string{"device1", "device2"}, + SessionKeyIDs: [][]byte{{0x03}, {0x02}}, + + DevAddrs: []*types.DevAddr{{0x44, 0x44, 0x44, 0x44}, {0x43, 0x43, 0x43, 0x43}}, + Keys: []*types.AES128Key{ + {0x67, 0x11, 0x92, 0xD5, 0x9C, 0x0D, 0x35, 0x7D, 0xEF, 0xE2, 0xA9, 0x45, 0x21, 0xC4, 0x22, 0x7C}, + {0xC2, 0x7E, 0x77, 0x4E, 0x20, 0x73, 0x18, 0x96, 0xFE, 0x20, 0x5D, 0x77, 0x1D, 0x7B, 0xC1, 0xF1}, + }, + + BatchGetByIDFunc: func( + ctx context.Context, + t *testing.T, + a *assertions.Assertion, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) { + t.Helper() + a.So(appIDs, should.Resemble, test.DefaultApplicationIdentifiers) + a.So(devIDs, should.Resemble, []string{"device1", "device2"}) + return filterFields(t, a, []*ttnpb.EndDevice{ + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device1", + }, + Session: &ttnpb.Session{ + DevAddr: types.DevAddr{0x42, 0x42, 0x42, 0x42}.Bytes(), + Keys: &ttnpb.SessionKeys{ + SessionKeyId: []byte{0x01}, + NwkSEncKey: &ttnpb.KeyEnvelope{ + Key: []byte{0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0B}, // nolint:lll + }, + }, + }, + PendingSession: &ttnpb.Session{ + DevAddr: types.DevAddr{0x44, 0x44, 0x44, 0x44}.Bytes(), + Keys: &ttnpb.SessionKeys{ + SessionKeyId: []byte{0x03}, + NwkSEncKey: &ttnpb.KeyEnvelope{ + Key: []byte{0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0D}, // nolint:lll + }, + }, + }, + }, + { + Ids: &ttnpb.EndDeviceIdentifiers{ + ApplicationIds: test.DefaultApplicationIdentifiers, + DeviceId: "device2", + }, + Session: &ttnpb.Session{ + DevAddr: types.DevAddr{0x43, 0x43, 0x43, 0x43}.Bytes(), + Keys: &ttnpb.SessionKeys{ + SessionKeyId: []byte{0x02}, + NwkSEncKey: &ttnpb.KeyEnvelope{ + Key: []byte{0xCE, 0x07, 0xA0, 0x09, 0xA3, 0x97, 0x0A, 0xC0, 0x51, 0x9A, 0x09, 0x9E, 0xD5, 0x3E, 0x55, 0x0C}, // nolint:lll + }, + }, + }, + }, + }, paths), nil + }, + }, + } { + tc := tc + test.RunSubtest(t, test.SubtestConfig{ + Name: tc.Name, + Parallel: true, + Func: func(ctx context.Context, t *testing.T, a *assertions.Assertion) { + t.Helper() + relayKeyService := networkserver.NewRelayKeyService( + &networkserver.MockDeviceRegistry{ + BatchGetByIDFunc: func( + ctx context.Context, + appIDs *ttnpb.ApplicationIdentifiers, + devIDs []string, + paths []string, + ) ([]*ttnpb.EndDevice, error) { + t.Helper() + return tc.BatchGetByIDFunc(ctx, t, a, appIDs, devIDs, paths) + }, + }, + keyService, + ) + devAddrs, keys, err := relayKeyService.BatchDeriveRootWorSKey( + ctx, tc.ApplicationIDs, tc.DeviceIDs, tc.SessionKeyIDs, + ) + if a.So(err, should.BeNil) { + a.So(devAddrs, should.Resemble, tc.DevAddrs) + a.So(keys, should.Resemble, tc.Keys) + } + }, + }) + } +} diff --git a/pkg/networkserver/relay_util_test.go b/pkg/networkserver/relay_util_test.go new file mode 100644 index 0000000000..4343c6fb92 --- /dev/null +++ b/pkg/networkserver/relay_util_test.go @@ -0,0 +1,28 @@ +// Copyright © 2023 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 networkserver + +import ( + "go.thethings.network/lorawan-stack/v3/pkg/crypto" + "go.thethings.network/lorawan-stack/v3/pkg/networkserver/mac" +) + +// NewRelayKeyService returns a new mac.RelayKeyService. +func NewRelayKeyService(devices DeviceRegistry, keys crypto.KeyService) mac.RelayKeyService { + return &relayKeyService{ + devices: devices, + keys: keys, + } +} diff --git a/pkg/networkserver/utils.go b/pkg/networkserver/utils.go index 9259e56994..43b00ca0ff 100644 --- a/pkg/networkserver/utils.go +++ b/pkg/networkserver/utils.go @@ -19,6 +19,7 @@ import ( "fmt" "go.thethings.network/lorawan-stack/v3/pkg/band" + "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/events" "go.thethings.network/lorawan-stack/v3/pkg/log" . "go.thethings.network/lorawan-stack/v3/pkg/networkserver/internal" @@ -255,6 +256,9 @@ func nextDataDownlinkSlot(ctx context.Context, dev *ttnpb.EndDevice, phy *band.B case mac.ContainsStickyMACCommand(dev.MacState.RecentMacCommandIdentifiers...): logger.Debug("Sticky MAC response received, choose class A downlink slot") return classA, true + case dev.MacState.PendingRelayDownlink != nil: + logger.Debug("Pending relay downlink, choose class A downlink slot") + return classA, true case mac.DeviceNeedsADRParamSetupReq(dev, phy): logger.Debug("Device needs ADRParamSetupReq, choose class A downlink slot") return classA, true @@ -294,6 +298,21 @@ func nextDataDownlinkSlot(ctx context.Context, dev *ttnpb.EndDevice, phy *band.B case mac.DeviceNeedsTxParamSetupReq(dev, phy): logger.Debug("Device needs TxParamSetupReq, choose class A downlink slot") return classA, true + case mac.DeviceNeedsRelayConfReq(dev): + logger.Debug("Device needs RelayConfReq, choose class A downlink slot") + return classA, true + case mac.DeviceNeedsRelayEndDeviceConfReq(dev): + logger.Debug("Device needs RelayEndDeviceConfReq, choose class A downlink slot") + return classA, true + case mac.DeviceNeedsRelayUpdateUplinkListReq(dev): + logger.Debug("Device needs RelayUpdateUplinkListReq, choose class A downlink slot") + return classA, true + case mac.DeviceNeedsRelayCtrlUplinkListReq(dev): + logger.Debug("Device needs RelayCtrlUplinkListReq, choose class A downlink slot") + return classA, true + case mac.DeviceNeedsRelayConfigureFwdLimitReq(dev): + logger.Debug("Device needs RelayConfigureFwdLimitReq, choose class A downlink slot") + return classA, true } } @@ -425,8 +444,10 @@ func (ns *NetworkServer) handleUplinkSubmission(ctx context.Context, ups []*ttnp } if err := ns.sendApplicationUplinks(ctx, ttnpb.NewNsAsClient(conn), ups...); err != nil { log.FromContext(ctx).WithError(err).Warn("Failed to send application uplinks to Application Server") + if !retryableUplinkError(err) { + return + } ns.enqueueApplicationUplinks(ctx, ups...) - return } } @@ -462,3 +483,11 @@ var ( "session", } ) + +func retryableUplinkError(err error) bool { + return errors.IsCanceled(err) || + errors.IsDeadlineExceeded(err) || + errors.IsResourceExhausted(err) || + errors.IsAborted(err) || + errors.IsUnavailable(err) +} diff --git a/pkg/packetbrokeragent/agent.go b/pkg/packetbrokeragent/agent.go index 41884e1d07..9bdf29bedc 100644 --- a/pkg/packetbrokeragent/agent.go +++ b/pkg/packetbrokeragent/agent.go @@ -74,7 +74,7 @@ type RegistrationInfo struct { Listed bool } -// PacketBrokerClusterBuilder builds a Packet Broker Cluster ID from a The Things Stack Cluster ID. +// PacketBrokerClusterIDBuilder builds a Packet Broker Cluster ID from a The Things Stack Cluster ID. type PacketBrokerClusterIDBuilder func(clusterID string) (string, error) func literalClusterID(clusterID string) (string, error) { @@ -177,7 +177,7 @@ func New(c *component.Component, conf *Config, opts ...Option) (*Agent, error) { } devAddrPrefix := types.DevAddrPrefix{ DevAddr: devAddr, - Length: uint8(conf.NetID.IDBits()), + Length: uint8(32 - types.NwkAddrBits(conf.NetID)), } devAddrPrefixes = append(devAddrPrefixes, devAddrPrefix) } @@ -675,7 +675,8 @@ func (a *Agent) handleDownlinkMessage( } } - uid, msg, err := fromPBDownlink(ctx, down.Message, receivedAt, a.forwarderConfig) + forwarderData := forwarderAdditionalData(down.ForwarderNetId, down.ForwarderTenantId, down.ForwarderClusterId) + uid, msg, err := fromPBDownlink(ctx, down.Message, forwarderData, receivedAt, a.forwarderConfig) if err != nil { logger.WithError(err).Warn("Failed to convert incoming downlink message") return err @@ -944,7 +945,7 @@ func (a *Agent) handleUplink( if up.Message == nil { return } - ctx = appendDownlinkCorrelationID(ctx, up.Id) + ctx = appendUplinkCorrelationID(ctx, up.Id) var forwarderNetID types.NetID forwarderNetID.UnmarshalNumber(up.ForwarderNetId) ctx = log.NewContextWithFields(ctx, log.Fields( diff --git a/pkg/packetbrokeragent/agent_test.go b/pkg/packetbrokeragent/agent_test.go index a7c1bbbded..157b437652 100644 --- a/pkg/packetbrokeragent/agent_test.go +++ b/pkg/packetbrokeragent/agent_test.go @@ -428,8 +428,9 @@ func TestForwarder(t *testing.T) { })) tokenNonce := make([]byte, aead.NonceSize()) test.Must(io.ReadFull(rand.Reader, tokenNonce)) + forwarderData := []byte("000013:foo-tenant:test") token := test.Must(proto.Marshal(&ttnpb.PacketBrokerAgentEncryptedPayload{ - Ciphertext: aead.Seal(nil, tokenNonce, plainToken, nil), + Ciphertext: aead.Seal(nil, tokenNonce, plainToken, forwarderData), Nonce: tokenNonce, })) diff --git a/pkg/webui/lib/components/scroll-to-top.js b/pkg/packetbrokeragent/crypto.go similarity index 67% rename from pkg/webui/lib/components/scroll-to-top.js rename to pkg/packetbrokeragent/crypto.go index fa731830d0..7effaeca2b 100644 --- a/pkg/webui/lib/components/scroll-to-top.js +++ b/pkg/packetbrokeragent/crypto.go @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,15 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { useEffect } from 'react' -import { useLocation } from 'react-router-dom' +package packetbrokeragent -export default () => { - const { pathname } = useLocation() +import "fmt" - useEffect(() => { - window.scrollTo(0, 0) - }, [pathname]) - - return null +func forwarderAdditionalData(netID uint32, tenantID string, clusterID string) []byte { + return []byte(fmt.Sprintf("%06x:%s:%s", netID, tenantID, clusterID)) } diff --git a/pkg/packetbrokeragent/grpc_gspba.go b/pkg/packetbrokeragent/grpc_gspba.go index 468b187817..502adfc028 100644 --- a/pkg/packetbrokeragent/grpc_gspba.go +++ b/pkg/packetbrokeragent/grpc_gspba.go @@ -75,7 +75,8 @@ func (s *gsPbaServer) PublishUplink(ctx context.Context, up *ttnpb.GatewayUplink ctx = appendUplinkCorrelationID(ctx) up.Message.CorrelationIds = events.CorrelationIDsFromContext(ctx) - msg, err := toPBUplink(ctx, up, s.config) + forwarderData := forwarderAdditionalData(s.netID.MarshalNumber(), s.tenantIDExtractor(ctx), s.clusterID) + msg, err := toPBUplink(ctx, up, forwarderData, s.config) if err != nil { log.FromContext(ctx).WithError(err).Warn("Failed to convert outgoing uplink message") return nil, err diff --git a/pkg/packetbrokeragent/grpc_pba.go b/pkg/packetbrokeragent/grpc_pba.go index b706390c1f..6875cfdaf3 100644 --- a/pkg/packetbrokeragent/grpc_pba.go +++ b/pkg/packetbrokeragent/grpc_pba.go @@ -556,6 +556,8 @@ func (s *pbaServer) ListNetworks(ctx context.Context, req *ttnpb.ListPacketBroke return res.GetNetworks(), res.GetTotal(), err } res, err := iampbv2.NewCatalogClient(s.iamConn).ListNetworks(ctx, &iampbv2.ListNetworksRequest{ + NetId: s.netID.MarshalNumber(), + TenantId: s.tenantIDExtractor(ctx), Offset: (page - 1) * req.Limit, Limit: req.Limit, TenantIdContains: req.TenantIdContains, @@ -576,6 +578,8 @@ func (s *pbaServer) ListHomeNetworks(ctx context.Context, req *ttnpb.ListPacketB } return s.listNetworks(ctx, func() ([]*packetbroker.NetworkOrTenant, uint32, error) { res, err := iampbv2.NewCatalogClient(s.iamConn).ListHomeNetworks(ctx, &iampbv2.ListNetworksRequest{ + NetId: s.netID.MarshalNumber(), + TenantId: s.tenantIDExtractor(ctx), Offset: (page - 1) * req.Limit, Limit: req.Limit, TenantIdContains: req.TenantIdContains, diff --git a/pkg/packetbrokeragent/translation.go b/pkg/packetbrokeragent/translation.go index 085f821a37..832dc6149f 100644 --- a/pkg/packetbrokeragent/translation.go +++ b/pkg/packetbrokeragent/translation.go @@ -180,27 +180,27 @@ func unwrapUplinkTokens( return t.Gateway, t.Forwarder, t.Agent, nil } -func encryptPlaintext(plaintext []byte, aead cipher.AEAD) ([]byte, error) { +func encryptPlaintext(plaintext, additionalData []byte, aead cipher.AEAD) ([]byte, error) { nonce := make([]byte, aead.NonceSize()) if _, err := io.ReadFull(rand.Reader, nonce); err != nil { return nil, err } return proto.Marshal(&ttnpb.PacketBrokerAgentEncryptedPayload{ - Ciphertext: aead.Seal(nil, nonce, plaintext, nil), + Ciphertext: aead.Seal(nil, nonce, plaintext, additionalData), Nonce: nonce, }) } -func decryptCiphertext(payload []byte, aead cipher.AEAD) ([]byte, error) { +func decryptCiphertext(payload, additionalData []byte, aead cipher.AEAD) ([]byte, error) { var encrypted ttnpb.PacketBrokerAgentEncryptedPayload if err := proto.Unmarshal(payload, &encrypted); err != nil { return nil, err } - return aead.Open(nil, encrypted.Nonce, encrypted.Ciphertext, nil) + return aead.Open(nil, encrypted.Nonce, encrypted.Ciphertext, additionalData) } func wrapGatewayUplinkToken( - ctx context.Context, ids *ttnpb.GatewayIdentifiers, ulToken []byte, aead cipher.AEAD, + ctx context.Context, ids *ttnpb.GatewayIdentifiers, ulToken, forwarderData []byte, aead cipher.AEAD, ) ([]byte, error) { plaintext, err := proto.Marshal(&ttnpb.PacketBrokerAgentGatewayUplinkToken{ GatewayUid: unique.ID(ctx, ids), @@ -209,11 +209,11 @@ func wrapGatewayUplinkToken( if err != nil { return nil, err } - return encryptPlaintext(plaintext, aead) + return encryptPlaintext(plaintext, forwarderData, aead) } -func unwrapGatewayUplinkToken(token []byte, aead cipher.AEAD) (string, []byte, error) { - plaintext, err := decryptCiphertext(token, aead) +func unwrapGatewayUplinkToken(token, forwarderData []byte, aead cipher.AEAD) (string, []byte, error) { + plaintext, err := decryptCiphertext(token, forwarderData, aead) if err != nil { return "", nil, err } @@ -266,7 +266,9 @@ var ( errWrapGatewayUplinkToken = errors.DefineAborted("wrap_gateway_uplink_token", "wrap gateway uplink token") ) -func toPBUplink(ctx context.Context, msg *ttnpb.GatewayUplinkMessage, config ForwarderConfig) (*packetbroker.UplinkMessage, error) { +func toPBUplink( + ctx context.Context, msg *ttnpb.GatewayUplinkMessage, forwarderData []byte, config ForwarderConfig, +) (*packetbroker.UplinkMessage, error) { msg.Message.Payload = &ttnpb.Message{} if err := lorawan.UnmarshalMessage(msg.Message.RawPayload, msg.Message.Payload); err != nil { return nil, errDecodePayload.WithCause(err) @@ -400,7 +402,9 @@ func toPBUplink(ctx context.Context, msg *ttnpb.GatewayUplinkMessage, config For if len(gatewayUplinkToken) == 0 { var err error - gatewayUplinkToken, err = wrapGatewayUplinkToken(ctx, md.GatewayIds, md.UplinkToken, config.TokenAEAD) + gatewayUplinkToken, err = wrapGatewayUplinkToken( + ctx, md.GatewayIds, md.UplinkToken, forwarderData, config.TokenAEAD, + ) if err != nil { return nil, errWrapGatewayUplinkToken.WithCause(err) } @@ -684,8 +688,14 @@ var ( errInvalidRx1Delay = errors.DefineInvalidArgument("invalid_rx1_delay", "invalid Rx1 delay") ) -func fromPBDownlink(ctx context.Context, msg *packetbroker.DownlinkMessage, receivedAt time.Time, conf ForwarderConfig) (uid string, res *ttnpb.DownlinkMessage, err error) { - uid, token, err := unwrapGatewayUplinkToken(msg.GatewayUplinkToken, conf.TokenAEAD) +func fromPBDownlink( + ctx context.Context, + msg *packetbroker.DownlinkMessage, + forwarderData []byte, + receivedAt time.Time, + conf ForwarderConfig, +) (uid string, res *ttnpb.DownlinkMessage, err error) { + uid, token, err := unwrapGatewayUplinkToken(msg.GatewayUplinkToken, forwarderData, conf.TokenAEAD) if err != nil { return "", nil, errUnwrapGatewayUplinkToken.WithCause(err) } diff --git a/pkg/packetbrokeragent/translation_internal_test.go b/pkg/packetbrokeragent/translation_internal_test.go index 248ff9dc66..90abb6fccb 100644 --- a/pkg/packetbrokeragent/translation_internal_test.go +++ b/pkg/packetbrokeragent/translation_internal_test.go @@ -34,6 +34,7 @@ func WrapUplinkTokens(gateway, forwarder []byte, agent *ttnpb.PacketBrokerAgentU func TestWrapGatewayUplinkToken(t *testing.T) { a, ctx := test.New(t) key := bytes.Repeat([]byte{0x42}, 16) + forwarderData := []byte("000013:tnt:eu1") blockCipher, err := aes.NewCipher(key) if !a.So(err, should.BeNil) { t.FailNow() @@ -43,15 +44,19 @@ func TestWrapGatewayUplinkToken(t *testing.T) { t.FailNow() } - wrappedToken, err := wrapGatewayUplinkToken(ctx, &ttnpb.GatewayIdentifiers{GatewayId: "test-gateway"}, - []byte{0x1, 0x2, 0x3}, aead, + wrappedToken, err := wrapGatewayUplinkToken( + ctx, + &ttnpb.GatewayIdentifiers{GatewayId: "test-gateway"}, + []byte{0x1, 0x2, 0x3}, + forwarderData, + aead, ) if !a.So(err, should.BeNil) { t.FailNow() } t.Logf("Wrapped token: %q", base64.RawStdEncoding.EncodeToString(wrappedToken)) - uid, gtwToken, err := unwrapGatewayUplinkToken(wrappedToken, aead) + uid, gtwToken, err := unwrapGatewayUplinkToken(wrappedToken, forwarderData, aead) if !a.So(err, should.BeNil) { t.FailNow() } diff --git a/pkg/pfconfig/lbslns/lbslbs_test.go b/pkg/pfconfig/lbslns/lbslbs_test.go index 0ee90625ae..c14459e506 100644 --- a/pkg/pfconfig/lbslns/lbslbs_test.go +++ b/pkg/pfconfig/lbslns/lbslbs_test.go @@ -271,7 +271,7 @@ func TestGetRouterConfig(t *testing.T) { t.Parallel() a, ctx := test.New(t) - fps := map[string]*frequencyplans.FrequencyPlan{tc.FrequencyPlanID: &tc.FrequencyPlan} + fps := []*frequencyplans.FrequencyPlan{&tc.FrequencyPlan} cfg, err := GetRouterConfig(ctx, tc.FrequencyPlan.BandID, fps, tc.Features, time.Now(), 0) if err != nil { if tc.ErrorAssertion == nil || !a.So(tc.ErrorAssertion(err), should.BeTrue) { @@ -295,7 +295,7 @@ func TestGetRouterConfigWithMultipleFP(t *testing.T) { for _, tc := range []struct { Name string BandID string - FrequencyPlans map[string]*frequencyplans.FrequencyPlan + FrequencyPlans []*frequencyplans.FrequencyPlan Cfg RouterConfig Features TestFeatures ErrorAssertion func(err error) bool @@ -303,8 +303,8 @@ func TestGetRouterConfigWithMultipleFP(t *testing.T) { { Name: "ValidFrequencyPlan", BandID: "US_902_928", - FrequencyPlans: map[string]*frequencyplans.FrequencyPlan{ - test.USFrequencyPlanID: { + FrequencyPlans: []*frequencyplans.FrequencyPlan{ + { BandID: "US_902_928", Radios: []frequencyplans.Radio{ { @@ -322,7 +322,8 @@ func TestGetRouterConfigWithMultipleFP(t *testing.T) { Frequency: 925000000, }, }, - }, "US_902_928_Custom": { + }, + { BandID: "US_902_928", Radios: []frequencyplans.Radio{ { diff --git a/pkg/pfconfig/lbslns/lbslns.go b/pkg/pfconfig/lbslns/lbslns.go index 635072cf55..3ba01ace03 100644 --- a/pkg/pfconfig/lbslns/lbslns.go +++ b/pkg/pfconfig/lbslns/lbslns.go @@ -274,7 +274,7 @@ type RouterFeatures interface { func GetRouterConfig( ctx context.Context, bandID string, - fps map[string]*frequencyplans.FrequencyPlan, + fps []*frequencyplans.FrequencyPlan, features RouterFeatures, dlTime time.Time, antennaGain int, @@ -386,7 +386,7 @@ func getDataRatesFromBandID(id string) (DataRates, error) { } // getMinMaxFrequencies extract the minimum and maximum frequencies between all the bands. -func getMinMaxFrequencies(fps map[string]*frequencyplans.FrequencyPlan) (min uint64, max uint64, err error) { +func getMinMaxFrequencies(fps []*frequencyplans.FrequencyPlan) (min uint64, max uint64, err error) { min = math.MaxUint64 for _, fp := range fps { if len(fp.Radios) == 0 { diff --git a/pkg/pfconfig/semtechudp/semtechudp.go b/pkg/pfconfig/semtechudp/semtechudp.go index ee5fde2ec9..6e38096af9 100644 --- a/pkg/pfconfig/semtechudp/semtechudp.go +++ b/pkg/pfconfig/semtechudp/semtechudp.go @@ -16,6 +16,8 @@ package semtechudp import ( + "encoding/json" + "go.thethings.network/lorawan-stack/v3/pkg/frequencyplans" "go.thethings.network/lorawan-stack/v3/pkg/pfconfig/shared" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" @@ -24,8 +26,39 @@ import ( // Config represents the full configuration for Semtech's UDP Packet Forwarder. type Config struct { - SX1301Conf shared.SX1301Config `json:"SX1301_conf"` - GatewayConf GatewayConf `json:"gateway_conf"` + SX1301Conf []*shared.SX1301Config `json:"SX1301_conf"` + GatewayConf GatewayConf `json:"gateway_conf"` +} + +// SingleSX1301Config is a helper type for marshaling a config with a single SX1301Config. +type singleSX1301Config struct { + SX1301Conf *shared.SX1301Config `json:"SX1301_conf"` + GatewayConf GatewayConf `json:"gateway_conf"` +} + +// MarshalJSON implements json.Marshaler. +// Serializes the SX1301Conf field as an object if it contains a single element and as an array otherwise. +func (c Config) MarshalJSON() ([]byte, error) { + if len(c.SX1301Conf) == 1 { + return json.Marshal(singleSX1301Config{ + SX1301Conf: c.SX1301Conf[0], + GatewayConf: c.GatewayConf, + }) + } + type alias Config + return json.Marshal(alias(c)) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (c *Config) UnmarshalJSON(data []byte) error { + var single singleSX1301Config + if err := json.Unmarshal(data, &single); err == nil { + c.SX1301Conf = []*shared.SX1301Config{single.SX1301Conf} + c.GatewayConf = single.GatewayConf + return nil + } + type alias Config + return json.Unmarshal(data, (*alias)(c)) } // GatewayConf contains the configuration for the gateway's server connection. @@ -50,22 +83,26 @@ func Build(gateway *ttnpb.Gateway, store *frequencyplans.Store) (*Config, error) if gateway.GetIds().GetEui() != nil { c.GatewayConf.GatewayID = types.MustEUI64(gateway.GetIds().GetEui()).String() } - c.GatewayConf.ServerAddress, c.GatewayConf.ServerPortUp, c.GatewayConf.ServerPortDown = host, uint32(port), uint32(port) + c.GatewayConf.ServerAddress = host + c.GatewayConf.ServerPortUp = uint32(port) + c.GatewayConf.ServerPortDown = uint32(port) server := c.GatewayConf server.Enabled = true c.GatewayConf.Servers = append(c.GatewayConf.Servers, server) - frequencyPlan, err := store.GetByID(gateway.FrequencyPlanId) - if err != nil { - return nil, err - } - if len(frequencyPlan.Radios) != 0 { - sx1301Config, err := shared.BuildSX1301Config(frequencyPlan) + c.SX1301Conf = make([]*shared.SX1301Config, 0, len(gateway.FrequencyPlanIds)) + for _, frequencyPlanID := range gateway.FrequencyPlanIds { + frequencyPlan, err := store.GetByID(frequencyPlanID) if err != nil { return nil, err } - c.SX1301Conf = *sx1301Config + if len(frequencyPlan.Radios) != 0 { + sx1301Config, err := shared.BuildSX1301Config(frequencyPlan) + if err != nil { + return nil, err + } + c.SX1301Conf = append(c.SX1301Conf, sx1301Config) + } } - return &c, nil } diff --git a/pkg/pfconfig/semtechudp/semtechudp_test.go b/pkg/pfconfig/semtechudp/semtechudp_test.go new file mode 100644 index 0000000000..97ce438f9c --- /dev/null +++ b/pkg/pfconfig/semtechudp/semtechudp_test.go @@ -0,0 +1,166 @@ +// Copyright © 2023 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 semtechudp_test + +import ( + "encoding/json" + "testing" + + "github.com/smarty/assertions" + "go.thethings.network/lorawan-stack/v3/pkg/pfconfig/semtechudp" + "go.thethings.network/lorawan-stack/v3/pkg/pfconfig/shared" + "go.thethings.network/lorawan-stack/v3/pkg/util/test/assertions/should" +) + +func getSX1301Conf(t *testing.T) *shared.SX1301Config { + t.Helper() + + return &shared.SX1301Config{ + LoRaWANPublic: true, + ClockSource: 1, + AntennaGain: 0, + Radios: []shared.RFConfig{ + { + Enable: true, + Type: "SX1257", + Frequency: 867500000, + TxEnable: true, + TxFreqMin: 863000000, + TxFreqMax: 870000000, + RSSIOffset: -166, + }, + { + Enable: true, Type: "SX1257", + Frequency: 868500000, + TxEnable: false, + TxFreqMin: 0, + TxFreqMax: 0, + RSSIOffset: -166, + }, + }, + Channels: []shared.IFConfig{ + {Enable: true, Radio: 1, IFValue: -400000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 1, IFValue: -200000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 1, IFValue: 0, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 0, IFValue: -400000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 0, IFValue: -200000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 0, IFValue: 0, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 0, IFValue: 200000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + {Enable: true, Radio: 0, IFValue: 400000, Bandwidth: 0, SpreadFactor: 0, Datarate: 0}, + }, + LoRaStandardChannel: &shared.IFConfig{ + Enable: true, + Radio: 1, + IFValue: -200000, + Bandwidth: 250000, + SpreadFactor: 7, + Datarate: 0, + }, + FSKChannel: &shared.IFConfig{ + Enable: true, + Radio: 1, + IFValue: -200000, + Bandwidth: 250000, + SpreadFactor: 7, + Datarate: 0, + }, + TxLUTConfigs: []shared.TxLUTConfig{ + {PAGain: 0, MixGain: 8, RFPower: -6, DigGain: 0}, + {PAGain: 0, MixGain: 10, RFPower: -3, DigGain: 0}, + {PAGain: 0, MixGain: 12, RFPower: 0, DigGain: 0}, + {PAGain: 1, MixGain: 8, RFPower: 3, DigGain: 0}, + {PAGain: 1, MixGain: 10, RFPower: 6, DigGain: 0}, + {PAGain: 1, MixGain: 12, RFPower: 10, DigGain: 0}, + {PAGain: 1, MixGain: 13, RFPower: 11, DigGain: 0}, + {PAGain: 2, MixGain: 9, RFPower: 12, DigGain: 0}, + {PAGain: 1, MixGain: 15, RFPower: 13, DigGain: 0}, + {PAGain: 2, MixGain: 10, RFPower: 14, DigGain: 0}, + {PAGain: 2, MixGain: 11, RFPower: 16, DigGain: 0}, + {PAGain: 3, MixGain: 9, RFPower: 20, DigGain: 0}, + {PAGain: 3, MixGain: 10, RFPower: 23, DigGain: 0}, + {PAGain: 3, MixGain: 11, RFPower: 25, DigGain: 0}, + {PAGain: 3, MixGain: 12, RFPower: 26, DigGain: 0}, + {PAGain: 3, MixGain: 14, RFPower: 27, DigGain: 0}, + }, + } +} + +func getGtwConfig(t *testing.T) semtechudp.GatewayConf { + t.Helper() + + return semtechudp.GatewayConf{ + ServerAddress: "localhost", + ServerPortUp: 1700, + ServerPortDown: 1700, + Servers: []semtechudp.GatewayConf{ + { + ServerAddress: "localhost", + ServerPortUp: 1700, + ServerPortDown: 1700, + Enabled: true, + }, + }, + } +} + +func TestConfigSerialization(t *testing.T) { + t.Parallel() + + testCases := []struct { + Name string + *semtechudp.Config + }{ + { + Name: "Single Frequency Plan", + Config: &semtechudp.Config{ + SX1301Conf: []*shared.SX1301Config{ + getSX1301Conf(t), + }, + GatewayConf: getGtwConfig(t), + }, + }, + { + Name: "Multiple Frequency Plans", + Config: &semtechudp.Config{ + SX1301Conf: []*shared.SX1301Config{ + getSX1301Conf(t), + getSX1301Conf(t), + getSX1301Conf(t), + }, + GatewayConf: getGtwConfig(t), + }, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.Name, func(t *testing.T) { + t.Parallel() + a := assertions.New(t) + marshalled, err := json.Marshal(tc.Config) + if !a.So(err, should.BeNil) { + t.FailNow() + } + + var cfg2 semtechudp.Config + err = json.Unmarshal(marshalled, &cfg2) + if !a.So(err, should.BeNil) { + t.FailNow() + } + + a.So(cfg2, should.Resemble, *tc.Config) + }) + } +} diff --git a/pkg/ratelimit/grpc.go b/pkg/ratelimit/grpc.go index 406f2d6f9b..9a9c9d27d2 100644 --- a/pkg/ratelimit/grpc.go +++ b/pkg/ratelimit/grpc.go @@ -18,7 +18,6 @@ import ( "context" "fmt" - "go.thethings.network/lorawan-stack/v3/pkg/auth" clusterauth "go.thethings.network/lorawan-stack/v3/pkg/auth/cluster" "go.thethings.network/lorawan-stack/v3/pkg/log" "go.thethings.network/lorawan-stack/v3/pkg/rpcmetadata" @@ -44,17 +43,6 @@ func grpcIsClusterAuthCall(ctx context.Context) bool { return rpcmetadata.FromIncomingContext(ctx).AuthType == clusterauth.AuthType } -func grpcAuthTokenID(ctx context.Context) string { - if authValue := rpcmetadata.FromIncomingContext(ctx).AuthValue; authValue != "" { - _, id, _, err := auth.SplitToken(authValue) - if err != nil { - return "unauthenticated" - } - return id - } - return "unauthenticated" -} - // UnaryServerInterceptor returns a gRPC unary server interceptor that rate limits incoming gRPC requests. func UnaryServerInterceptor(limiter Interface) grpc.UnaryServerInterceptor { return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { diff --git a/pkg/ratelimit/grpc_test.go b/pkg/ratelimit/grpc_test.go index 0e42d8295b..d66d1d7ead 100644 --- a/pkg/ratelimit/grpc_test.go +++ b/pkg/ratelimit/grpc_test.go @@ -53,12 +53,6 @@ func (ss *serverStream) SetHeader(md metadata.MD) error { return nil } -func grpcTokenContext(authTokenID string) context.Context { - return metadata.NewIncomingContext(test.Context(), metadata.Pairs( - "authorization", fmt.Sprintf("Bearer NNSXS.%s.authTokenKey", authTokenID), - )) -} - func grpcClusterContext() context.Context { return metadata.NewIncomingContext(test.Context(), metadata.Pairs( "authorization", fmt.Sprintf("%s %X", clusterauth.AuthType, []byte{0x00, 0x01, 0x02}), @@ -82,7 +76,6 @@ func TestGRPC(t *testing.T) { const ( unaryMethod = "/Service/UnaryMethod" - authTokenID = "my-token-id" streamMethod = "/Service/StreamMethod" ) @@ -157,7 +150,7 @@ func TestGRPC(t *testing.T) { t.Run(tc.name, func(t *testing.T) { intercept := ratelimit.UnaryServerInterceptor(tc.limiter) - ctx := grpcTokenContext(authTokenID) + ctx := tokenContext(authTokenID) if tc.cluster { ctx = grpcClusterContext() } @@ -219,7 +212,7 @@ func TestGRPC(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { intercept := ratelimit.StreamServerInterceptor(tc.limiter) - ss := &serverStream{t: t, ctx: grpcTokenContext(authTokenID)} + ss := &serverStream{t: t, ctx: tokenContext(authTokenID)} if tc.cluster { ss.ctx = grpcClusterContext() } @@ -238,7 +231,7 @@ func TestGRPC(t *testing.T) { "grpc:stream:up": &mockLimiter{}, } intercept := ratelimit.StreamServerInterceptor(limiter) - ss := &serverStream{t: t, ctx: grpcTokenContext(authTokenID)} + ss := &serverStream{t: t, ctx: tokenContext(authTokenID)} info := &grpc.StreamServerInfo{FullMethod: streamMethod} keyFromFirstStream := "" diff --git a/pkg/ratelimit/http_test.go b/pkg/ratelimit/http_test.go index 1ab9a6f597..8972b78136 100644 --- a/pkg/ratelimit/http_test.go +++ b/pkg/ratelimit/http_test.go @@ -54,6 +54,42 @@ func TestHTTP(t *testing.T) { a.So(limiter.calledWithResource.Classes(), should.Resemble, []string{class, "http"}) }) + t.Run("PathTemplate", func(t *testing.T) { + limiter.limit = false + limiter.result = ratelimit.Result{Limit: 10} + + restore := ratelimit.SetPathTemplate(func(r *http.Request) (string, bool) { + return "/path/{id}", true + }) + defer restore() + + rec := httptest.NewRecorder() + handler.ServeHTTP(rec, httpRequest("/path/123", "10.10.10.10")) + + a.So(rec.Header().Get("x-rate-limit-limit"), should.Equal, "10") + a.So(rec.Result().StatusCode, should.Equal, http.StatusOK) + + a.So(limiter.calledWithResource.Key(), should.ContainSubstring, "/path/123") + a.So(limiter.calledWithResource.Key(), should.ContainSubstring, "10.10.10.10") + a.So(limiter.calledWithResource.Classes(), should.Resemble, []string{"http:test:/path/{id}", class, "http"}) + }) + + t.Run("AuthToken", func(t *testing.T) { + limiter.limit = false + limiter.result = ratelimit.Result{Limit: 10} + + rec := httptest.NewRecorder() + req := httpRequest("/path", "10.10.10.10").WithContext(tokenContext(authTokenID)) + handler.ServeHTTP(rec, req) + + a.So(rec.Header().Get("x-rate-limit-limit"), should.Equal, "10") + a.So(rec.Result().StatusCode, should.Equal, http.StatusOK) + + a.So(limiter.calledWithResource.Key(), should.ContainSubstring, "/path") + a.So(limiter.calledWithResource.Key(), should.ContainSubstring, authTokenID) + a.So(limiter.calledWithResource.Classes(), should.Resemble, []string{class, "http"}) + }) + t.Run("Limit", func(t *testing.T) { limiter.limit = true rec := httptest.NewRecorder() diff --git a/pkg/ratelimit/resource.go b/pkg/ratelimit/resource.go index afe7b5683f..dfb734d747 100644 --- a/pkg/ratelimit/resource.go +++ b/pkg/ratelimit/resource.go @@ -20,7 +20,10 @@ import ( "net" "net/http" + "github.com/gorilla/mux" + "go.thethings.network/lorawan-stack/v3/pkg/auth" "go.thethings.network/lorawan-stack/v3/pkg/events" + "go.thethings.network/lorawan-stack/v3/pkg/rpcmetadata" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" "go.thethings.network/lorawan-stack/v3/pkg/unique" ) @@ -44,18 +47,51 @@ type resource struct { func (r *resource) Key() string { return r.key } func (r *resource) Classes() []string { return r.classes } +const unauthenticated = "unauthenticated" + +func authTokenID(ctx context.Context) string { + if authValue := rpcmetadata.FromIncomingContext(ctx).AuthValue; authValue != "" { + _, id, _, err := auth.SplitToken(authValue) + if err != nil { + return unauthenticated + } + return id + } + return unauthenticated +} + +var pathTemplate = func(r *http.Request) (string, bool) { + route := mux.CurrentRoute(r) + if route == nil { + return "", false + } + pathTemplate, err := route.GetPathTemplate() + if err != nil { + return "", false + } + return pathTemplate, true +} + // httpRequestResource represents an HTTP request. Avoid using directly, use HTTPMiddleware instead. func httpRequestResource(r *http.Request, class string) Resource { + specificClasses := make([]string, 0, 3) + if template, ok := pathTemplate(r); ok { + specificClasses = append(specificClasses, fmt.Sprintf("%s:%s", class, template)) + } + callerInfo := fmt.Sprintf("ip:%s", httpRemoteIP(r)) + if authTokenID := authTokenID(r.Context()); authTokenID != unauthenticated { + callerInfo = fmt.Sprintf("token:%s", authTokenID) + } return &resource{ - key: fmt.Sprintf("%s:ip:%s:url:%s", class, httpRemoteIP(r), r.URL.Path), - classes: []string{class, "http"}, + key: fmt.Sprintf("%s:%s:url:%s", class, callerInfo, r.URL.Path), + classes: append(specificClasses, class, "http"), } } // grpcMethodResource represents a gRPC request. func grpcMethodResource(ctx context.Context, fullMethod string, req any) Resource { key := fmt.Sprintf("grpc:method:%s:%s", fullMethod, grpcEntityFromRequest(ctx, req)) - if authTokenID := grpcAuthTokenID(ctx); authTokenID != "" { + if authTokenID := authTokenID(ctx); authTokenID != unauthenticated { key = fmt.Sprintf("%s:token:%s", key, authTokenID) } return &resource{ @@ -67,7 +103,7 @@ func grpcMethodResource(ctx context.Context, fullMethod string, req any) Resourc // grpcStreamAcceptResource represents a new gRPC server stream. func grpcStreamAcceptResource(ctx context.Context, fullMethod string) Resource { key := fmt.Sprintf("grpc:stream:accept:%s", fullMethod) - if authTokenID := grpcAuthTokenID(ctx); authTokenID != "" { + if authTokenID := authTokenID(ctx); authTokenID != unauthenticated { key = fmt.Sprintf("%s:token:%s", key, authTokenID) } return &resource{ @@ -148,6 +184,15 @@ func ApplicationWebhooksDownResource(ctx context.Context, ids *ttnpb.EndDeviceId } } +// ConsoleEventsRequestResource represents a request for events from the Console. +func ConsoleEventsRequestResource(callerID string) Resource { + key := fmt.Sprintf("console:internal:events:request:%s", callerID) + return &resource{ + key: key, + classes: []string{"http:console:internal:events"}, + } +} + // NewCustomResource returns a new resource. It is used internally by other components. func NewCustomResource(key string, classes ...string) Resource { return &resource{key, classes} diff --git a/pkg/webui/console/containers/device-profile-section/device-card/connect.js b/pkg/ratelimit/resource_util_test.go similarity index 58% rename from pkg/webui/console/containers/device-profile-section/device-card/connect.js rename to pkg/ratelimit/resource_util_test.go index 0ab4bb6764..a94522a257 100644 --- a/pkg/webui/console/containers/device-profile-section/device-card/connect.js +++ b/pkg/ratelimit/resource_util_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,16 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { connect } from 'react-redux' +package ratelimit -import { selectDeviceModelById } from '@console/store/selectors/device-repository' +import "net/http" -const mapStateToProps = (state, props) => { - const { brandId, modelId } = props - - return { - model: selectDeviceModelById(state, brandId, modelId), - } +// SetPathTemplate sets the path template function for HTTP rate limiting. +func SetPathTemplate(f func(*http.Request) (string, bool)) func() { + old := pathTemplate + pathTemplate = f + return func() { pathTemplate = old } } - -export default DeviceCard => connect(mapStateToProps)(DeviceCard) diff --git a/pkg/webui/console/containers/device-profile-section/device-selection/hw-version-select/connect.js b/pkg/ratelimit/util_test.go similarity index 56% rename from pkg/webui/console/containers/device-profile-section/device-selection/hw-version-select/connect.js rename to pkg/ratelimit/util_test.go index 3f1b4282db..7aaf76f6f4 100644 --- a/pkg/webui/console/containers/device-profile-section/device-selection/hw-version-select/connect.js +++ b/pkg/ratelimit/util_test.go @@ -1,4 +1,4 @@ -// Copyright © 2022 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,16 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { connect } from 'react-redux' +package ratelimit_test -import { selectDeviceModelHardwareVersions } from '@console/store/selectors/device-repository' +import ( + "context" + "fmt" -const mapStateToProps = (state, props) => { - const { brandId, modelId } = props + "go.thethings.network/lorawan-stack/v3/pkg/util/test" + "google.golang.org/grpc/metadata" +) - return { - versions: selectDeviceModelHardwareVersions(state, brandId, modelId), - } -} +const authTokenID = "my-token-id" -export default HardwareVersionSelect => connect(mapStateToProps)(HardwareVersionSelect) +func tokenContext(authTokenID string) context.Context { + return metadata.NewIncomingContext(test.Context(), metadata.Pairs( + "authorization", fmt.Sprintf("Bearer NNSXS.%s.authTokenKey", authTokenID), + )) +} diff --git a/pkg/redis/redis.go b/pkg/redis/redis.go index 1f88355d9e..7c66bb1d06 100644 --- a/pkg/redis/redis.go +++ b/pkg/redis/redis.go @@ -696,13 +696,17 @@ func (q *TaskQueue) Pop(ctx context.Context, consumerID string, r redis.Cmdable, return popTask(ctx, r, q.Group, consumerID, f, q.Key, q.StreamBlockLimit) } -var deduplicateProtosScript = redis.NewScript(`local exp = ARGV[1] +var deduplicateProtosScript = redis.NewScript(`local exp = table.remove(ARGV, 1) +local limit = tonumber(table.remove(ARGV, 1)) local ok = redis.call('set', KEYS[1], '', 'px', exp, 'nx') -if #ARGV > 1 then - table.remove(ARGV, 1) + +if #ARGV > 0 then redis.call('rpush', KEYS[2], unpack(ARGV)) local ttl = redis.call('pttl', KEYS[1]) redis.call('pexpire', KEYS[2], ttl) + if limit > 0 then + redis.call('ltrim', KEYS[2], -limit, -1) + end end if ok then return 1 @@ -728,12 +732,19 @@ func milliseconds(d time.Duration) int64 { return ms } -// DeduplicateProtos deduplicates protos using key k. It stores a lock at LockKey(k) and the list of collected protos at ListKey(k). +// DeduplicateProtos deduplicates protos using key k. It stores a lock at LockKey(k) +// and the list of collected protos at ListKey(k). +// If the number of protos exceeds limit, the messages are trimmed from the start of the list. func DeduplicateProtos( - ctx context.Context, r redis.Scripter, k string, window time.Duration, msgs ...proto.Message, + ctx context.Context, r redis.Scripter, k string, window time.Duration, limit int, msgs ...proto.Message, ) (bool, error) { - args := make([]any, 0, 1+len(msgs)) + args := make([]any, 0, 2+len(msgs)) args = append(args, milliseconds(window)) + args = append(args, limit) + if n := len(msgs) - limit; n > 0 { + msgs = msgs[n:] + } + for _, msg := range msgs { s, err := MarshalProto(msg) if err != nil { @@ -885,17 +896,23 @@ func LockedWatch(ctx context.Context, r WatchCmdable, k, id string, expiration t return nil } -// RangeStreams sequentially iterates over all non-acknowledged messages in streams calling f with at most count messages. +// RangeStreams sequentially iterates over all non-acknowledged messages in streams calling f with at most count +// messages. f must acknowledge the messages which have been processed. // RangeStreams assumes that within its lifetime it is the only consumer within group group using ID id. // RangeStreams iterates over all pending messages, which have been idle for at least minIdle milliseconds first. -func RangeStreams(ctx context.Context, r redis.Cmdable, group, id string, count int64, minIdle time.Duration, f func(string, ...redis.XMessage) error, streams ...string) error { - var ack func(context.Context, string, ...redis.XMessage) error - { - ids := make([]string, 0, int(count)) - ack = func(ctx context.Context, stream string, msgs ...redis.XMessage) error { - ids = ids[:0] - for _, msg := range msgs { - ids = append(ids, msg.ID) +func RangeStreams( + ctx context.Context, + r redis.Cmdable, + group, id string, + count int64, + minIdle time.Duration, + f func(string, func(...string) error, ...redis.XMessage) error, + streams ...string, +) error { + makeAck := func(stream string) func(...string) error { + return func(ids ...string) error { + if len(ids) == 0 { + return nil } _, err := r.Pipelined(ctx, func(p redis.Pipeliner) error { // NOTE: Both calls below copy contents of ids internally. @@ -903,13 +920,17 @@ func RangeStreams(ctx context.Context, r redis.Cmdable, group, id string, count p.XDel(ctx, stream, ids...) return nil }) - return err + if err != nil { + return ConvertError(err) + } + return nil } } for _, stream := range streams { - for start := "-"; ; { - msgs, lastID, err := r.XAutoClaim(ctx, &redis.XAutoClaimArgs{ + for start := "-"; start != "0-0"; { + var err error + _, start, err = r.XAutoClaimJustID(ctx, &redis.XAutoClaimArgs{ Stream: stream, Group: group, Consumer: id, @@ -918,38 +939,27 @@ func RangeStreams(ctx context.Context, r redis.Cmdable, group, id string, count Count: count, }).Result() if err != nil { - return err - } - if len(msgs) == 0 { - break + return ConvertError(err) } - if err := f(stream, msgs...); err != nil { - return err - } - if err := ack(ctx, stream, msgs...); err != nil { - return err - } - start = lastID } } streamCount := len(streams) - streamsArg := make([]string, 2*streamCount) - idsArg := make([]string, 2*streamCount) - for i, stream := range streams { - j := i * 2 - streamsArg[j], streamsArg[j+1], idsArg[j], idsArg[j+1] = stream, stream, "0", ">" + args := make([]string, 2*streamCount) + streamsArg := args[:streamCount] + idsArg := args[streamCount:] + for i := range streams { + streamsArg[i], idsArg[i] = streams[i], "0" } - drainedOld := make(map[string]struct{}, streamCount) -outer: + finishedOld, block := false, time.Duration(-1) for { rets, err := r.XReadGroup(ctx, &redis.XReadGroupArgs{ Group: group, Consumer: id, - Streams: append(streamsArg, idsArg...), + Streams: args, Count: count, - Block: -1, // do not block + Block: block, }).Result() if err != nil { if errors.Is(err, redis.Nil) { @@ -958,38 +968,33 @@ outer: return ConvertError(err) } + cont := false for i, ret := range rets { - if idsArg[i] == "0" && len(ret.Messages) < int(count) { - drainedOld[ret.Stream] = struct{}{} - } - if len(ret.Messages) == 0 { - if i == len(rets)-1 { - return nil - } + n := int64(len(ret.Messages)) + if n == 0 { continue } - - if err := f(ret.Stream, ret.Messages...); err != nil { - return err - } - if err := ack(ctx, ret.Stream, ret.Messages...); err != nil { + cont = cont || n == count + idsArg[i] = ret.Messages[len(ret.Messages)-1].ID + if err := f(ret.Stream, makeAck(ret.Stream), ret.Messages...); err != nil { return err } - if len(ret.Messages) == int(count) { - continue outer - } } - streamsArg = streamsArg[:0] - idsArg = idsArg[:0] - for _, stream := range streams { - _, ok := drainedOld[stream] - if !ok { - streamsArg = append(streamsArg, stream) - idsArg = append(idsArg, "0") + switch { + case cont: + // At least one stream has returned `count` messages. + case finishedOld: + // All streams have returned less than `count` messages, + // and we have already processed all of the old and new messages. + return nil + default: // !cont && !finishedOld + // All streams have returned less than `count` messages, + // and we have processed all of the old messages. + finishedOld, block = true, minIdle + for i := range streams { + idsArg[i] = ">" } - streamsArg = append(streamsArg, stream) - idsArg = append(idsArg, ">") } } } diff --git a/pkg/redis/redis_test.go b/pkg/redis/redis_test.go index ed247ceca2..ce433375d6 100644 --- a/pkg/redis/redis_test.go +++ b/pkg/redis/redis_test.go @@ -487,57 +487,62 @@ func TestTaskQueue(t *testing.T) { } } +func makeProto(t *testing.T, s string) proto.Message { + t.Helper() + return &ttnpb.APIKey{Id: s} +} + +func makeProtoString(t *testing.T, s string) string { + t.Helper() + m := makeProto(t, s) + return test.Must(MarshalProto(m)) +} + func TestProtoDeduplicator(t *testing.T) { a, ctx := test.New(t) cl, flush := test.NewRedis(ctx, "redis_test") defer flush() defer cl.Close() - - makeProto := func(s string) proto.Message { - return &ttnpb.APIKey{Id: s} - } - makeProtoString := func(s string) string { - m := makeProto(s) - s, _ = MarshalProto(m) - return s - } + limit := 50 ttl := (1 << 12) * test.Delay key1 := cl.Key("test1") key2 := cl.Key("test2") - v, err := DeduplicateProtos(ctx, cl, key1, ttl) + v, err := DeduplicateProtos(ctx, cl, key1, ttl, limit) if !a.So(err, should.BeNil) { t.FailNow() } a.So(v, should.BeTrue) - v, err = DeduplicateProtos(ctx, cl, key1, ttl, makeProto("proto1")) + v, err = DeduplicateProtos(ctx, cl, key1, ttl, limit, makeProto(t, "proto1")) if !a.So(err, should.BeNil) { t.FailNow() } a.So(v, should.BeFalse) - v, err = DeduplicateProtos(ctx, cl, key2, ttl, makeProto("proto1")) + v, err = DeduplicateProtos(ctx, cl, key2, ttl, limit, makeProto(t, "proto1")) if !a.So(err, should.BeNil) { t.FailNow() } a.So(v, should.BeTrue) - v, err = DeduplicateProtos(ctx, cl, key1, ttl, makeProto("proto1")) + v, err = DeduplicateProtos(ctx, cl, key1, ttl, limit, makeProto(t, "proto1")) if !a.So(err, should.BeNil) { t.FailNow() } a.So(v, should.BeFalse) - v, err = DeduplicateProtos(ctx, cl, key1, ttl, makeProto("proto2"), makeProto("proto3")) + v, err = DeduplicateProtos( + ctx, cl, key1, ttl, limit, makeProto(t, "proto2"), makeProto(t, "proto3"), + ) if !a.So(err, should.BeNil) { t.FailNow() } a.So(v, should.BeFalse) - v, err = DeduplicateProtos(ctx, cl, key2, ttl, makeProto("proto2")) + v, err = DeduplicateProtos(ctx, cl, key2, ttl, limit, makeProto(t, "proto2")) if !a.So(err, should.BeNil) { t.FailNow() } @@ -556,10 +561,10 @@ func TestProtoDeduplicator(t *testing.T) { t.FailNow() } a.So(ss, should.Resemble, []string{ - makeProtoString("proto1"), - makeProtoString("proto1"), - makeProtoString("proto2"), - makeProtoString("proto3"), + makeProtoString(t, "proto1"), + makeProtoString(t, "proto1"), + makeProtoString(t, "proto2"), + makeProtoString(t, "proto3"), }) a.So(lockTTL, should.BeGreaterThan, 0) a.So(lockTTL, should.BeLessThanOrEqualTo, ttl) @@ -579,8 +584,8 @@ func TestProtoDeduplicator(t *testing.T) { t.FailNow() } a.So(ss, should.Resemble, []string{ - makeProtoString("proto1"), - makeProtoString("proto2"), + makeProtoString(t, "proto1"), + makeProtoString(t, "proto2"), }) a.So(lockTTL, should.BeGreaterThan, 0) a.So(lockTTL, should.BeLessThanOrEqualTo, ttl) @@ -588,6 +593,64 @@ func TestProtoDeduplicator(t *testing.T) { a.So(listTTL, should.BeLessThanOrEqualTo, ttl) } +func TestProtoDeduplicatorRespectsLimit(t *testing.T) { + t.Parallel() + a, ctx := test.New(t) + cl, flush := test.NewRedis(ctx, "redis_test") + defer flush() + defer cl.Close() + + ttl := (1 << 12) * test.Delay + key := cl.Key("test1") + limit := 30 + protoID := 0 + + for i := 0; i < limit+3; i++ { + s := fmt.Sprintf("proto%d", protoID) + _, err := DeduplicateProtos(ctx, cl, key, ttl, limit, makeProto(t, s)) + if !a.So(err, should.BeNil) { + t.FailNow() + } + protoID++ + } + + actual, err := cl.LRange(ctx, ListKey(key), 0, -1).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(actual, should.HaveLength, limit) + expected := make([]string, limit) + for i := limit - 1; i >= 0; i-- { + s := fmt.Sprintf("proto%d", protoID-limit+i) + expected[i] = makeProtoString(t, s) + } + a.So(actual, should.Resemble, expected) + + bulkedProtosLen := limit + 5 + bulkedProtos := make([]proto.Message, bulkedProtosLen) + for i := 0; i < bulkedProtosLen; i++ { + s := fmt.Sprintf("proto%d", protoID) + bulkedProtos[i] = makeProto(t, s) + protoID++ + } + + if _, err := DeduplicateProtos(ctx, cl, key, ttl, limit, bulkedProtos...); !a.So(err, should.BeNil) { + t.FailNow() + } + + actual, err = cl.LRange(ctx, ListKey(key), 0, -1).Result() + if !a.So(err, should.BeNil) { + t.FailNow() + } + a.So(actual, should.HaveLength, limit) + expected = make([]string, limit) + for i := limit - 1; i >= 0; i-- { + s := fmt.Sprintf("proto%d", protoID-limit+i) + expected[i] = makeProtoString(t, s) + } + a.So(actual, should.Resemble, expected) +} + func TestMutex(t *testing.T) { a, ctx := test.New(t) diff --git a/pkg/rpcserver/rpcserver.go b/pkg/rpcserver/rpcserver.go index 3d313ba9e9..0778a24c44 100644 --- a/pkg/rpcserver/rpcserver.go +++ b/pkg/rpcserver/rpcserver.go @@ -267,6 +267,9 @@ func New(ctx context.Context, opts ...Option) *Server { } return s, false }), + runtime.WithOutgoingTrailerMatcher(func(s string) (string, bool) { + return s, false + }), runtime.WithDisablePathLengthFallback(), ) return server diff --git a/pkg/specification/relayspec/relay.go b/pkg/specification/relayspec/relay.go new file mode 100644 index 0000000000..81b8b1ebbd --- /dev/null +++ b/pkg/specification/relayspec/relay.go @@ -0,0 +1,24 @@ +// Copyright © 2023 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 relayspec contains LoRaWAN relay related functionality. +package relayspec + +import "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" + +// FPort is the FPort used for the relay forwarding protocol. +const FPort = 226 + +// GatewayIdentifiers is the GatewayIdentifiers used for relay end devices. +var GatewayIdentifiers = &ttnpb.GatewayIdentifiers{GatewayId: "relay"} diff --git a/pkg/ttnpb/configuration_services.pb.go b/pkg/ttnpb/configuration_services.pb.go index 8efa76b9df..4cb3b3c269 100644 --- a/pkg/ttnpb/configuration_services.pb.go +++ b/pkg/ttnpb/configuration_services.pb.go @@ -46,6 +46,8 @@ type ListFrequencyPlansRequest struct { // Optional base frequency in MHz for hardware support (433, 470, 868 or 915) BaseFrequency uint32 `protobuf:"varint,1,opt,name=base_frequency,json=baseFrequency,proto3" json:"base_frequency,omitempty"` + // Optional Band ID to filter the results. + BandId string `protobuf:"bytes,2,opt,name=band_id,json=bandId,proto3" json:"band_id,omitempty"` } func (x *ListFrequencyPlansRequest) Reset() { @@ -87,6 +89,13 @@ func (x *ListFrequencyPlansRequest) GetBaseFrequency() uint32 { return 0 } +func (x *ListFrequencyPlansRequest) GetBandId() string { + if x != nil { + return x.BandId + } + return "" +} + type FrequencyPlanDescription struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -98,6 +107,7 @@ type FrequencyPlanDescription struct { Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` // Base frequency in MHz for hardware support (433, 470, 868 or 915) BaseFrequency uint32 `protobuf:"varint,4,opt,name=base_frequency,json=baseFrequency,proto3" json:"base_frequency,omitempty"` + BandId string `protobuf:"bytes,5,opt,name=band_id,json=bandId,proto3" json:"band_id,omitempty"` } func (x *FrequencyPlanDescription) Reset() { @@ -160,6 +170,13 @@ func (x *FrequencyPlanDescription) GetBaseFrequency() uint32 { return 0 } +func (x *FrequencyPlanDescription) GetBandId() string { + if x != nil { + return x.BandId + } + return "" +} + type ListFrequencyPlansResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -390,6 +407,8 @@ type BandDescription struct { MaxRetransmitTimeout *durationpb.Duration `protobuf:"bytes,21,opt,name=max_retransmit_timeout,json=maxRetransmitTimeout,proto3" json:"max_retransmit_timeout,omitempty"` TxOffset []float32 `protobuf:"fixed32,22,rep,packed,name=tx_offset,json=txOffset,proto3" json:"tx_offset,omitempty"` MaxAdrDataRateIndex DataRateIndex `protobuf:"varint,23,opt,name=max_adr_data_rate_index,json=maxAdrDataRateIndex,proto3,enum=ttn.lorawan.v3.DataRateIndex" json:"max_adr_data_rate_index,omitempty"` + RelayForwardDelay *durationpb.Duration `protobuf:"bytes,34,opt,name=relay_forward_delay,json=relayForwardDelay,proto3" json:"relay_forward_delay,omitempty"` + RelayReceiveDelay *durationpb.Duration `protobuf:"bytes,35,opt,name=relay_receive_delay,json=relayReceiveDelay,proto3" json:"relay_receive_delay,omitempty"` TxParamSetupReqSupport bool `protobuf:"varint,24,opt,name=tx_param_setup_req_support,json=txParamSetupReqSupport,proto3" json:"tx_param_setup_req_support,omitempty"` DefaultMaxEirp float32 `protobuf:"fixed32,25,opt,name=default_max_eirp,json=defaultMaxEirp,proto3" json:"default_max_eirp,omitempty"` DefaultRx2Parameters *BandDescription_Rx2Parameters `protobuf:"bytes,30,opt,name=default_rx2_parameters,json=defaultRx2Parameters,proto3" json:"default_rx2_parameters,omitempty"` @@ -590,6 +609,20 @@ func (x *BandDescription) GetMaxAdrDataRateIndex() DataRateIndex { return DataRateIndex_DATA_RATE_0 } +func (x *BandDescription) GetRelayForwardDelay() *durationpb.Duration { + if x != nil { + return x.RelayForwardDelay + } + return nil +} + +func (x *BandDescription) GetRelayReceiveDelay() *durationpb.Duration { + if x != nil { + return x.RelayReceiveDelay + } + return nil +} + func (x *BandDescription) GetTxParamSetupReqSupport() bool { if x != nil { return x.TxParamSetupReqSupport @@ -1256,303 +1289,316 @@ var file_ttn_lorawan_v3_configuration_services_proto_rawDesc = []byte{ 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4c, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x65, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x62, 0x61, 0x73, 0x65, - 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, - 0x00, 0x10, 0x01, 0x22, 0x7e, 0x0a, 0x18, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x50, 0x6c, 0x61, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x17, 0x0a, 0x07, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x62, 0x61, 0x73, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x79, 0x22, 0x6f, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x51, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x70, - 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x46, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, - 0x6c, 0x61, 0x6e, 0x73, 0x22, 0x3a, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, - 0x22, 0xd6, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0c, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, - 0x66, 0x6f, 0x1a, 0x65, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0c, 0x70, 0x68, - 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, - 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x68, - 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7c, 0x0a, 0x10, 0x4c, 0x69, 0x73, - 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x0b, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x0a, 0x70, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xc7, 0x17, 0x0a, 0x0f, 0x42, 0x61, 0x6e, 0x64, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3e, 0x0a, 0x06, 0x62, - 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, - 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x65, 0x61, - 0x63, 0x6f, 0x6e, 0x52, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x15, 0x70, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x69, 0x65, 0x73, 0x18, 0x20, 0x20, 0x03, 0x28, 0x04, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x67, - 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, - 0x2e, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x6d, 0x61, - 0x78, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, - 0x50, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, - 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x13, 0x6d, 0x61, 0x78, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, - 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x4e, 0x0a, 0x09, 0x73, - 0x75, 0x62, 0x5f, 0x62, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, + 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, + 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, + 0x49, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0x97, 0x01, 0x0a, + 0x18, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x73, 0x65, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, + 0x62, 0x61, 0x73, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x17, 0x0a, + 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x22, 0x6f, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x46, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x22, 0x3a, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x68, + 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, + 0x00, 0x10, 0x01, 0x22, 0xd6, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, + 0x0a, 0x0c, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x65, 0x0a, 0x0b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3d, 0x0a, + 0x0c, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x0b, 0x70, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7c, 0x0a, 0x10, + 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x17, 0x0a, 0x07, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x62, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x0b, 0x70, 0x68, 0x79, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x53, 0x75, 0x62, 0x42, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x52, 0x08, 0x73, 0x75, 0x62, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x0a, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x09, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x72, - 0x65, 0x71, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0e, 0x66, 0x72, 0x65, 0x71, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, - 0x69, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x5f, 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x10, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x43, 0x66, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x46, 0x4c, 0x69, 0x73, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x66, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x41, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, - 0x5f, 0x31, 0x18, 0x0d, 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, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x44, 0x65, 0x6c, 0x61, - 0x79, 0x31, 0x12, 0x41, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, - 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x18, 0x0e, 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, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x44, - 0x65, 0x6c, 0x61, 0x79, 0x32, 0x12, 0x48, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, - 0x63, 0x65, 0x70, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x18, 0x0f, 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, 0x10, 0x6a, - 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x31, 0x12, - 0x48, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x18, 0x10, 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, 0x10, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x32, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, - 0x5f, 0x66, 0x63, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x70, 0x18, 0x11, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0a, 0x6d, 0x61, 0x78, 0x46, 0x63, 0x6e, 0x74, 0x47, 0x61, 0x70, 0x12, 0x30, 0x0a, 0x14, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x5f, - 0x61, 0x64, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x41, 0x64, 0x72, 0x12, 0x47, 0x0a, - 0x0d, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x64, 0x72, 0x41, 0x63, - 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4f, 0x0a, 0x16, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x65, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x18, 0x14, 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, 0x14, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4f, 0x0a, 0x16, 0x6d, 0x61, 0x78, 0x5f, 0x72, - 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, - 0x74, 0x18, 0x15, 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, 0x14, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x78, 0x5f, 0x6f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x16, 0x20, 0x03, 0x28, 0x02, 0x52, 0x08, 0x74, 0x78, 0x4f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x53, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x64, 0x72, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x17, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x13, 0x6d, 0x61, 0x78, 0x41, 0x64, 0x72, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3a, 0x0a, 0x1a, 0x74, 0x78, - 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, - 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, - 0x74, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x53, - 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x19, 0x20, 0x01, 0x28, 0x02, - 0x52, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, - 0x12, 0x63, 0x0a, 0x16, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x78, 0x32, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x52, 0x78, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, - 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x52, 0x78, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x51, 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x64, 0x77, - 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x70, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x01, 0x22, 0xdd, 0x18, 0x0a, 0x0f, 0x42, + 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3e, + 0x0a, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x0d, 0x62, 0x6f, 0x6f, 0x74, 0x44, - 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x45, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, - 0x79, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x1a, - 0x9e, 0x01, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0f, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x61, 0x74, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, - 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x69, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, - 0x1a, 0xad, 0x01, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, - 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x41, 0x0a, 0x0d, 0x6d, 0x69, - 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, - 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x1a, 0x97, 0x01, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x42, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, - 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x6d, - 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x64, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x02, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x1a, 0x42, 0x0a, 0x0c, 0x42, 0x61, - 0x6e, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x04, 0x72, 0x61, - 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, - 0x74, 0x65, 0x52, 0x04, 0x72, 0x61, 0x74, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0x6a, - 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x42, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x52, 0x06, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x12, 0x32, + 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x20, 0x20, 0x03, 0x28, 0x04, 0x52, 0x13, 0x70, + 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, + 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x11, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x73, 0x12, 0x50, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, + 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x32, 0x0a, 0x15, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6d, 0x61, 0x78, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x54, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e, + 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x10, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x4e, + 0x0a, 0x09, 0x73, 0x75, 0x62, 0x5f, 0x62, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x74, 0x0a, 0x0d, 0x52, 0x78, - 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x45, 0x0a, 0x0f, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x1a, 0x7b, 0x0a, 0x09, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x34, 0x0a, - 0x07, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x6f, 0x6e, 0x2e, 0x53, 0x75, 0x62, 0x42, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x52, 0x08, 0x73, 0x75, 0x62, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x4d, + 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, + 0x0f, 0x66, 0x72, 0x65, 0x71, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x66, 0x72, 0x65, 0x71, 0x4d, 0x75, 0x6c, 0x74, + 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x5f, 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x43, 0x66, + 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x46, 0x4c, 0x69, + 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x63, 0x66, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, + 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x18, 0x0d, 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, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x44, + 0x65, 0x6c, 0x61, 0x79, 0x31, 0x12, 0x41, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x07, 0x75, 0x70, 0x6c, 0x69, - 0x6e, 0x6b, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x1a, 0x93, 0x02, - 0x0a, 0x0f, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x73, 0x12, 0x62, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x32, 0x12, 0x48, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, + 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x31, 0x18, + 0x0f, 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, 0x10, 0x6a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x44, 0x65, 0x6c, 0x61, + 0x79, 0x31, 0x12, 0x48, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, + 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x32, 0x18, 0x10, 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, 0x10, 0x6a, 0x6f, 0x69, 0x6e, + 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x32, 0x12, 0x20, 0x0a, 0x0c, + 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x63, 0x6e, 0x74, 0x5f, 0x67, 0x61, 0x70, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x46, 0x63, 0x6e, 0x74, 0x47, 0x61, 0x70, 0x12, 0x30, + 0x0a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x64, 0x79, 0x6e, 0x61, 0x6d, + 0x69, 0x63, 0x5f, 0x61, 0x64, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x41, 0x64, 0x72, + 0x12, 0x47, 0x0a, 0x0d, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x0b, 0x61, 0x64, + 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4f, 0x0a, 0x16, 0x6d, 0x69, 0x6e, + 0x5f, 0x72, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x14, 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, 0x14, 0x6d, 0x69, 0x6e, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x6d, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x4f, 0x0a, 0x16, 0x6d, 0x61, + 0x78, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x6d, 0x69, 0x74, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x18, 0x15, 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, 0x14, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x6d, 0x69, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x74, + 0x78, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x16, 0x20, 0x03, 0x28, 0x02, 0x52, 0x08, + 0x74, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x53, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, + 0x61, 0x64, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x13, 0x6d, 0x61, 0x78, 0x41, 0x64, 0x72, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x49, 0x0a, + 0x13, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x64, + 0x65, 0x6c, 0x61, 0x79, 0x18, 0x22, 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, 0x11, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x49, 0x0a, 0x13, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, + 0x23, 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, 0x11, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x44, 0x65, + 0x6c, 0x61, 0x79, 0x12, 0x3a, 0x0a, 0x1a, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, + 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x74, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, + 0x28, 0x0a, 0x10, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x65, + 0x69, 0x72, 0x70, 0x18, 0x19, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x4d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x12, 0x63, 0x0a, 0x16, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x78, 0x32, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x52, 0x78, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x51, + 0x0a, 0x0f, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, - 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x1a, 0x9b, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, - 0x4f, 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x5f, 0x66, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, - 0x61, 0x63, 0x6b, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x45, 0x0a, 0x0f, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x1a, 0x10, 0x1b, 0x4a, - 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, - 0x1e, 0x22, 0xba, 0x03, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, + 0x6d, 0x65, 0x52, 0x0d, 0x62, 0x6f, 0x6f, 0x74, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x45, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x52, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x1a, 0x9e, 0x01, 0x0a, 0x06, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x12, 0x45, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0d, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0a, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x04, + 0x52, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x4a, 0x04, 0x08, + 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0xad, 0x01, 0x0a, 0x07, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x79, 0x12, 0x41, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x41, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0b, 0x6d, 0x61, + 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x1a, 0x97, 0x01, 0x0a, 0x11, 0x53, 0x75, + 0x62, 0x42, 0x61, 0x6e, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, + 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x75, 0x74, + 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x09, 0x64, + 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, + 0x65, 0x69, 0x72, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x45, + 0x69, 0x72, 0x70, 0x1a, 0x42, 0x0a, 0x0c, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x12, 0x2c, 0x0a, 0x04, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x04, 0x72, 0x61, 0x74, + 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0x6a, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x42, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x61, 0x6e, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x74, 0x0a, 0x0d, 0x52, 0x78, 0x32, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x73, 0x12, 0x45, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0d, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, + 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x1a, 0x7b, 0x0a, 0x09, 0x44, 0x77, 0x65, + 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x07, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x38, 0x0a, 0x09, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x09, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x1a, 0x93, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x62, 0x0a, 0x0c, 0x77, 0x6f, + 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x3f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x1a, 0x9b, + 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x61, 0x63, 0x6b, 0x46, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x45, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, + 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x0d, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4a, 0x04, 0x08, 0x03, + 0x10, 0x04, 0x4a, 0x04, 0x08, 0x1a, 0x10, 0x1b, 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x4a, 0x04, + 0x08, 0x1c, 0x10, 0x1d, 0x4a, 0x04, 0x08, 0x1d, 0x10, 0x1e, 0x22, 0xba, 0x03, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x1a, 0xce, 0x01, 0x0a, 0x18, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x61, - 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x58, 0x0a, - 0x04, 0x62, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x74, 0x74, + 0x12, 0x57, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0xce, 0x01, 0x0a, 0x18, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x58, 0x0a, 0x04, 0x62, 0x61, 0x6e, 0x64, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x64, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x62, 0x61, 0x6e, 0x64, + 0x1a, 0x58, 0x0a, 0x09, 0x42, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x7b, 0x0a, 0x11, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 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, 0x50, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x6e, + 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xef, 0x03, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x93, 0x01, 0x0a, 0x12, 0x4c, 0x69, + 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, + 0x12, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, + 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x04, 0x62, 0x61, 0x6e, 0x64, 0x1a, 0x58, 0x0a, 0x09, 0x42, 0x61, 0x6e, 0x64, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x7b, 0x0a, 0x11, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 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, 0x50, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, - 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x64, 0x42, 0x61, 0x6e, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xef, - 0x03, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x93, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x12, 0x84, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x68, - 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, + 0x1e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x12, + 0x84, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, - 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, - 0x12, 0x1b, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2f, 0x70, 0x68, 0x79, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0xc0, 0x01, - 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x20, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x6e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x68, 0x5a, 0x20, 0x12, 0x1e, 0x2f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, 0x64, 0x73, - 0x2f, 0x7b, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x5a, 0x2e, 0x12, 0x2c, 0x2f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, - 0x64, 0x73, 0x2f, 0x7b, 0x62, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x70, 0x68, - 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x7d, 0x12, 0x14, 0x2f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, 0x64, 0x73, - 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, + 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x68, 0x79, 0x2d, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0xc0, 0x01, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x42, + 0x61, 0x6e, 0x64, 0x73, 0x12, 0x20, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x6e, 0x64, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x6e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x68, 0x5a, 0x20, 0x12, 0x1e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x62, 0x61, 0x6e, 0x64, 0x5f, + 0x69, 0x64, 0x7d, 0x5a, 0x2e, 0x12, 0x2c, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x62, 0x61, 0x6e, + 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x7b, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x7d, 0x12, 0x14, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x62, 0x61, 0x6e, 0x64, 0x73, 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 ( @@ -1616,35 +1662,37 @@ var file_ttn_lorawan_v3_configuration_services_proto_depIdxs = []int32{ 23, // 14: ttn.lorawan.v3.BandDescription.min_retransmit_timeout:type_name -> google.protobuf.Duration 23, // 15: ttn.lorawan.v3.BandDescription.max_retransmit_timeout:type_name -> google.protobuf.Duration 25, // 16: ttn.lorawan.v3.BandDescription.max_adr_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 14, // 17: ttn.lorawan.v3.BandDescription.default_rx2_parameters:type_name -> ttn.lorawan.v3.BandDescription.Rx2Parameters - 15, // 18: ttn.lorawan.v3.BandDescription.boot_dwell_time:type_name -> ttn.lorawan.v3.BandDescription.DwellTime - 16, // 19: ttn.lorawan.v3.BandDescription.relay:type_name -> ttn.lorawan.v3.BandDescription.RelayParameters - 19, // 20: ttn.lorawan.v3.ListBandsResponse.descriptions:type_name -> ttn.lorawan.v3.ListBandsResponse.DescriptionsEntry - 21, // 21: ttn.lorawan.v3.GetPhyVersionsResponse.VersionInfo.phy_versions:type_name -> ttn.lorawan.v3.PHYVersion - 25, // 22: ttn.lorawan.v3.BandDescription.Beacon.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 25, // 23: ttn.lorawan.v3.BandDescription.Channel.min_data_rate:type_name -> ttn.lorawan.v3.DataRateIndex - 25, // 24: ttn.lorawan.v3.BandDescription.Channel.max_data_rate:type_name -> ttn.lorawan.v3.DataRateIndex - 26, // 25: ttn.lorawan.v3.BandDescription.BandDataRate.rate:type_name -> ttn.lorawan.v3.DataRate - 12, // 26: ttn.lorawan.v3.BandDescription.DataRatesEntry.value:type_name -> ttn.lorawan.v3.BandDescription.BandDataRate - 25, // 27: ttn.lorawan.v3.BandDescription.Rx2Parameters.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 27, // 28: ttn.lorawan.v3.BandDescription.DwellTime.uplinks:type_name -> google.protobuf.BoolValue - 27, // 29: ttn.lorawan.v3.BandDescription.DwellTime.downlinks:type_name -> google.protobuf.BoolValue - 17, // 30: ttn.lorawan.v3.BandDescription.RelayParameters.wor_channels:type_name -> ttn.lorawan.v3.BandDescription.RelayParameters.RelayWORChannel - 25, // 31: ttn.lorawan.v3.BandDescription.RelayParameters.RelayWORChannel.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 20, // 32: ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.band:type_name -> ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.BandEntry - 18, // 33: ttn.lorawan.v3.ListBandsResponse.DescriptionsEntry.value:type_name -> ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription - 6, // 34: ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.BandEntry.value:type_name -> ttn.lorawan.v3.BandDescription - 0, // 35: ttn.lorawan.v3.Configuration.ListFrequencyPlans:input_type -> ttn.lorawan.v3.ListFrequencyPlansRequest - 3, // 36: ttn.lorawan.v3.Configuration.GetPhyVersions:input_type -> ttn.lorawan.v3.GetPhyVersionsRequest - 5, // 37: ttn.lorawan.v3.Configuration.ListBands:input_type -> ttn.lorawan.v3.ListBandsRequest - 2, // 38: ttn.lorawan.v3.Configuration.ListFrequencyPlans:output_type -> ttn.lorawan.v3.ListFrequencyPlansResponse - 4, // 39: ttn.lorawan.v3.Configuration.GetPhyVersions:output_type -> ttn.lorawan.v3.GetPhyVersionsResponse - 7, // 40: ttn.lorawan.v3.Configuration.ListBands:output_type -> ttn.lorawan.v3.ListBandsResponse - 38, // [38:41] is the sub-list for method output_type - 35, // [35:38] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 23, // 17: ttn.lorawan.v3.BandDescription.relay_forward_delay:type_name -> google.protobuf.Duration + 23, // 18: ttn.lorawan.v3.BandDescription.relay_receive_delay:type_name -> google.protobuf.Duration + 14, // 19: ttn.lorawan.v3.BandDescription.default_rx2_parameters:type_name -> ttn.lorawan.v3.BandDescription.Rx2Parameters + 15, // 20: ttn.lorawan.v3.BandDescription.boot_dwell_time:type_name -> ttn.lorawan.v3.BandDescription.DwellTime + 16, // 21: ttn.lorawan.v3.BandDescription.relay:type_name -> ttn.lorawan.v3.BandDescription.RelayParameters + 19, // 22: ttn.lorawan.v3.ListBandsResponse.descriptions:type_name -> ttn.lorawan.v3.ListBandsResponse.DescriptionsEntry + 21, // 23: ttn.lorawan.v3.GetPhyVersionsResponse.VersionInfo.phy_versions:type_name -> ttn.lorawan.v3.PHYVersion + 25, // 24: ttn.lorawan.v3.BandDescription.Beacon.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 25, // 25: ttn.lorawan.v3.BandDescription.Channel.min_data_rate:type_name -> ttn.lorawan.v3.DataRateIndex + 25, // 26: ttn.lorawan.v3.BandDescription.Channel.max_data_rate:type_name -> ttn.lorawan.v3.DataRateIndex + 26, // 27: ttn.lorawan.v3.BandDescription.BandDataRate.rate:type_name -> ttn.lorawan.v3.DataRate + 12, // 28: ttn.lorawan.v3.BandDescription.DataRatesEntry.value:type_name -> ttn.lorawan.v3.BandDescription.BandDataRate + 25, // 29: ttn.lorawan.v3.BandDescription.Rx2Parameters.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 27, // 30: ttn.lorawan.v3.BandDescription.DwellTime.uplinks:type_name -> google.protobuf.BoolValue + 27, // 31: ttn.lorawan.v3.BandDescription.DwellTime.downlinks:type_name -> google.protobuf.BoolValue + 17, // 32: ttn.lorawan.v3.BandDescription.RelayParameters.wor_channels:type_name -> ttn.lorawan.v3.BandDescription.RelayParameters.RelayWORChannel + 25, // 33: ttn.lorawan.v3.BandDescription.RelayParameters.RelayWORChannel.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 20, // 34: ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.band:type_name -> ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.BandEntry + 18, // 35: ttn.lorawan.v3.ListBandsResponse.DescriptionsEntry.value:type_name -> ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription + 6, // 36: ttn.lorawan.v3.ListBandsResponse.VersionedBandDescription.BandEntry.value:type_name -> ttn.lorawan.v3.BandDescription + 0, // 37: ttn.lorawan.v3.Configuration.ListFrequencyPlans:input_type -> ttn.lorawan.v3.ListFrequencyPlansRequest + 3, // 38: ttn.lorawan.v3.Configuration.GetPhyVersions:input_type -> ttn.lorawan.v3.GetPhyVersionsRequest + 5, // 39: ttn.lorawan.v3.Configuration.ListBands:input_type -> ttn.lorawan.v3.ListBandsRequest + 2, // 40: ttn.lorawan.v3.Configuration.ListFrequencyPlans:output_type -> ttn.lorawan.v3.ListFrequencyPlansResponse + 4, // 41: ttn.lorawan.v3.Configuration.GetPhyVersions:output_type -> ttn.lorawan.v3.GetPhyVersionsResponse + 7, // 42: ttn.lorawan.v3.Configuration.ListBands:output_type -> ttn.lorawan.v3.ListBandsResponse + 40, // [40:43] is the sub-list for method output_type + 37, // [37:40] is the sub-list for method input_type + 37, // [37:37] is the sub-list for extension type_name + 37, // [37:37] is the sub-list for extension extendee + 0, // [0:37] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_configuration_services_proto_init() } diff --git a/pkg/ttnpb/configuration_services.pb.paths.fm.go b/pkg/ttnpb/configuration_services.pb.paths.fm.go index 95895132bb..64564273bb 100644 --- a/pkg/ttnpb/configuration_services.pb.paths.fm.go +++ b/pkg/ttnpb/configuration_services.pb.paths.fm.go @@ -3,13 +3,16 @@ package ttnpb var ListFrequencyPlansRequestFieldPathsNested = []string{ + "band_id", "base_frequency", } var ListFrequencyPlansRequestFieldPathsTopLevel = []string{ + "band_id", "base_frequency", } var FrequencyPlanDescriptionFieldPathsNested = []string{ + "band_id", "base_frequency", "base_id", "id", @@ -17,6 +20,7 @@ var FrequencyPlanDescriptionFieldPathsNested = []string{ } var FrequencyPlanDescriptionFieldPathsTopLevel = []string{ + "band_id", "base_frequency", "base_id", "id", @@ -84,6 +88,8 @@ var BandDescriptionFieldPathsNested = []string{ "receive_delay_2", "relay", "relay.wor_channels", + "relay_forward_delay", + "relay_receive_delay", "sub_bands", "supports_dynamic_adr", "tx_offset", @@ -115,6 +121,8 @@ var BandDescriptionFieldPathsTopLevel = []string{ "receive_delay_1", "receive_delay_2", "relay", + "relay_forward_delay", + "relay_receive_delay", "sub_bands", "supports_dynamic_adr", "tx_offset", diff --git a/pkg/ttnpb/configuration_services.pb.setters.fm.go b/pkg/ttnpb/configuration_services.pb.setters.fm.go index 2c93fe5910..7dfacb8cd4 100644 --- a/pkg/ttnpb/configuration_services.pb.setters.fm.go +++ b/pkg/ttnpb/configuration_services.pb.setters.fm.go @@ -17,6 +17,16 @@ func (dst *ListFrequencyPlansRequest) SetFields(src *ListFrequencyPlansRequest, var zero uint32 dst.BaseFrequency = zero } + case "band_id": + if len(subs) > 0 { + return fmt.Errorf("'band_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.BandId = src.BandId + } else { + var zero string + dst.BandId = zero + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -68,6 +78,16 @@ func (dst *FrequencyPlanDescription) SetFields(src *FrequencyPlanDescription, pa var zero uint32 dst.BaseFrequency = zero } + case "band_id": + if len(subs) > 0 { + return fmt.Errorf("'band_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.BandId = src.BandId + } else { + var zero string + dst.BandId = zero + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -400,6 +420,24 @@ func (dst *BandDescription) SetFields(src *BandDescription, paths ...string) err } else { dst.MaxAdrDataRateIndex = 0 } + case "relay_forward_delay": + if len(subs) > 0 { + return fmt.Errorf("'relay_forward_delay' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.RelayForwardDelay = src.RelayForwardDelay + } else { + dst.RelayForwardDelay = nil + } + case "relay_receive_delay": + if len(subs) > 0 { + return fmt.Errorf("'relay_receive_delay' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.RelayReceiveDelay = src.RelayReceiveDelay + } else { + dst.RelayReceiveDelay = nil + } case "tx_param_setup_req_support": if len(subs) > 0 { return fmt.Errorf("'tx_param_setup_req_support' has no subfields, but %s were specified", subs) diff --git a/pkg/ttnpb/configuration_services.pb.validate.go b/pkg/ttnpb/configuration_services.pb.validate.go index a2e2ad41ba..427ce5ba5d 100644 --- a/pkg/ttnpb/configuration_services.pb.validate.go +++ b/pkg/ttnpb/configuration_services.pb.validate.go @@ -49,6 +49,8 @@ func (m *ListFrequencyPlansRequest) ValidateFields(paths ...string) error { switch name { case "base_frequency": // no validation rules for BaseFrequency + case "band_id": + // no validation rules for BandId default: return ListFrequencyPlansRequestValidationError{ field: name, @@ -139,6 +141,8 @@ func (m *FrequencyPlanDescription) ValidateFields(paths ...string) error { // no validation rules for Name case "base_frequency": // no validation rules for BaseFrequency + case "band_id": + // no validation rules for BandId default: return FrequencyPlanDescriptionValidationError{ field: name, @@ -769,6 +773,30 @@ func (m *BandDescription) ValidateFields(paths ...string) error { case "max_adr_data_rate_index": // no validation rules for MaxAdrDataRateIndex + case "relay_forward_delay": + + if v, ok := interface{}(m.GetRelayForwardDelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return BandDescriptionValidationError{ + field: "relay_forward_delay", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_receive_delay": + + if v, ok := interface{}(m.GetRelayReceiveDelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return BandDescriptionValidationError{ + field: "relay_receive_delay", + reason: "embedded message failed validation", + cause: err, + } + } + } + case "tx_param_setup_req_support": // no validation rules for TxParamSetupReqSupport case "default_max_eirp": diff --git a/pkg/ttnpb/configuration_services_flags.pb.go b/pkg/ttnpb/configuration_services_flags.pb.go index 43a5d0f76c..e4e72481de 100644 --- a/pkg/ttnpb/configuration_services_flags.pb.go +++ b/pkg/ttnpb/configuration_services_flags.pb.go @@ -14,6 +14,7 @@ import ( // AddSetFlagsForListFrequencyPlansRequest adds flags to select fields in ListFrequencyPlansRequest. func AddSetFlagsForListFrequencyPlansRequest(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("base-frequency", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("band-id", prefix), "", flagsplugin.WithHidden(hidden))) } // SetFromFlags sets the ListFrequencyPlansRequest message from flags. @@ -24,6 +25,12 @@ func (m *ListFrequencyPlansRequest) SetFromFlags(flags *pflag.FlagSet, prefix st m.BaseFrequency = val paths = append(paths, flagsplugin.Prefix("base_frequency", prefix)) } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("band_id", prefix)); err != nil { + return nil, err + } else if changed { + m.BandId = val + paths = append(paths, flagsplugin.Prefix("band_id", prefix)) + } return paths, nil } diff --git a/pkg/ttnpb/configuration_services_json.pb.go b/pkg/ttnpb/configuration_services_json.pb.go index 22bbd70238..61586aead8 100644 --- a/pkg/ttnpb/configuration_services_json.pb.go +++ b/pkg/ttnpb/configuration_services_json.pb.go @@ -653,6 +653,24 @@ func (x *BandDescription) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteObjectField("max_adr_data_rate_index") x.MaxAdrDataRateIndex.MarshalProtoJSON(s) } + if x.RelayForwardDelay != nil || s.HasField("relay_forward_delay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_forward_delay") + if x.RelayForwardDelay == nil { + s.WriteNil() + } else { + golang.MarshalDuration(s, x.RelayForwardDelay) + } + } + if x.RelayReceiveDelay != nil || s.HasField("relay_receive_delay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_receive_delay") + if x.RelayReceiveDelay == nil { + s.WriteNil() + } else { + golang.MarshalDuration(s, x.RelayReceiveDelay) + } + } if x.TxParamSetupReqSupport || s.HasField("tx_param_setup_req_support") { s.WriteMoreIf(&wroteField) s.WriteObjectField("tx_param_setup_req_support") @@ -874,6 +892,28 @@ func (x *BandDescription) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { case "max_adr_data_rate_index", "maxAdrDataRateIndex": s.AddField("max_adr_data_rate_index") x.MaxAdrDataRateIndex.UnmarshalProtoJSON(s) + case "relay_forward_delay", "relayForwardDelay": + s.AddField("relay_forward_delay") + if s.ReadNil() { + x.RelayForwardDelay = nil + return + } + v := golang.UnmarshalDuration(s) + if s.Err() != nil { + return + } + x.RelayForwardDelay = v + case "relay_receive_delay", "relayReceiveDelay": + s.AddField("relay_receive_delay") + if s.ReadNil() { + x.RelayReceiveDelay = nil + return + } + v := golang.UnmarshalDuration(s) + if s.Err() != nil { + return + } + x.RelayReceiveDelay = v case "tx_param_setup_req_support", "txParamSetupReqSupport": s.AddField("tx_param_setup_req_support") x.TxParamSetupReqSupport = s.ReadBool() diff --git a/pkg/ttnpb/end_device.go b/pkg/ttnpb/end_device.go index 16b2c1d497..b1f1fe4f82 100644 --- a/pkg/ttnpb/end_device.go +++ b/pkg/ttnpb/end_device.go @@ -59,6 +59,222 @@ func (v *BoolValue) FieldIsZero(p string) bool { panic(fmt.Sprintf("unknown path '%s'", p)) } +// FieldIsZero returns whether path p is zero. +func (v *ServedRelayParameters) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "backoff": + return v.Backoff == 0 + case "mode": + return v.Mode == nil + case "mode.always": + return v.GetAlways() == nil + case "mode.dynamic": + return v.GetDynamic() == nil + case "mode.dynamic.smart_enable_level": + return v.GetDynamic().FieldIsZero("smart_enable_level") + case "mode.end_device_controlled": + return v.GetEndDeviceControlled() == nil + case "second_channel": + return v.SecondChannel == nil + case "second_channel.ack_offset": + return v.SecondChannel.FieldIsZero("ack_offset") + case "second_channel.data_rate_index": + return v.SecondChannel.FieldIsZero("data_rate_index") + case "second_channel.frequency": + return v.SecondChannel.FieldIsZero("frequency") + case "serving_device_id": + return v.ServingDeviceId == "" + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *RelayForwardLimits) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "bucket_size": + return v.BucketSize == 0 + case "reload_rate": + return v.ReloadRate == 0 + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *ServingRelayForwardingLimits) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "reset_behavior": + return v.ResetBehavior == 0 + case "join_requests": + return v.JoinRequests == nil + case "join_requests.bucket_size": + return v.JoinRequests.FieldIsZero("bucket_size") + case "join_requests.reload_rate": + return v.JoinRequests.FieldIsZero("reload_rate") + case "notifications": + return v.Notifications == nil + case "notifications.bucket_size": + return v.Notifications.FieldIsZero("bucket_size") + case "notifications.reload_rate": + return v.Notifications.FieldIsZero("reload_rate") + case "uplink_messages": + return v.UplinkMessages == nil + case "uplink_messages.bucket_size": + return v.UplinkMessages.FieldIsZero("bucket_size") + case "uplink_messages.reload_rate": + return v.UplinkMessages.FieldIsZero("reload_rate") + case "overall": + return v.Overall == nil + case "overall.bucket_size": + return v.Overall.FieldIsZero("bucket_size") + case "overall.reload_rate": + return v.Overall.FieldIsZero("reload_rate") + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *ServingRelayParameters) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "second_channel": + return v.SecondChannel == nil + case "second_channel.ack_offset": + return v.SecondChannel.FieldIsZero("ack_offset") + case "second_channel.data_rate_index": + return v.SecondChannel.FieldIsZero("data_rate_index") + case "second_channel.frequency": + return v.SecondChannel.FieldIsZero("frequency") + case "default_channel_index": + return v.DefaultChannelIndex == 0 + case "cad_periodicity": + return v.CadPeriodicity == 0 + case "uplink_forwarding_rules": + return v.UplinkForwardingRules == nil + case "limits": + return v.Limits == nil + case "limits.reset_behavior": + return v.Limits.FieldIsZero("reset_behavior") + case "limits.join_requests": + return v.Limits.FieldIsZero("join_requests") + case "limits.join_requests.bucket_size": + return v.Limits.FieldIsZero("join_requests.bucket_size") + case "limits.join_requests.reload_rate": + return v.Limits.FieldIsZero("join_requests.reload_rate") + case "limits.notifications": + return v.Limits.FieldIsZero("notifications") + case "limits.notifications.bucket_size": + return v.Limits.FieldIsZero("notifications.bucket_size") + case "limits.notifications.reload_rate": + return v.Limits.FieldIsZero("notifications.reload_rate") + case "limits.uplink_messages": + return v.Limits.FieldIsZero("uplink_messages") + case "limits.uplink_messages.bucket_size": + return v.Limits.FieldIsZero("uplink_messages.bucket_size") + case "limits.uplink_messages.reload_rate": + return v.Limits.FieldIsZero("uplink_messages.reload_rate") + case "limits.overall": + return v.Limits.FieldIsZero("overall") + case "limits.overall.bucket_size": + return v.Limits.FieldIsZero("overall.bucket_size") + case "limits.overall.reload_rate": + return v.Limits.FieldIsZero("overall.reload_rate") + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *RelayParameters) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "mode": + return v.Mode == nil + case "mode.served": + return v.GetServed() == nil + case "mode.served.backoff": + return v.GetServed().FieldIsZero("backoff") + case "mode.served.mode": + return v.GetServed().FieldIsZero("mode") + case "mode.served.mode.always": + return v.GetServed().FieldIsZero("mode.always") + case "mode.served.mode.dynamic": + return v.GetServed().FieldIsZero("mode.dynamic") + case "mode.served.mode.dynamic.smart_enable_level": + return v.GetServed().FieldIsZero("mode.dynamic.smart_enable_level") + case "mode.served.mode.end_device_controlled": + return v.GetServed().FieldIsZero("mode.end_device_controlled") + case "mode.served.second_channel": + return v.GetServed().FieldIsZero("second_channel") + case "mode.served.second_channel.ack_offset": + return v.GetServed().FieldIsZero("second_channel.ack_offset") + case "mode.served.second_channel.data_rate_index": + return v.GetServed().FieldIsZero("second_channel.data_rate_index") + case "mode.served.second_channel.frequency": + return v.GetServed().FieldIsZero("second_channel.frequency") + case "mode.served.default_channel_index": + return v.GetServed().FieldIsZero("default_channel_index") + case "mode.served.serving_device_id": + return v.GetServed().FieldIsZero("serving_device_id") + case "mode.serving": + return v.GetServing() == nil + case "mode.serving.second_channel": + return v.GetServing().FieldIsZero("second_channel") + case "mode.serving.second_channel.ack_offset": + return v.GetServing().FieldIsZero("second_channel.ack_offset") + case "mode.serving.second_channel.data_rate_index": + return v.GetServing().FieldIsZero("second_channel.data_rate_index") + case "mode.serving.second_channel.frequency": + return v.GetServing().FieldIsZero("second_channel.frequency") + case "mode.serving.default_channel_index": + return v.GetServing().FieldIsZero("default_channel_index") + case "mode.serving.cad_periodicity": + return v.GetServing().FieldIsZero("cad_periodicity") + case "mode.serving.uplink_forwarding_rules": + return v.GetServing().FieldIsZero("uplink_forwarding_rules") + case "mode.serving.limits": + return v.GetServing().FieldIsZero("limits") + case "mode.serving.limits.reset_behavior": + return v.GetServing().FieldIsZero("limits.reset_behavior") + case "mode.serving.limits.join_requests": + return v.GetServing().FieldIsZero("limits.join_requests") + case "mode.serving.limits.join_requests.bucket_size": + return v.GetServing().FieldIsZero("limits.join_requests.bucket_size") + case "mode.serving.limits.join_requests.reload_rate": + return v.GetServing().FieldIsZero("limits.join_requests.reload_rate") + case "mode.serving.limits.notifications": + return v.GetServing().FieldIsZero("limits.notifications") + case "mode.serving.limits.notifications.bucket_size": + return v.GetServing().FieldIsZero("limits.notifications.bucket_size") + case "mode.serving.limits.notifications.reload_rate": + return v.GetServing().FieldIsZero("limits.notifications.reload_rate") + case "mode.serving.limits.uplink_messages": + return v.GetServing().FieldIsZero("limits.uplink_messages") + case "mode.serving.limits.uplink_messages.bucket_size": + return v.GetServing().FieldIsZero("limits.uplink_messages.bucket_size") + case "mode.serving.limits.uplink_messages.reload_rate": + return v.GetServing().FieldIsZero("limits.uplink_messages.reload_rate") + case "mode.serving.limits.overall": + return v.GetServing().FieldIsZero("limits.overall") + case "mode.serving.limits.overall.bucket_size": + return v.GetServing().FieldIsZero("limits.overall.bucket_size") + case "mode.serving.limits.overall.reload_rate": + return v.GetServing().FieldIsZero("limits.overall.reload_rate") + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + // FieldIsZero returns whether path p is zero. func (v *EndDeviceAuthenticationCode) FieldIsZero(p string) bool { if v == nil { @@ -315,6 +531,154 @@ func (v *MACSettings) FieldIsZero(p string) bool { return v.PingSlotPeriodicity == nil case "ping_slot_periodicity.value": return v.PingSlotPeriodicity.FieldIsZero("value") + case "relay": + return v.Relay == nil + case "relay.mode": + return v.Relay.FieldIsZero("mode") + case "relay.mode.served": + return v.Relay.FieldIsZero("mode.served") + case "relay.mode.served.backoff": + return v.Relay.FieldIsZero("mode.served.backoff") + case "relay.mode.served.mode": + return v.Relay.FieldIsZero("mode.served.mode") + case "relay.mode.served.mode.always": + return v.Relay.FieldIsZero("mode.served.mode.always") + case "relay.mode.served.mode.dynamic": + return v.Relay.FieldIsZero("mode.served.mode.dynamic") + case "relay.mode.served.mode.dynamic.smart_enable_level": + return v.Relay.FieldIsZero("mode.served.mode.dynamic.smart_enable_level") + case "relay.mode.served.mode.end_device_controlled": + return v.Relay.FieldIsZero("mode.served.mode.end_device_controlled") + case "relay.mode.served.second_channel": + return v.Relay.FieldIsZero("mode.served.second_channel") + case "relay.mode.served.second_channel.ack_offset": + return v.Relay.FieldIsZero("mode.served.second_channel.ack_offset") + case "relay.mode.served.second_channel.data_rate_index": + return v.Relay.FieldIsZero("mode.served.second_channel.data_rate_index") + case "relay.mode.served.second_channel.frequency": + return v.Relay.FieldIsZero("mode.served.second_channel.frequency") + case "relay.mode.served.default_channel_index": + return v.Relay.FieldIsZero("mode.served.default_channel_index") + case "relay.mode.served.serving_device_id": + return v.Relay.FieldIsZero("mode.served.serving_device_id") + case "relay.mode.serving": + return v.Relay.FieldIsZero("mode.serving") + case "relay.mode.serving.second_channel": + return v.Relay.FieldIsZero("mode.serving.second_channel") + case "relay.mode.serving.second_channel.ack_offset": + return v.Relay.FieldIsZero("mode.serving.second_channel.ack_offset") + case "relay.mode.serving.second_channel.data_rate_index": + return v.Relay.FieldIsZero("mode.serving.second_channel.data_rate_index") + case "relay.mode.serving.second_channel.frequency": + return v.Relay.FieldIsZero("mode.serving.second_channel.frequency") + case "relay.mode.serving.default_channel_index": + return v.Relay.FieldIsZero("mode.serving.default_channel_index") + case "relay.mode.serving.cad_periodicity": + return v.Relay.FieldIsZero("mode.serving.cad_periodicity") + case "relay.mode.serving.uplink_forwarding_rules": + return v.Relay.FieldIsZero("mode.serving.uplink_forwarding_rules") + case "relay.mode.serving.limits": + return v.Relay.FieldIsZero("mode.serving.limits") + case "relay.mode.serving.limits.reset_behavior": + return v.Relay.FieldIsZero("mode.serving.limits.reset_behavior") + case "relay.mode.serving.limits.join_requests": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests") + case "relay.mode.serving.limits.join_requests.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests.bucket_size") + case "relay.mode.serving.limits.join_requests.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests.reload_rate") + case "relay.mode.serving.limits.notifications": + return v.Relay.FieldIsZero("mode.serving.limits.notifications") + case "relay.mode.serving.limits.notifications.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.notifications.bucket_size") + case "relay.mode.serving.limits.notifications.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.notifications.reload_rate") + case "relay.mode.serving.limits.uplink_messages": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages") + case "relay.mode.serving.limits.uplink_messages.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages.bucket_size") + case "relay.mode.serving.limits.uplink_messages.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages.reload_rate") + case "relay.mode.serving.limits.overall": + return v.Relay.FieldIsZero("mode.serving.limits.overall") + case "relay.mode.serving.limits.overall.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.overall.bucket_size") + case "relay.mode.serving.limits.overall.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.overall.reload_rate") + case "desired_relay": + return v.DesiredRelay == nil + case "desired_relay.mode": + return v.DesiredRelay.FieldIsZero("mode") + case "desired_relay.mode.served": + return v.DesiredRelay.FieldIsZero("mode.served") + case "desired_relay.mode.served.backoff": + return v.DesiredRelay.FieldIsZero("mode.served.backoff") + case "desired_relay.mode.served.mode": + return v.DesiredRelay.FieldIsZero("mode.served.mode") + case "desired_relay.mode.served.mode.always": + return v.DesiredRelay.FieldIsZero("mode.served.mode.always") + case "desired_relay.mode.served.mode.dynamic": + return v.DesiredRelay.FieldIsZero("mode.served.mode.dynamic") + case "desired_relay.mode.served.mode.dynamic.smart_enable_level": + return v.DesiredRelay.FieldIsZero("mode.served.mode.dynamic.smart_enable_level") + case "desired_relay.mode.served.mode.end_device_controlled": + return v.DesiredRelay.FieldIsZero("mode.served.mode.end_device_controlled") + case "desired_relay.mode.served.second_channel": + return v.DesiredRelay.FieldIsZero("mode.served.second_channel") + case "desired_relay.mode.served.second_channel.ack_offset": + return v.DesiredRelay.FieldIsZero("mode.served.second_channel.ack_offset") + case "desired_relay.mode.served.second_channel.data_rate_index": + return v.DesiredRelay.FieldIsZero("mode.served.second_channel.data_rate_index") + case "desired_relay.mode.served.second_channel.frequency": + return v.DesiredRelay.FieldIsZero("mode.served.second_channel.frequency") + case "desired_relay.mode.served.default_channel_index": + return v.DesiredRelay.FieldIsZero("mode.served.default_channel_index") + case "desired_relay.mode.served.serving_device_id": + return v.DesiredRelay.FieldIsZero("mode.served.serving_device_id") + case "desired_relay.mode.serving": + return v.DesiredRelay.FieldIsZero("mode.serving") + case "desired_relay.mode.serving.second_channel": + return v.DesiredRelay.FieldIsZero("mode.serving.second_channel") + case "desired_relay.mode.serving.second_channel.ack_offset": + return v.DesiredRelay.FieldIsZero("mode.serving.second_channel.ack_offset") + case "desired_relay.mode.serving.second_channel.data_rate_index": + return v.DesiredRelay.FieldIsZero("mode.serving.second_channel.data_rate_index") + case "desired_relay.mode.serving.second_channel.frequency": + return v.DesiredRelay.FieldIsZero("mode.serving.second_channel.frequency") + case "desired_relay.mode.serving.default_channel_index": + return v.DesiredRelay.FieldIsZero("mode.serving.default_channel_index") + case "desired_relay.mode.serving.cad_periodicity": + return v.DesiredRelay.FieldIsZero("mode.serving.cad_periodicity") + case "desired_relay.mode.serving.uplink_forwarding_rules": + return v.DesiredRelay.FieldIsZero("mode.serving.uplink_forwarding_rules") + case "desired_relay.mode.serving.limits": + return v.DesiredRelay.FieldIsZero("mode.serving.limits") + case "desired_relay.mode.serving.limits.reset_behavior": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.reset_behavior") + case "desired_relay.mode.serving.limits.join_requests": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.join_requests") + case "desired_relay.mode.serving.limits.join_requests.bucket_size": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.join_requests.bucket_size") + case "desired_relay.mode.serving.limits.join_requests.reload_rate": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.join_requests.reload_rate") + case "desired_relay.mode.serving.limits.notifications": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.notifications") + case "desired_relay.mode.serving.limits.notifications.bucket_size": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.notifications.bucket_size") + case "desired_relay.mode.serving.limits.notifications.reload_rate": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.notifications.reload_rate") + case "desired_relay.mode.serving.limits.uplink_messages": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.uplink_messages") + case "desired_relay.mode.serving.limits.uplink_messages.bucket_size": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.uplink_messages.bucket_size") + case "desired_relay.mode.serving.limits.uplink_messages.reload_rate": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.uplink_messages.reload_rate") + case "desired_relay.mode.serving.limits.overall": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.overall") + case "desired_relay.mode.serving.limits.overall.bucket_size": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.overall.bucket_size") + case "desired_relay.mode.serving.limits.overall.reload_rate": + return v.DesiredRelay.FieldIsZero("mode.serving.limits.overall.reload_rate") case "resets_f_cnt": return v.ResetsFCnt == nil case "resets_f_cnt.value": @@ -411,6 +775,80 @@ func (v *MACParameters) FieldIsZero(p string) bool { return v.RejoinCountPeriodicity == 0 case "rejoin_time_periodicity": return v.RejoinTimePeriodicity == 0 + case "relay": + return v.Relay == nil + case "relay.mode": + return v.Relay.FieldIsZero("mode") + case "relay.mode.served": + return v.Relay.FieldIsZero("mode.served") + case "relay.mode.served.backoff": + return v.Relay.FieldIsZero("mode.served.backoff") + case "relay.mode.served.mode": + return v.Relay.FieldIsZero("mode.served.mode") + case "relay.mode.served.mode.always": + return v.Relay.FieldIsZero("mode.served.mode.always") + case "relay.mode.served.mode.dynamic": + return v.Relay.FieldIsZero("mode.served.mode.dynamic") + case "relay.mode.served.mode.dynamic.smart_enable_level": + return v.Relay.FieldIsZero("mode.served.mode.dynamic.smart_enable_level") + case "relay.mode.served.mode.end_device_controlled": + return v.Relay.FieldIsZero("mode.served.mode.end_device_controlled") + case "relay.mode.served.second_channel": + return v.Relay.FieldIsZero("mode.served.second_channel") + case "relay.mode.served.second_channel.ack_offset": + return v.Relay.FieldIsZero("mode.served.second_channel.ack_offset") + case "relay.mode.served.second_channel.data_rate_index": + return v.Relay.FieldIsZero("mode.served.second_channel.data_rate_index") + case "relay.mode.served.second_channel.frequency": + return v.Relay.FieldIsZero("mode.served.second_channel.frequency") + case "relay.mode.served.default_channel_index": + return v.Relay.FieldIsZero("mode.served.default_channel_index") + case "relay.mode.served.serving_device_id": + return v.Relay.FieldIsZero("mode.served.serving_device_id") + case "relay.mode.serving": + return v.Relay.FieldIsZero("mode.serving") + case "relay.mode.serving.second_channel": + return v.Relay.FieldIsZero("mode.serving.second_channel") + case "relay.mode.serving.second_channel.ack_offset": + return v.Relay.FieldIsZero("mode.serving.second_channel.ack_offset") + case "relay.mode.serving.second_channel.data_rate_index": + return v.Relay.FieldIsZero("mode.serving.second_channel.data_rate_index") + case "relay.mode.serving.second_channel.frequency": + return v.Relay.FieldIsZero("mode.serving.second_channel.frequency") + case "relay.mode.serving.default_channel_index": + return v.Relay.FieldIsZero("mode.serving.default_channel_index") + case "relay.mode.serving.cad_periodicity": + return v.Relay.FieldIsZero("mode.serving.cad_periodicity") + case "relay.mode.serving.uplink_forwarding_rules": + return v.Relay.FieldIsZero("mode.serving.uplink_forwarding_rules") + case "relay.mode.serving.limits": + return v.Relay.FieldIsZero("mode.serving.limits") + case "relay.mode.serving.limits.reset_behavior": + return v.Relay.FieldIsZero("mode.serving.limits.reset_behavior") + case "relay.mode.serving.limits.join_requests": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests") + case "relay.mode.serving.limits.join_requests.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests.bucket_size") + case "relay.mode.serving.limits.join_requests.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.join_requests.reload_rate") + case "relay.mode.serving.limits.notifications": + return v.Relay.FieldIsZero("mode.serving.limits.notifications") + case "relay.mode.serving.limits.notifications.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.notifications.bucket_size") + case "relay.mode.serving.limits.notifications.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.notifications.reload_rate") + case "relay.mode.serving.limits.uplink_messages": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages") + case "relay.mode.serving.limits.uplink_messages.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages.bucket_size") + case "relay.mode.serving.limits.uplink_messages.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.uplink_messages.reload_rate") + case "relay.mode.serving.limits.overall": + return v.Relay.FieldIsZero("mode.serving.limits.overall") + case "relay.mode.serving.limits.overall.bucket_size": + return v.Relay.FieldIsZero("mode.serving.limits.overall.bucket_size") + case "relay.mode.serving.limits.overall.reload_rate": + return v.Relay.FieldIsZero("mode.serving.limits.overall.reload_rate") case "rx1_data_rate_offset": return v.Rx1DataRateOffset == 0 case "rx1_delay": @@ -579,6 +1017,80 @@ func (v *MACState) FieldIsZero(p string) bool { return v.CurrentParameters.FieldIsZero("rejoin_count_periodicity") case "current_parameters.rejoin_time_periodicity": return v.CurrentParameters.FieldIsZero("rejoin_time_periodicity") + case "current_parameters.relay": + return v.CurrentParameters.FieldIsZero("relay") + case "current_parameters.relay.mode": + return v.CurrentParameters.FieldIsZero("relay.mode") + case "current_parameters.relay.mode.served": + return v.CurrentParameters.FieldIsZero("relay.mode.served") + case "current_parameters.relay.mode.served.backoff": + return v.CurrentParameters.FieldIsZero("relay.mode.served.backoff") + case "current_parameters.relay.mode.served.mode": + return v.CurrentParameters.FieldIsZero("relay.mode.served.mode") + case "current_parameters.relay.mode.served.mode.always": + return v.CurrentParameters.FieldIsZero("relay.mode.served.mode.always") + case "current_parameters.relay.mode.served.mode.dynamic": + return v.CurrentParameters.FieldIsZero("relay.mode.served.mode.dynamic") + case "current_parameters.relay.mode.served.mode.dynamic.smart_enable_level": + return v.CurrentParameters.FieldIsZero("relay.mode.served.mode.dynamic.smart_enable_level") + case "current_parameters.relay.mode.served.mode.end_device_controlled": + return v.CurrentParameters.FieldIsZero("relay.mode.served.mode.end_device_controlled") + case "current_parameters.relay.mode.served.second_channel": + return v.CurrentParameters.FieldIsZero("relay.mode.served.second_channel") + case "current_parameters.relay.mode.served.second_channel.ack_offset": + return v.CurrentParameters.FieldIsZero("relay.mode.served.second_channel.ack_offset") + case "current_parameters.relay.mode.served.second_channel.data_rate_index": + return v.CurrentParameters.FieldIsZero("relay.mode.served.second_channel.data_rate_index") + case "current_parameters.relay.mode.served.second_channel.frequency": + return v.CurrentParameters.FieldIsZero("relay.mode.served.second_channel.frequency") + case "current_parameters.relay.mode.served.default_channel_index": + return v.CurrentParameters.FieldIsZero("relay.mode.served.default_channel_index") + case "current_parameters.relay.mode.served.serving_device_id": + return v.CurrentParameters.FieldIsZero("relay.mode.served.serving_device_id") + case "current_parameters.relay.mode.serving": + return v.CurrentParameters.FieldIsZero("relay.mode.serving") + case "current_parameters.relay.mode.serving.second_channel": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.second_channel") + case "current_parameters.relay.mode.serving.second_channel.ack_offset": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.second_channel.ack_offset") + case "current_parameters.relay.mode.serving.second_channel.data_rate_index": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.second_channel.data_rate_index") + case "current_parameters.relay.mode.serving.second_channel.frequency": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.second_channel.frequency") + case "current_parameters.relay.mode.serving.default_channel_index": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.default_channel_index") + case "current_parameters.relay.mode.serving.cad_periodicity": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.cad_periodicity") + case "current_parameters.relay.mode.serving.uplink_forwarding_rules": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.uplink_forwarding_rules") + case "current_parameters.relay.mode.serving.limits": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits") + case "current_parameters.relay.mode.serving.limits.reset_behavior": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.reset_behavior") + case "current_parameters.relay.mode.serving.limits.join_requests": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.join_requests") + case "current_parameters.relay.mode.serving.limits.join_requests.bucket_size": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.join_requests.bucket_size") + case "current_parameters.relay.mode.serving.limits.join_requests.reload_rate": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.join_requests.reload_rate") + case "current_parameters.relay.mode.serving.limits.notifications": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.notifications") + case "current_parameters.relay.mode.serving.limits.notifications.bucket_size": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.notifications.bucket_size") + case "current_parameters.relay.mode.serving.limits.notifications.reload_rate": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.notifications.reload_rate") + case "current_parameters.relay.mode.serving.limits.uplink_messages": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages") + case "current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages.bucket_size") + case "current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages.reload_rate") + case "current_parameters.relay.mode.serving.limits.overall": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.overall") + case "current_parameters.relay.mode.serving.limits.overall.bucket_size": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.overall.bucket_size") + case "current_parameters.relay.mode.serving.limits.overall.reload_rate": + return v.CurrentParameters.FieldIsZero("relay.mode.serving.limits.overall.reload_rate") case "current_parameters.rx1_data_rate_offset": return v.CurrentParameters.FieldIsZero("rx1_data_rate_offset") case "current_parameters.rx1_delay": @@ -635,6 +1147,80 @@ func (v *MACState) FieldIsZero(p string) bool { return v.DesiredParameters.FieldIsZero("rejoin_count_periodicity") case "desired_parameters.rejoin_time_periodicity": return v.DesiredParameters.FieldIsZero("rejoin_time_periodicity") + case "desired_parameters.relay": + return v.DesiredParameters.FieldIsZero("relay") + case "desired_parameters.relay.mode": + return v.DesiredParameters.FieldIsZero("relay.mode") + case "desired_parameters.relay.mode.served": + return v.DesiredParameters.FieldIsZero("relay.mode.served") + case "desired_parameters.relay.mode.served.backoff": + return v.DesiredParameters.FieldIsZero("relay.mode.served.backoff") + case "desired_parameters.relay.mode.served.mode": + return v.DesiredParameters.FieldIsZero("relay.mode.served.mode") + case "desired_parameters.relay.mode.served.mode.always": + return v.DesiredParameters.FieldIsZero("relay.mode.served.mode.always") + case "desired_parameters.relay.mode.served.mode.dynamic": + return v.DesiredParameters.FieldIsZero("relay.mode.served.mode.dynamic") + case "desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level": + return v.DesiredParameters.FieldIsZero("relay.mode.served.mode.dynamic.smart_enable_level") + case "desired_parameters.relay.mode.served.mode.end_device_controlled": + return v.DesiredParameters.FieldIsZero("relay.mode.served.mode.end_device_controlled") + case "desired_parameters.relay.mode.served.second_channel": + return v.DesiredParameters.FieldIsZero("relay.mode.served.second_channel") + case "desired_parameters.relay.mode.served.second_channel.ack_offset": + return v.DesiredParameters.FieldIsZero("relay.mode.served.second_channel.ack_offset") + case "desired_parameters.relay.mode.served.second_channel.data_rate_index": + return v.DesiredParameters.FieldIsZero("relay.mode.served.second_channel.data_rate_index") + case "desired_parameters.relay.mode.served.second_channel.frequency": + return v.DesiredParameters.FieldIsZero("relay.mode.served.second_channel.frequency") + case "desired_parameters.relay.mode.served.default_channel_index": + return v.DesiredParameters.FieldIsZero("relay.mode.served.default_channel_index") + case "desired_parameters.relay.mode.served.serving_device_id": + return v.DesiredParameters.FieldIsZero("relay.mode.served.serving_device_id") + case "desired_parameters.relay.mode.serving": + return v.DesiredParameters.FieldIsZero("relay.mode.serving") + case "desired_parameters.relay.mode.serving.second_channel": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.second_channel") + case "desired_parameters.relay.mode.serving.second_channel.ack_offset": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.second_channel.ack_offset") + case "desired_parameters.relay.mode.serving.second_channel.data_rate_index": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.second_channel.data_rate_index") + case "desired_parameters.relay.mode.serving.second_channel.frequency": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.second_channel.frequency") + case "desired_parameters.relay.mode.serving.default_channel_index": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.default_channel_index") + case "desired_parameters.relay.mode.serving.cad_periodicity": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.cad_periodicity") + case "desired_parameters.relay.mode.serving.uplink_forwarding_rules": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.uplink_forwarding_rules") + case "desired_parameters.relay.mode.serving.limits": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits") + case "desired_parameters.relay.mode.serving.limits.reset_behavior": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.reset_behavior") + case "desired_parameters.relay.mode.serving.limits.join_requests": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.join_requests") + case "desired_parameters.relay.mode.serving.limits.join_requests.bucket_size": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.join_requests.bucket_size") + case "desired_parameters.relay.mode.serving.limits.join_requests.reload_rate": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.join_requests.reload_rate") + case "desired_parameters.relay.mode.serving.limits.notifications": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.notifications") + case "desired_parameters.relay.mode.serving.limits.notifications.bucket_size": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.notifications.bucket_size") + case "desired_parameters.relay.mode.serving.limits.notifications.reload_rate": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.notifications.reload_rate") + case "desired_parameters.relay.mode.serving.limits.uplink_messages": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages") + case "desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages.bucket_size") + case "desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.uplink_messages.reload_rate") + case "desired_parameters.relay.mode.serving.limits.overall": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.overall") + case "desired_parameters.relay.mode.serving.limits.overall.bucket_size": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.overall.bucket_size") + case "desired_parameters.relay.mode.serving.limits.overall.reload_rate": + return v.DesiredParameters.FieldIsZero("relay.mode.serving.limits.overall.reload_rate") case "desired_parameters.rx1_data_rate_offset": return v.DesiredParameters.FieldIsZero("rx1_data_rate_offset") case "desired_parameters.rx1_delay": @@ -815,6 +1401,10 @@ func (v *MACState) FieldIsZero(p string) bool { return v.PendingJoinRequest.FieldIsZero("rx_delay") case "pending_join_request.selected_mac_version": return v.PendingJoinRequest.FieldIsZero("selected_mac_version") + case "pending_relay_downlink": + return v.PendingRelayDownlink == nil + case "pending_relay_downlink.raw_payload": + return v.PendingRelayDownlink.FieldIsZero("raw_payload") case "pending_requests": return v.PendingRequests == nil case "ping_slot_periodicity": @@ -1199,6 +1789,150 @@ func (v *EndDevice) FieldIsZero(p string) bool { return v.MacSettings.FieldIsZero("ping_slot_periodicity") case "mac_settings.ping_slot_periodicity.value": return v.MacSettings.FieldIsZero("ping_slot_periodicity.value") + case "mac_settings.relay": + return v.MacSettings.FieldIsZero("relay") + case "mac_settings.relay.mode": + return v.MacSettings.FieldIsZero("relay.mode") + case "mac_settings.relay.mode.served": + return v.MacSettings.FieldIsZero("relay.mode.served") + case "mac_settings.relay.mode.served.backoff": + return v.MacSettings.FieldIsZero("relay.mode.served.backoff") + case "mac_settings.relay.mode.served.mode": + return v.MacSettings.FieldIsZero("relay.mode.served.mode") + case "mac_settings.relay.mode.served.mode.always": + return v.MacSettings.FieldIsZero("relay.mode.served.mode.always") + case "mac_settings.relay.mode.served.mode.dynamic": + return v.MacSettings.FieldIsZero("relay.mode.served.mode.dynamic") + case "mac_settings.relay.mode.served.mode.dynamic.smart_enable_level": + return v.MacSettings.FieldIsZero("relay.mode.served.mode.dynamic.smart_enable_level") + case "mac_settings.relay.mode.served.mode.end_device_controlled": + return v.MacSettings.FieldIsZero("relay.mode.served.mode.end_device_controlled") + case "mac_settings.relay.mode.served.second_channel": + return v.MacSettings.FieldIsZero("relay.mode.served.second_channel") + case "mac_settings.relay.mode.served.second_channel.ack_offset": + return v.MacSettings.FieldIsZero("relay.mode.served.second_channel.ack_offset") + case "mac_settings.relay.mode.served.second_channel.data_rate_index": + return v.MacSettings.FieldIsZero("relay.mode.served.second_channel.data_rate_index") + case "mac_settings.relay.mode.served.second_channel.frequency": + return v.MacSettings.FieldIsZero("relay.mode.served.second_channel.frequency") + case "mac_settings.relay.mode.served.serving_device_id": + return v.MacSettings.FieldIsZero("relay.mode.served.serving_device_id") + case "mac_settings.relay.mode.serving": + return v.MacSettings.FieldIsZero("relay.mode.serving") + case "mac_settings.relay.mode.serving.second_channel": + return v.MacSettings.FieldIsZero("relay.mode.serving.second_channel") + case "mac_settings.relay.mode.serving.second_channel.ack_offset": + return v.MacSettings.FieldIsZero("relay.mode.serving.second_channel.ack_offset") + case "mac_settings.relay.mode.serving.second_channel.data_rate_index": + return v.MacSettings.FieldIsZero("relay.mode.serving.second_channel.data_rate_index") + case "mac_settings.relay.mode.serving.second_channel.frequency": + return v.MacSettings.FieldIsZero("relay.mode.serving.second_channel.frequency") + case "mac_settings.relay.mode.serving.default_channel_index": + return v.MacSettings.FieldIsZero("relay.mode.serving.default_channel_index") + case "mac_settings.relay.mode.serving.cad_periodicity": + return v.MacSettings.FieldIsZero("relay.mode.serving.cad_periodicity") + case "mac_settings.relay.mode.serving.uplink_forwarding_rules": + return v.MacSettings.FieldIsZero("relay.mode.serving.uplink_forwarding_rules") + case "mac_settings.relay.mode.serving.limits": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits") + case "mac_settings.relay.mode.serving.limits.reset_behavior": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.reset_behavior") + case "mac_settings.relay.mode.serving.limits.join_requests": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.join_requests") + case "mac_settings.relay.mode.serving.limits.join_requests.bucket_size": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.join_requests.bucket_size") + case "mac_settings.relay.mode.serving.limits.join_requests.reload_rate": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.join_requests.reload_rate") + case "mac_settings.relay.mode.serving.limits.notifications": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.notifications") + case "mac_settings.relay.mode.serving.limits.notifications.bucket_size": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.notifications.bucket_size") + case "mac_settings.relay.mode.serving.limits.notifications.reload_rate": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.notifications.reload_rate") + case "mac_settings.relay.mode.serving.limits.uplink_messages": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.uplink_messages") + case "mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.uplink_messages.bucket_size") + case "mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.uplink_messages.reload_rate") + case "mac_settings.relay.mode.serving.limits.overall": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.overall") + case "mac_settings.relay.mode.serving.limits.overall.bucket_size": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.overall.bucket_size") + case "mac_settings.relay.mode.serving.limits.overall.reload_rate": + return v.MacSettings.FieldIsZero("relay.mode.serving.limits.overall.reload_rate") + case "mac_settings.desired_relay": + return v.MacSettings.FieldIsZero("desired_relay") + case "mac_settings.desired_relay.mode": + return v.MacSettings.FieldIsZero("desired_relay.mode") + case "mac_settings.desired_relay.mode.served": + return v.MacSettings.FieldIsZero("desired_relay.mode.served") + case "mac_settings.desired_relay.mode.served.backoff": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.backoff") + case "mac_settings.desired_relay.mode.served.mode": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.mode") + case "mac_settings.desired_relay.mode.served.mode.always": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.mode.always") + case "mac_settings.desired_relay.mode.served.mode.dynamic": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.mode.dynamic") + case "mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.mode.dynamic.smart_enable_level") + case "mac_settings.desired_relay.mode.served.mode.end_device_controlled": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.mode.end_device_controlled") + case "mac_settings.desired_relay.mode.served.second_channel": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.second_channel") + case "mac_settings.desired_relay.mode.served.second_channel.ack_offset": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.second_channel.ack_offset") + case "mac_settings.desired_relay.mode.served.second_channel.data_rate_index": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.second_channel.data_rate_index") + case "mac_settings.desired_relay.mode.served.second_channel.frequency": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.second_channel.frequency") + case "mac_settings.desired_relay.mode.served.serving_device_id": + return v.MacSettings.FieldIsZero("desired_relay.mode.served.serving_device_id") + case "mac_settings.desired_relay.mode.serving": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving") + case "mac_settings.desired_relay.mode.serving.second_channel": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.second_channel") + case "mac_settings.desired_relay.mode.serving.second_channel.ack_offset": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.second_channel.ack_offset") + case "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.second_channel.data_rate_index") + case "mac_settings.desired_relay.mode.serving.second_channel.frequency": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.second_channel.frequency") + case "mac_settings.desired_relay.mode.serving.default_channel_index": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.default_channel_index") + case "mac_settings.desired_relay.mode.serving.cad_periodicity": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.cad_periodicity") + case "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.uplink_forwarding_rules") + case "mac_settings.desired_relay.mode.serving.limits": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits") + case "mac_settings.desired_relay.mode.serving.limits.reset_behavior": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.reset_behavior") + case "mac_settings.desired_relay.mode.serving.limits.join_requests": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.join_requests") + case "mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.join_requests.bucket_size") + case "mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.join_requests.reload_rate") + case "mac_settings.desired_relay.mode.serving.limits.notifications": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.notifications") + case "mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.notifications.bucket_size") + case "mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.notifications.reload_rate") + case "mac_settings.desired_relay.mode.serving.limits.uplink_messages": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.uplink_messages") + case "mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.uplink_messages.bucket_size") + case "mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.uplink_messages.reload_rate") + case "mac_settings.desired_relay.mode.serving.limits.overall": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.overall") + case "mac_settings.desired_relay.mode.serving.limits.overall.bucket_size": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.overall.bucket_size") + case "mac_settings.desired_relay.mode.serving.limits.overall.reload_rate": + return v.MacSettings.FieldIsZero("desired_relay.mode.serving.limits.overall.reload_rate") case "mac_settings.resets_f_cnt": return v.MacSettings.FieldIsZero("resets_f_cnt") case "mac_settings.resets_f_cnt.value": diff --git a/pkg/ttnpb/end_device.pb.go b/pkg/ttnpb/end_device.pb.go index ce9dffa44e..587dd02e6f 100644 --- a/pkg/ttnpb/end_device.pb.go +++ b/pkg/ttnpb/end_device.pb.go @@ -251,6 +251,466 @@ func (x *BoolValue) GetValue() bool { return false } +type ServingRelayForwardingLimits struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Reset behavior of the buckets upon limit update. + ResetBehavior RelayResetLimitCounter `protobuf:"varint,1,opt,name=reset_behavior,json=resetBehavior,proto3,enum=ttn.lorawan.v3.RelayResetLimitCounter" json:"reset_behavior,omitempty"` + // Bucket configuration for join requests. + // If unset, no individual limits will apply to join requests, but the relay overall limitations will apply. + JoinRequests *RelayForwardLimits `protobuf:"bytes,2,opt,name=join_requests,json=joinRequests,proto3" json:"join_requests,omitempty"` + // Bucket configuration for unknown device notifications. + // If unset, no individual limits will apply to unknown end device notifications, but the relay overall + // limitations will still apply. + Notifications *RelayForwardLimits `protobuf:"bytes,3,opt,name=notifications,proto3" json:"notifications,omitempty"` + // Bucket configuration for uplink messages across all served end devices. + // If unset, no individual limits will apply to uplink messages across all served end devices, but the relay + // overall limitations will still apply. + UplinkMessages *RelayForwardLimits `protobuf:"bytes,4,opt,name=uplink_messages,json=uplinkMessages,proto3" json:"uplink_messages,omitempty"` + // Bucket configuration for all relay messages. + // If unset, no overall limits will apply to the relay, but individual limitations will still apply. + Overall *RelayForwardLimits `protobuf:"bytes,5,opt,name=overall,proto3" json:"overall,omitempty"` +} + +func (x *ServingRelayForwardingLimits) Reset() { + *x = ServingRelayForwardingLimits{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServingRelayForwardingLimits) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServingRelayForwardingLimits) ProtoMessage() {} + +func (x *ServingRelayForwardingLimits) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServingRelayForwardingLimits.ProtoReflect.Descriptor instead. +func (*ServingRelayForwardingLimits) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{2} +} + +func (x *ServingRelayForwardingLimits) GetResetBehavior() RelayResetLimitCounter { + if x != nil { + return x.ResetBehavior + } + return RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_ZERO +} + +func (x *ServingRelayForwardingLimits) GetJoinRequests() *RelayForwardLimits { + if x != nil { + return x.JoinRequests + } + return nil +} + +func (x *ServingRelayForwardingLimits) GetNotifications() *RelayForwardLimits { + if x != nil { + return x.Notifications + } + return nil +} + +func (x *ServingRelayForwardingLimits) GetUplinkMessages() *RelayForwardLimits { + if x != nil { + return x.UplinkMessages + } + return nil +} + +func (x *ServingRelayForwardingLimits) GetOverall() *RelayForwardLimits { + if x != nil { + return x.Overall + } + return nil +} + +type RelayUplinkForwardingRule struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Bucket configuration for the served end device. + // If unset, no individual limits will apply to the end device, but the relay global limitations will apply. + Limits *RelayUplinkForwardLimits `protobuf:"bytes,1,opt,name=limits,proto3" json:"limits,omitempty"` + // Last wake on radio frame counter used by the served end device. + LastWFCnt uint32 `protobuf:"varint,2,opt,name=last_w_f_cnt,json=lastWFCnt,proto3" json:"last_w_f_cnt,omitempty"` + // End device identifier of the served end device. + DeviceId string `protobuf:"bytes,3,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + // Session key ID of the session keys used to derive the root relay session key. + SessionKeyId []byte `protobuf:"bytes,4,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"` +} + +func (x *RelayUplinkForwardingRule) Reset() { + *x = RelayUplinkForwardingRule{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayUplinkForwardingRule) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayUplinkForwardingRule) ProtoMessage() {} + +func (x *RelayUplinkForwardingRule) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayUplinkForwardingRule.ProtoReflect.Descriptor instead. +func (*RelayUplinkForwardingRule) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{3} +} + +func (x *RelayUplinkForwardingRule) GetLimits() *RelayUplinkForwardLimits { + if x != nil { + return x.Limits + } + return nil +} + +func (x *RelayUplinkForwardingRule) GetLastWFCnt() uint32 { + if x != nil { + return x.LastWFCnt + } + return 0 +} + +func (x *RelayUplinkForwardingRule) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *RelayUplinkForwardingRule) GetSessionKeyId() []byte { + if x != nil { + return x.SessionKeyId + } + return nil +} + +type ServingRelayParameters struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Second wake on radio channel configuration. + SecondChannel *RelaySecondChannel `protobuf:"bytes,1,opt,name=second_channel,json=secondChannel,proto3" json:"second_channel,omitempty"` + // Index of the default wake on radio channel. + DefaultChannelIndex uint32 `protobuf:"varint,2,opt,name=default_channel_index,json=defaultChannelIndex,proto3" json:"default_channel_index,omitempty"` + // Channel activity detection periodicity. + CadPeriodicity RelayCADPeriodicity `protobuf:"varint,3,opt,name=cad_periodicity,json=cadPeriodicity,proto3,enum=ttn.lorawan.v3.RelayCADPeriodicity" json:"cad_periodicity,omitempty"` + // Configured uplink forwarding rules. + UplinkForwardingRules []*RelayUplinkForwardingRule `protobuf:"bytes,4,rep,name=uplink_forwarding_rules,json=uplinkForwardingRules,proto3" json:"uplink_forwarding_rules,omitempty"` + // Configured forwarding limits. + // If unset, the default value from Network Server configuration will be used. + Limits *ServingRelayForwardingLimits `protobuf:"bytes,5,opt,name=limits,proto3" json:"limits,omitempty"` +} + +func (x *ServingRelayParameters) Reset() { + *x = ServingRelayParameters{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServingRelayParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServingRelayParameters) ProtoMessage() {} + +func (x *ServingRelayParameters) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServingRelayParameters.ProtoReflect.Descriptor instead. +func (*ServingRelayParameters) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4} +} + +func (x *ServingRelayParameters) GetSecondChannel() *RelaySecondChannel { + if x != nil { + return x.SecondChannel + } + return nil +} + +func (x *ServingRelayParameters) GetDefaultChannelIndex() uint32 { + if x != nil { + return x.DefaultChannelIndex + } + return 0 +} + +func (x *ServingRelayParameters) GetCadPeriodicity() RelayCADPeriodicity { + if x != nil { + return x.CadPeriodicity + } + return RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND +} + +func (x *ServingRelayParameters) GetUplinkForwardingRules() []*RelayUplinkForwardingRule { + if x != nil { + return x.UplinkForwardingRules + } + return nil +} + +func (x *ServingRelayParameters) GetLimits() *ServingRelayForwardingLimits { + if x != nil { + return x.Limits + } + return nil +} + +type ServedRelayParameters struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mode: + // *ServedRelayParameters_Always + // *ServedRelayParameters_Dynamic + // *ServedRelayParameters_EndDeviceControlled + Mode isServedRelayParameters_Mode `protobuf_oneof:"mode"` + // Number of uplinks to be sent without a wake on radio frame. + Backoff uint32 `protobuf:"varint,4,opt,name=backoff,proto3" json:"backoff,omitempty"` + // Second wake on radio channel configuration. + SecondChannel *RelaySecondChannel `protobuf:"bytes,5,opt,name=second_channel,json=secondChannel,proto3" json:"second_channel,omitempty"` + // End device identifier of the serving end device. + ServingDeviceId string `protobuf:"bytes,6,opt,name=serving_device_id,json=servingDeviceId,proto3" json:"serving_device_id,omitempty"` +} + +func (x *ServedRelayParameters) Reset() { + *x = ServedRelayParameters{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServedRelayParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServedRelayParameters) ProtoMessage() {} + +func (x *ServedRelayParameters) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServedRelayParameters.ProtoReflect.Descriptor instead. +func (*ServedRelayParameters) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{5} +} + +func (m *ServedRelayParameters) GetMode() isServedRelayParameters_Mode { + if m != nil { + return m.Mode + } + return nil +} + +func (x *ServedRelayParameters) GetAlways() *RelayEndDeviceAlwaysMode { + if x, ok := x.GetMode().(*ServedRelayParameters_Always); ok { + return x.Always + } + return nil +} + +func (x *ServedRelayParameters) GetDynamic() *RelayEndDeviceDynamicMode { + if x, ok := x.GetMode().(*ServedRelayParameters_Dynamic); ok { + return x.Dynamic + } + return nil +} + +func (x *ServedRelayParameters) GetEndDeviceControlled() *RelayEndDeviceControlledMode { + if x, ok := x.GetMode().(*ServedRelayParameters_EndDeviceControlled); ok { + return x.EndDeviceControlled + } + return nil +} + +func (x *ServedRelayParameters) GetBackoff() uint32 { + if x != nil { + return x.Backoff + } + return 0 +} + +func (x *ServedRelayParameters) GetSecondChannel() *RelaySecondChannel { + if x != nil { + return x.SecondChannel + } + return nil +} + +func (x *ServedRelayParameters) GetServingDeviceId() string { + if x != nil { + return x.ServingDeviceId + } + return "" +} + +type isServedRelayParameters_Mode interface { + isServedRelayParameters_Mode() +} + +type ServedRelayParameters_Always struct { + // The end device will always attempt to use the relay mode in order to send uplink messages. + Always *RelayEndDeviceAlwaysMode `protobuf:"bytes,1,opt,name=always,proto3,oneof"` +} + +type ServedRelayParameters_Dynamic struct { + // The end device will attempt to use relay mode only after a number of uplink messages have been sent without + // receiving a valid a downlink message. + Dynamic *RelayEndDeviceDynamicMode `protobuf:"bytes,2,opt,name=dynamic,proto3,oneof"` +} + +type ServedRelayParameters_EndDeviceControlled struct { + // The end device will control when it uses the relay mode. This is the default mode. + EndDeviceControlled *RelayEndDeviceControlledMode `protobuf:"bytes,3,opt,name=end_device_controlled,json=endDeviceControlled,proto3,oneof"` +} + +func (*ServedRelayParameters_Always) isServedRelayParameters_Mode() {} + +func (*ServedRelayParameters_Dynamic) isServedRelayParameters_Mode() {} + +func (*ServedRelayParameters_EndDeviceControlled) isServedRelayParameters_Mode() {} + +// RelayParameters represent the parameters of a relay. +// This is used internally by the Network Server. +type RelayParameters struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mode: + // *RelayParameters_Serving + // *RelayParameters_Served + Mode isRelayParameters_Mode `protobuf_oneof:"mode"` +} + +func (x *RelayParameters) Reset() { + *x = RelayParameters{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayParameters) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayParameters) ProtoMessage() {} + +func (x *RelayParameters) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayParameters.ProtoReflect.Descriptor instead. +func (*RelayParameters) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6} +} + +func (m *RelayParameters) GetMode() isRelayParameters_Mode { + if m != nil { + return m.Mode + } + return nil +} + +func (x *RelayParameters) GetServing() *ServingRelayParameters { + if x, ok := x.GetMode().(*RelayParameters_Serving); ok { + return x.Serving + } + return nil +} + +func (x *RelayParameters) GetServed() *ServedRelayParameters { + if x, ok := x.GetMode().(*RelayParameters_Served); ok { + return x.Served + } + return nil +} + +type isRelayParameters_Mode interface { + isRelayParameters_Mode() +} + +type RelayParameters_Serving struct { + // Parameters related to a relay which is serving end devices. + Serving *ServingRelayParameters `protobuf:"bytes,25,opt,name=serving,proto3,oneof"` +} + +type RelayParameters_Served struct { + // Parameters related to an end device served by a relay. + Served *ServedRelayParameters `protobuf:"bytes,26,opt,name=served,proto3,oneof"` +} + +func (*RelayParameters_Serving) isRelayParameters_Mode() {} + +func (*RelayParameters_Served) isRelayParameters_Mode() {} + // MACParameters represent the parameters of the device's MAC layer (active or desired). // This is used internally by the Network Server. type MACParameters struct { @@ -302,10 +762,10 @@ type MACParameters struct { // Configured uplink channels and optionally Rx1 frequency. Channels []*MACParameters_Channel `protobuf:"bytes,19,rep,name=channels,proto3" json:"channels,omitempty"` // Whether uplink dwell time is set (400ms). - // If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). + // If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). UplinkDwellTime *BoolValue `protobuf:"bytes,20,opt,name=uplink_dwell_time,json=uplinkDwellTime,proto3" json:"uplink_dwell_time,omitempty"` // Whether downlink dwell time is set (400ms). - // If this field is not set, then the value is either unknown or irrelevant(Network Server cannot modify it). + // If unset, then the value is either unknown or irrelevant(Network Server cannot modify it). DownlinkDwellTime *BoolValue `protobuf:"bytes,21,opt,name=downlink_dwell_time,json=downlinkDwellTime,proto3" json:"downlink_dwell_time,omitempty"` // ADR: number of messages to wait before setting ADRAckReq. AdrAckLimitExponent *ADRAckLimitExponentValue `protobuf:"bytes,22,opt,name=adr_ack_limit_exponent,json=adrAckLimitExponent,proto3" json:"adr_ack_limit_exponent,omitempty"` @@ -313,12 +773,14 @@ type MACParameters struct { AdrAckDelayExponent *ADRAckDelayExponentValue `protobuf:"bytes,23,opt,name=adr_ack_delay_exponent,json=adrAckDelayExponent,proto3" json:"adr_ack_delay_exponent,omitempty"` // Data rate index of the class B ping slot. PingSlotDataRateIndexValue *DataRateIndexValue `protobuf:"bytes,24,opt,name=ping_slot_data_rate_index_value,json=pingSlotDataRateIndexValue,proto3" json:"ping_slot_data_rate_index_value,omitempty"` + // Relay parameters. + Relay *RelayParameters `protobuf:"bytes,25,opt,name=relay,proto3" json:"relay,omitempty"` } func (x *MACParameters) Reset() { *x = MACParameters{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[2] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -331,7 +793,7 @@ func (x *MACParameters) String() string { func (*MACParameters) ProtoMessage() {} func (x *MACParameters) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[2] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -344,7 +806,7 @@ func (x *MACParameters) ProtoReflect() protoreflect.Message { // Deprecated: Use MACParameters.ProtoReflect.Descriptor instead. func (*MACParameters) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{2} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{7} } func (x *MACParameters) GetMaxEirp() float32 { @@ -504,6 +966,13 @@ func (x *MACParameters) GetPingSlotDataRateIndexValue() *DataRateIndexValue { return nil } +func (x *MACParameters) GetRelay() *RelayParameters { + if x != nil { + return x.Relay + } + return nil +} + // Template for creating end devices. type EndDeviceVersion struct { state protoimpl.MessageState @@ -541,7 +1010,7 @@ type EndDeviceVersion struct { func (x *EndDeviceVersion) Reset() { *x = EndDeviceVersion{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[3] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -554,7 +1023,7 @@ func (x *EndDeviceVersion) String() string { func (*EndDeviceVersion) ProtoMessage() {} func (x *EndDeviceVersion) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[3] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -567,7 +1036,7 @@ func (x *EndDeviceVersion) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDeviceVersion.ProtoReflect.Descriptor instead. func (*EndDeviceVersion) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{3} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{8} } func (x *EndDeviceVersion) GetIds() *EndDeviceVersionIdentifiers { @@ -677,7 +1146,7 @@ type ADRSettings struct { func (x *ADRSettings) Reset() { *x = ADRSettings{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[4] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -690,7 +1159,7 @@ func (x *ADRSettings) String() string { func (*ADRSettings) ProtoMessage() {} func (x *ADRSettings) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[4] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -703,7 +1172,7 @@ func (x *ADRSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRSettings.ProtoReflect.Descriptor instead. func (*ADRSettings) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9} } func (m *ADRSettings) GetMode() isADRSettings_Mode { @@ -867,12 +1336,18 @@ type MACSettings struct { // This option can be used in order to disable any downlink interaction with the end device. It will affect all types // of downlink messages: data and MAC downlinks, and join accepts. ScheduleDownlinks *BoolValue `protobuf:"bytes,35,opt,name=schedule_downlinks,json=scheduleDownlinks,proto3" json:"schedule_downlinks,omitempty"` + // The relay parameters the end device is using. + // If unset, the default value from Network Server configuration or regional parameters specification will be used. + Relay *RelayParameters `protobuf:"bytes,36,opt,name=relay,proto3" json:"relay,omitempty"` + // The relay parameters the Network Server should configure device to use via MAC commands. + // If unset, the default value from Network Server configuration or regional parameters specification will be used. + DesiredRelay *RelayParameters `protobuf:"bytes,37,opt,name=desired_relay,json=desiredRelay,proto3" json:"desired_relay,omitempty"` } func (x *MACSettings) Reset() { *x = MACSettings{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -885,7 +1360,7 @@ func (x *MACSettings) String() string { func (*MACSettings) ProtoMessage() {} func (x *MACSettings) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[5] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -898,7 +1373,7 @@ func (x *MACSettings) ProtoReflect() protoreflect.Message { // Deprecated: Use MACSettings.ProtoReflect.Descriptor instead. func (*MACSettings) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{5} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{10} } func (x *MACSettings) GetClassBTimeout() *durationpb.Duration { @@ -1141,6 +1616,20 @@ func (x *MACSettings) GetScheduleDownlinks() *BoolValue { return nil } +func (x *MACSettings) GetRelay() *RelayParameters { + if x != nil { + return x.Relay + } + return nil +} + +func (x *MACSettings) GetDesiredRelay() *RelayParameters { + if x != nil { + return x.DesiredRelay + } + return nil +} + // MACState represents the state of MAC layer of the device. // MACState is reset on each join for OTAA or ResetInd for ABP devices. // This is used internally by the Network Server. @@ -1211,12 +1700,16 @@ type MACState struct { // The Network Server may choose to store only certain types of MAC // command identifiers in the underlying implementation. RecentMacCommandIdentifiers []MACCommandIdentifier `protobuf:"varint,23,rep,packed,name=recent_mac_command_identifiers,json=recentMacCommandIdentifiers,proto3,enum=ttn.lorawan.v3.MACCommandIdentifier" json:"recent_mac_command_identifiers,omitempty"` + // Pending relay downlink contents. + // The pending downlink will be scheduled to the relay in either Rx1 or Rx2. + // The pending downlink will be cleared after the scheduling attempt. + PendingRelayDownlink *RelayForwardDownlinkReq `protobuf:"bytes,24,opt,name=pending_relay_downlink,json=pendingRelayDownlink,proto3" json:"pending_relay_downlink,omitempty"` } func (x *MACState) Reset() { *x = MACState{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1229,7 +1722,7 @@ func (x *MACState) String() string { func (*MACState) ProtoMessage() {} func (x *MACState) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[6] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1242,7 +1735,7 @@ func (x *MACState) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState.ProtoReflect.Descriptor instead. func (*MACState) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11} } func (x *MACState) GetCurrentParameters() *MACParameters { @@ -1406,6 +1899,13 @@ func (x *MACState) GetRecentMacCommandIdentifiers() []MACCommandIdentifier { return nil } +func (x *MACState) GetPendingRelayDownlink() *RelayForwardDownlinkReq { + if x != nil { + return x.PendingRelayDownlink + } + return nil +} + // Authentication code for end devices. type EndDeviceAuthenticationCode struct { state protoimpl.MessageState @@ -1420,7 +1920,7 @@ type EndDeviceAuthenticationCode struct { func (x *EndDeviceAuthenticationCode) Reset() { *x = EndDeviceAuthenticationCode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1433,7 +1933,7 @@ func (x *EndDeviceAuthenticationCode) String() string { func (*EndDeviceAuthenticationCode) ProtoMessage() {} func (x *EndDeviceAuthenticationCode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[7] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1446,7 +1946,7 @@ func (x *EndDeviceAuthenticationCode) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDeviceAuthenticationCode.ProtoReflect.Descriptor instead. func (*EndDeviceAuthenticationCode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{7} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{12} } func (x *EndDeviceAuthenticationCode) GetValue() string { @@ -1639,7 +2139,7 @@ type EndDevice struct { func (x *EndDevice) Reset() { *x = EndDevice{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1652,7 +2152,7 @@ func (x *EndDevice) String() string { func (*EndDevice) ProtoMessage() {} func (x *EndDevice) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[8] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1665,7 +2165,7 @@ func (x *EndDevice) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDevice.ProtoReflect.Descriptor instead. func (*EndDevice) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{8} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{13} } func (x *EndDevice) GetIds() *EndDeviceIdentifiers { @@ -2050,7 +2550,7 @@ type EndDevices struct { func (x *EndDevices) Reset() { *x = EndDevices{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2063,7 +2563,7 @@ func (x *EndDevices) String() string { func (*EndDevices) ProtoMessage() {} func (x *EndDevices) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[9] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2076,7 +2576,7 @@ func (x *EndDevices) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDevices.ProtoReflect.Descriptor instead. func (*EndDevices) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{14} } func (x *EndDevices) GetEndDevices() []*EndDevice { @@ -2100,7 +2600,7 @@ type DevAddrPrefix struct { func (x *DevAddrPrefix) Reset() { *x = DevAddrPrefix{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2113,7 +2613,7 @@ func (x *DevAddrPrefix) String() string { func (*DevAddrPrefix) ProtoMessage() {} func (x *DevAddrPrefix) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[10] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2126,7 +2626,7 @@ func (x *DevAddrPrefix) ProtoReflect() protoreflect.Message { // Deprecated: Use DevAddrPrefix.ProtoReflect.Descriptor instead. func (*DevAddrPrefix) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{10} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{15} } func (x *DevAddrPrefix) GetDevAddr() []byte { @@ -2154,7 +2654,7 @@ type CreateEndDeviceRequest struct { func (x *CreateEndDeviceRequest) Reset() { *x = CreateEndDeviceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2167,7 +2667,7 @@ func (x *CreateEndDeviceRequest) String() string { func (*CreateEndDeviceRequest) ProtoMessage() {} func (x *CreateEndDeviceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[11] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2180,7 +2680,7 @@ func (x *CreateEndDeviceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateEndDeviceRequest.ProtoReflect.Descriptor instead. func (*CreateEndDeviceRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{16} } func (x *CreateEndDeviceRequest) GetEndDevice() *EndDevice { @@ -2204,7 +2704,7 @@ type UpdateEndDeviceRequest struct { func (x *UpdateEndDeviceRequest) Reset() { *x = UpdateEndDeviceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2217,7 +2717,7 @@ func (x *UpdateEndDeviceRequest) String() string { func (*UpdateEndDeviceRequest) ProtoMessage() {} func (x *UpdateEndDeviceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[12] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2230,7 +2730,7 @@ func (x *UpdateEndDeviceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateEndDeviceRequest.ProtoReflect.Descriptor instead. func (*UpdateEndDeviceRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{12} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{17} } func (x *UpdateEndDeviceRequest) GetEndDevice() *EndDevice { @@ -2259,7 +2759,7 @@ type BatchUpdateEndDeviceLastSeenRequest struct { func (x *BatchUpdateEndDeviceLastSeenRequest) Reset() { *x = BatchUpdateEndDeviceLastSeenRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2272,7 +2772,7 @@ func (x *BatchUpdateEndDeviceLastSeenRequest) String() string { func (*BatchUpdateEndDeviceLastSeenRequest) ProtoMessage() {} func (x *BatchUpdateEndDeviceLastSeenRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[13] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2285,7 +2785,7 @@ func (x *BatchUpdateEndDeviceLastSeenRequest) ProtoReflect() protoreflect.Messag // Deprecated: Use BatchUpdateEndDeviceLastSeenRequest.ProtoReflect.Descriptor instead. func (*BatchUpdateEndDeviceLastSeenRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{13} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{18} } func (x *BatchUpdateEndDeviceLastSeenRequest) GetUpdates() []*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate { @@ -2309,7 +2809,7 @@ type GetEndDeviceRequest struct { func (x *GetEndDeviceRequest) Reset() { *x = GetEndDeviceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2322,7 +2822,7 @@ func (x *GetEndDeviceRequest) String() string { func (*GetEndDeviceRequest) ProtoMessage() {} func (x *GetEndDeviceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[14] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2335,7 +2835,7 @@ func (x *GetEndDeviceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEndDeviceRequest.ProtoReflect.Descriptor instead. func (*GetEndDeviceRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{14} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{19} } func (x *GetEndDeviceRequest) GetEndDeviceIds() *EndDeviceIdentifiers { @@ -2364,7 +2864,7 @@ type GetEndDeviceIdentifiersForEUIsRequest struct { func (x *GetEndDeviceIdentifiersForEUIsRequest) Reset() { *x = GetEndDeviceIdentifiersForEUIsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2377,7 +2877,7 @@ func (x *GetEndDeviceIdentifiersForEUIsRequest) String() string { func (*GetEndDeviceIdentifiersForEUIsRequest) ProtoMessage() {} func (x *GetEndDeviceIdentifiersForEUIsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[15] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2390,7 +2890,7 @@ func (x *GetEndDeviceIdentifiersForEUIsRequest) ProtoReflect() protoreflect.Mess // Deprecated: Use GetEndDeviceIdentifiersForEUIsRequest.ProtoReflect.Descriptor instead. func (*GetEndDeviceIdentifiersForEUIsRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{15} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{20} } func (x *GetEndDeviceIdentifiersForEUIsRequest) GetJoinEui() []byte { @@ -2428,7 +2928,7 @@ type ListEndDevicesRequest struct { func (x *ListEndDevicesRequest) Reset() { *x = ListEndDevicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2441,7 +2941,7 @@ func (x *ListEndDevicesRequest) String() string { func (*ListEndDevicesRequest) ProtoMessage() {} func (x *ListEndDevicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[16] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2454,7 +2954,7 @@ func (x *ListEndDevicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListEndDevicesRequest.ProtoReflect.Descriptor instead. func (*ListEndDevicesRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{16} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{21} } func (x *ListEndDevicesRequest) GetApplicationIds() *ApplicationIdentifiers { @@ -2506,7 +3006,7 @@ type SetEndDeviceRequest struct { func (x *SetEndDeviceRequest) Reset() { *x = SetEndDeviceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2519,7 +3019,7 @@ func (x *SetEndDeviceRequest) String() string { func (*SetEndDeviceRequest) ProtoMessage() {} func (x *SetEndDeviceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[17] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2532,7 +3032,7 @@ func (x *SetEndDeviceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetEndDeviceRequest.ProtoReflect.Descriptor instead. func (*SetEndDeviceRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{17} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{22} } func (x *SetEndDeviceRequest) GetEndDevice() *EndDevice { @@ -2563,7 +3063,7 @@ type ResetAndGetEndDeviceRequest struct { func (x *ResetAndGetEndDeviceRequest) Reset() { *x = ResetAndGetEndDeviceRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[18] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2576,7 +3076,7 @@ func (x *ResetAndGetEndDeviceRequest) String() string { func (*ResetAndGetEndDeviceRequest) ProtoMessage() {} func (x *ResetAndGetEndDeviceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[18] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2589,7 +3089,7 @@ func (x *ResetAndGetEndDeviceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResetAndGetEndDeviceRequest.ProtoReflect.Descriptor instead. func (*ResetAndGetEndDeviceRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{18} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{23} } func (x *ResetAndGetEndDeviceRequest) GetEndDeviceIds() *EndDeviceIdentifiers { @@ -2619,7 +3119,7 @@ type EndDeviceTemplate struct { func (x *EndDeviceTemplate) Reset() { *x = EndDeviceTemplate{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[19] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2632,7 +3132,7 @@ func (x *EndDeviceTemplate) String() string { func (*EndDeviceTemplate) ProtoMessage() {} func (x *EndDeviceTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[19] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2645,7 +3145,7 @@ func (x *EndDeviceTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDeviceTemplate.ProtoReflect.Descriptor instead. func (*EndDeviceTemplate) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{19} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{24} } func (x *EndDeviceTemplate) GetEndDevice() *EndDevice { @@ -2682,7 +3182,7 @@ type EndDeviceTemplateFormat struct { func (x *EndDeviceTemplateFormat) Reset() { *x = EndDeviceTemplateFormat{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2695,7 +3195,7 @@ func (x *EndDeviceTemplateFormat) String() string { func (*EndDeviceTemplateFormat) ProtoMessage() {} func (x *EndDeviceTemplateFormat) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2708,7 +3208,7 @@ func (x *EndDeviceTemplateFormat) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDeviceTemplateFormat.ProtoReflect.Descriptor instead. func (*EndDeviceTemplateFormat) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{20} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{25} } func (x *EndDeviceTemplateFormat) GetName() string { @@ -2743,7 +3243,7 @@ type EndDeviceTemplateFormats struct { func (x *EndDeviceTemplateFormats) Reset() { *x = EndDeviceTemplateFormats{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2756,7 +3256,7 @@ func (x *EndDeviceTemplateFormats) String() string { func (*EndDeviceTemplateFormats) ProtoMessage() {} func (x *EndDeviceTemplateFormats) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2769,7 +3269,7 @@ func (x *EndDeviceTemplateFormats) ProtoReflect() protoreflect.Message { // Deprecated: Use EndDeviceTemplateFormats.ProtoReflect.Descriptor instead. func (*EndDeviceTemplateFormats) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{21} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{26} } func (x *EndDeviceTemplateFormats) GetFormats() map[string]*EndDeviceTemplateFormat { @@ -2795,7 +3295,7 @@ type ConvertEndDeviceTemplateRequest struct { func (x *ConvertEndDeviceTemplateRequest) Reset() { *x = ConvertEndDeviceTemplateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2808,7 +3308,7 @@ func (x *ConvertEndDeviceTemplateRequest) String() string { func (*ConvertEndDeviceTemplateRequest) ProtoMessage() {} func (x *ConvertEndDeviceTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2821,7 +3321,7 @@ func (x *ConvertEndDeviceTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConvertEndDeviceTemplateRequest.ProtoReflect.Descriptor instead. func (*ConvertEndDeviceTemplateRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{22} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{27} } func (x *ConvertEndDeviceTemplateRequest) GetFormatId() string { @@ -2857,7 +3357,7 @@ type BatchDeleteEndDevicesRequest struct { func (x *BatchDeleteEndDevicesRequest) Reset() { *x = BatchDeleteEndDevicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2870,7 +3370,7 @@ func (x *BatchDeleteEndDevicesRequest) String() string { func (*BatchDeleteEndDevicesRequest) ProtoMessage() {} func (x *BatchDeleteEndDevicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2883,7 +3383,7 @@ func (x *BatchDeleteEndDevicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchDeleteEndDevicesRequest.ProtoReflect.Descriptor instead. func (*BatchDeleteEndDevicesRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{23} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{28} } func (x *BatchDeleteEndDevicesRequest) GetApplicationIds() *ApplicationIdentifiers { @@ -2916,7 +3416,7 @@ type BatchGetEndDevicesRequest struct { func (x *BatchGetEndDevicesRequest) Reset() { *x = BatchGetEndDevicesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2929,7 +3429,7 @@ func (x *BatchGetEndDevicesRequest) String() string { func (*BatchGetEndDevicesRequest) ProtoMessage() {} func (x *BatchGetEndDevicesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2942,7 +3442,7 @@ func (x *BatchGetEndDevicesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchGetEndDevicesRequest.ProtoReflect.Descriptor instead. func (*BatchGetEndDevicesRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{24} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{29} } func (x *BatchGetEndDevicesRequest) GetApplicationIds() *ApplicationIdentifiers { @@ -2986,7 +3486,7 @@ type MACParameters_Channel struct { func (x *MACParameters_Channel) Reset() { *x = MACParameters_Channel{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[25] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2999,7 +3499,7 @@ func (x *MACParameters_Channel) String() string { func (*MACParameters_Channel) ProtoMessage() {} func (x *MACParameters_Channel) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[25] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3012,7 +3512,7 @@ func (x *MACParameters_Channel) ProtoReflect() protoreflect.Message { // Deprecated: Use MACParameters_Channel.ProtoReflect.Descriptor instead. func (*MACParameters_Channel) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{2, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{7, 0} } func (x *MACParameters_Channel) GetUplinkFrequency() uint64 { @@ -3067,7 +3567,7 @@ type ADRSettings_StaticMode struct { func (x *ADRSettings_StaticMode) Reset() { *x = ADRSettings_StaticMode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[26] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3080,7 +3580,7 @@ func (x *ADRSettings_StaticMode) String() string { func (*ADRSettings_StaticMode) ProtoMessage() {} func (x *ADRSettings_StaticMode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[26] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3093,7 +3593,7 @@ func (x *ADRSettings_StaticMode) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRSettings_StaticMode.ProtoReflect.Descriptor instead. func (*ADRSettings_StaticMode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 0} } func (x *ADRSettings_StaticMode) GetDataRateIndex() DataRateIndex { @@ -3151,7 +3651,7 @@ type ADRSettings_DynamicMode struct { func (x *ADRSettings_DynamicMode) Reset() { *x = ADRSettings_DynamicMode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[27] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3164,7 +3664,7 @@ func (x *ADRSettings_DynamicMode) String() string { func (*ADRSettings_DynamicMode) ProtoMessage() {} func (x *ADRSettings_DynamicMode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[27] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3177,7 +3677,7 @@ func (x *ADRSettings_DynamicMode) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRSettings_DynamicMode.ProtoReflect.Descriptor instead. func (*ADRSettings_DynamicMode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 1} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 1} } func (x *ADRSettings_DynamicMode) GetMargin() *wrapperspb.FloatValue { @@ -3247,7 +3747,7 @@ type ADRSettings_DisabledMode struct { func (x *ADRSettings_DisabledMode) Reset() { *x = ADRSettings_DisabledMode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[28] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3260,7 +3760,7 @@ func (x *ADRSettings_DisabledMode) String() string { func (*ADRSettings_DisabledMode) ProtoMessage() {} func (x *ADRSettings_DisabledMode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[28] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3273,7 +3773,7 @@ func (x *ADRSettings_DisabledMode) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRSettings_DisabledMode.ProtoReflect.Descriptor instead. func (*ADRSettings_DisabledMode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 2} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 2} } // EXPERIMENTAL: Channel steering settings. @@ -3291,7 +3791,7 @@ type ADRSettings_DynamicMode_ChannelSteeringSettings struct { func (x *ADRSettings_DynamicMode_ChannelSteeringSettings) Reset() { *x = ADRSettings_DynamicMode_ChannelSteeringSettings{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[29] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3304,7 +3804,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings) String() string { func (*ADRSettings_DynamicMode_ChannelSteeringSettings) ProtoMessage() {} func (x *ADRSettings_DynamicMode_ChannelSteeringSettings) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[29] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3317,7 +3817,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings) ProtoReflect() protore // Deprecated: Use ADRSettings_DynamicMode_ChannelSteeringSettings.ProtoReflect.Descriptor instead. func (*ADRSettings_DynamicMode_ChannelSteeringSettings) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 1, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 1, 0} } func (m *ADRSettings_DynamicMode_ChannelSteeringSettings) GetMode() isADRSettings_DynamicMode_ChannelSteeringSettings_Mode { @@ -3371,7 +3871,7 @@ type ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode struct { func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) Reset() { *x = ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[30] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3384,7 +3884,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) String( func (*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) ProtoMessage() {} func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[30] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3397,7 +3897,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) ProtoRe // Deprecated: Use ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode.ProtoReflect.Descriptor instead. func (*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 1, 0, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 1, 0, 0} } // Configuration options for cases in which ADR is not supposed to steer the end device @@ -3411,7 +3911,7 @@ type ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode struct { func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) Reset() { *x = ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[31] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3424,7 +3924,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) String() func (*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) ProtoMessage() {} func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[31] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3437,7 +3937,7 @@ func (x *ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) ProtoRefl // Deprecated: Use ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode.ProtoReflect.Descriptor instead. func (*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{4, 1, 0, 1} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{9, 1, 0, 1} } type MACState_JoinRequest struct { @@ -3453,7 +3953,7 @@ type MACState_JoinRequest struct { func (x *MACState_JoinRequest) Reset() { *x = MACState_JoinRequest{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[32] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3466,7 +3966,7 @@ func (x *MACState_JoinRequest) String() string { func (*MACState_JoinRequest) ProtoMessage() {} func (x *MACState_JoinRequest) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[32] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3479,7 +3979,7 @@ func (x *MACState_JoinRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_JoinRequest.ProtoReflect.Descriptor instead. func (*MACState_JoinRequest) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 0} } func (x *MACState_JoinRequest) GetDownlinkSettings() *DLSettings { @@ -3521,7 +4021,7 @@ type MACState_JoinAccept struct { func (x *MACState_JoinAccept) Reset() { *x = MACState_JoinAccept{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[33] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3534,7 +4034,7 @@ func (x *MACState_JoinAccept) String() string { func (*MACState_JoinAccept) ProtoMessage() {} func (x *MACState_JoinAccept) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[33] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3547,7 +4047,7 @@ func (x *MACState_JoinAccept) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_JoinAccept.ProtoReflect.Descriptor instead. func (*MACState_JoinAccept) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 1} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 1} } func (x *MACState_JoinAccept) GetPayload() []byte { @@ -3610,7 +4110,7 @@ type MACState_UplinkMessage struct { func (x *MACState_UplinkMessage) Reset() { *x = MACState_UplinkMessage{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[34] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3623,7 +4123,7 @@ func (x *MACState_UplinkMessage) String() string { func (*MACState_UplinkMessage) ProtoMessage() {} func (x *MACState_UplinkMessage) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[34] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3636,7 +4136,7 @@ func (x *MACState_UplinkMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_UplinkMessage.ProtoReflect.Descriptor instead. func (*MACState_UplinkMessage) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 2} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 2} } func (x *MACState_UplinkMessage) GetPayload() *Message { @@ -3695,7 +4195,7 @@ type MACState_DownlinkMessage struct { func (x *MACState_DownlinkMessage) Reset() { *x = MACState_DownlinkMessage{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[35] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3708,7 +4208,7 @@ func (x *MACState_DownlinkMessage) String() string { func (*MACState_DownlinkMessage) ProtoMessage() {} func (x *MACState_DownlinkMessage) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[35] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3721,7 +4221,7 @@ func (x *MACState_DownlinkMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_DownlinkMessage.ProtoReflect.Descriptor instead. func (*MACState_DownlinkMessage) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 3} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 3} } func (x *MACState_DownlinkMessage) GetPayload() *MACState_DownlinkMessage_Message { @@ -3750,7 +4250,7 @@ type MACState_DataRateRange struct { func (x *MACState_DataRateRange) Reset() { *x = MACState_DataRateRange{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[36] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3763,7 +4263,7 @@ func (x *MACState_DataRateRange) String() string { func (*MACState_DataRateRange) ProtoMessage() {} func (x *MACState_DataRateRange) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[36] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3776,7 +4276,7 @@ func (x *MACState_DataRateRange) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_DataRateRange.ProtoReflect.Descriptor instead. func (*MACState_DataRateRange) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 4} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 4} } func (x *MACState_DataRateRange) GetMinDataRateIndex() DataRateIndex { @@ -3804,7 +4304,7 @@ type MACState_DataRateRanges struct { func (x *MACState_DataRateRanges) Reset() { *x = MACState_DataRateRanges{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[37] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3817,7 +4317,7 @@ func (x *MACState_DataRateRanges) String() string { func (*MACState_DataRateRanges) ProtoMessage() {} func (x *MACState_DataRateRanges) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[37] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3830,7 +4330,7 @@ func (x *MACState_DataRateRanges) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_DataRateRanges.ProtoReflect.Descriptor instead. func (*MACState_DataRateRanges) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 5} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 5} } func (x *MACState_DataRateRanges) GetRanges() []*MACState_DataRateRange { @@ -3851,7 +4351,7 @@ type MACState_UplinkMessage_TxSettings struct { func (x *MACState_UplinkMessage_TxSettings) Reset() { *x = MACState_UplinkMessage_TxSettings{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[39] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3864,7 +4364,7 @@ func (x *MACState_UplinkMessage_TxSettings) String() string { func (*MACState_UplinkMessage_TxSettings) ProtoMessage() {} func (x *MACState_UplinkMessage_TxSettings) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[39] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[44] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3877,7 +4377,7 @@ func (x *MACState_UplinkMessage_TxSettings) ProtoReflect() protoreflect.Message // Deprecated: Use MACState_UplinkMessage_TxSettings.ProtoReflect.Descriptor instead. func (*MACState_UplinkMessage_TxSettings) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 2, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 2, 0} } func (x *MACState_UplinkMessage_TxSettings) GetDataRate() *DataRate { @@ -3898,12 +4398,13 @@ type MACState_UplinkMessage_RxMetadata struct { DownlinkPathConstraint DownlinkPathConstraint `protobuf:"varint,14,opt,name=downlink_path_constraint,json=downlinkPathConstraint,proto3,enum=ttn.lorawan.v3.DownlinkPathConstraint" json:"downlink_path_constraint,omitempty"` UplinkToken []byte `protobuf:"bytes,15,opt,name=uplink_token,json=uplinkToken,proto3" json:"uplink_token,omitempty"` PacketBroker *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata `protobuf:"bytes,18,opt,name=packet_broker,json=packetBroker,proto3" json:"packet_broker,omitempty"` + Relay *MACState_UplinkMessage_RxMetadata_RelayMetadata `protobuf:"bytes,23,opt,name=relay,proto3" json:"relay,omitempty"` } func (x *MACState_UplinkMessage_RxMetadata) Reset() { *x = MACState_UplinkMessage_RxMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[40] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3916,7 +4417,7 @@ func (x *MACState_UplinkMessage_RxMetadata) String() string { func (*MACState_UplinkMessage_RxMetadata) ProtoMessage() {} func (x *MACState_UplinkMessage_RxMetadata) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[40] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3929,7 +4430,7 @@ func (x *MACState_UplinkMessage_RxMetadata) ProtoReflect() protoreflect.Message // Deprecated: Use MACState_UplinkMessage_RxMetadata.ProtoReflect.Descriptor instead. func (*MACState_UplinkMessage_RxMetadata) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 2, 1} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 2, 1} } func (x *MACState_UplinkMessage_RxMetadata) GetGatewayIds() *GatewayIdentifiers { @@ -3974,6 +4475,13 @@ func (x *MACState_UplinkMessage_RxMetadata) GetPacketBroker() *MACState_UplinkMe return nil } +func (x *MACState_UplinkMessage_RxMetadata) GetRelay() *MACState_UplinkMessage_RxMetadata_RelayMetadata { + if x != nil { + return x.Relay + } + return nil +} + type MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3983,7 +4491,7 @@ type MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata struct { func (x *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) Reset() { *x = MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[41] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3996,7 +4504,7 @@ func (x *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) String() string func (*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) ProtoMessage() {} func (x *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[41] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4009,7 +4517,45 @@ func (x *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) ProtoReflect() // Deprecated: Use MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata.ProtoReflect.Descriptor instead. func (*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 2, 1, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 2, 1, 0} +} + +type MACState_UplinkMessage_RxMetadata_RelayMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MACState_UplinkMessage_RxMetadata_RelayMetadata) Reset() { + *x = MACState_UplinkMessage_RxMetadata_RelayMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACState_UplinkMessage_RxMetadata_RelayMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACState_UplinkMessage_RxMetadata_RelayMetadata) ProtoMessage() {} + +func (x *MACState_UplinkMessage_RxMetadata_RelayMetadata) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACState_UplinkMessage_RxMetadata_RelayMetadata.ProtoReflect.Descriptor instead. +func (*MACState_UplinkMessage_RxMetadata_RelayMetadata) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 2, 1, 1} } type MACState_DownlinkMessage_Message struct { @@ -4024,7 +4570,7 @@ type MACState_DownlinkMessage_Message struct { func (x *MACState_DownlinkMessage_Message) Reset() { *x = MACState_DownlinkMessage_Message{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[42] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4037,7 +4583,7 @@ func (x *MACState_DownlinkMessage_Message) String() string { func (*MACState_DownlinkMessage_Message) ProtoMessage() {} func (x *MACState_DownlinkMessage_Message) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[42] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4050,7 +4596,7 @@ func (x *MACState_DownlinkMessage_Message) ProtoReflect() protoreflect.Message { // Deprecated: Use MACState_DownlinkMessage_Message.ProtoReflect.Descriptor instead. func (*MACState_DownlinkMessage_Message) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 3, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 3, 0} } func (x *MACState_DownlinkMessage_Message) GetMHdr() *MACState_DownlinkMessage_Message_MHDR { @@ -4078,7 +4624,7 @@ type MACState_DownlinkMessage_Message_MHDR struct { func (x *MACState_DownlinkMessage_Message_MHDR) Reset() { *x = MACState_DownlinkMessage_Message_MHDR{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[43] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4091,7 +4637,7 @@ func (x *MACState_DownlinkMessage_Message_MHDR) String() string { func (*MACState_DownlinkMessage_Message_MHDR) ProtoMessage() {} func (x *MACState_DownlinkMessage_Message_MHDR) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[43] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4104,7 +4650,7 @@ func (x *MACState_DownlinkMessage_Message_MHDR) ProtoReflect() protoreflect.Mess // Deprecated: Use MACState_DownlinkMessage_Message_MHDR.ProtoReflect.Descriptor instead. func (*MACState_DownlinkMessage_Message_MHDR) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 3, 0, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 3, 0, 0} } func (x *MACState_DownlinkMessage_Message_MHDR) GetMType() MType { @@ -4126,7 +4672,7 @@ type MACState_DownlinkMessage_Message_MACPayload struct { func (x *MACState_DownlinkMessage_Message_MACPayload) Reset() { *x = MACState_DownlinkMessage_Message_MACPayload{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[44] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4139,7 +4685,7 @@ func (x *MACState_DownlinkMessage_Message_MACPayload) String() string { func (*MACState_DownlinkMessage_Message_MACPayload) ProtoMessage() {} func (x *MACState_DownlinkMessage_Message_MACPayload) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[44] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4152,7 +4698,7 @@ func (x *MACState_DownlinkMessage_Message_MACPayload) ProtoReflect() protoreflec // Deprecated: Use MACState_DownlinkMessage_Message_MACPayload.ProtoReflect.Descriptor instead. func (*MACState_DownlinkMessage_Message_MACPayload) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{6, 3, 0, 1} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{11, 3, 0, 1} } func (x *MACState_DownlinkMessage_Message_MACPayload) GetFPort() uint32 { @@ -4181,7 +4727,7 @@ type BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate struct { func (x *BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) Reset() { *x = BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[47] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4194,7 +4740,7 @@ func (x *BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) String() s func (*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) ProtoMessage() {} func (x *BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[47] + mi := &file_ttn_lorawan_v3_end_device_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4207,7 +4753,7 @@ func (x *BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) ProtoRefle // Deprecated: Use BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate.ProtoReflect.Descriptor instead. func (*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{13, 0} + return file_ttn_lorawan_v3_end_device_proto_rawDescGZIP(), []int{18, 0} } func (x *BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate) GetIds() *EndDeviceIdentifiers { @@ -4314,834 +4860,990 @@ var file_ttn_lorawan_v3_end_device_proto_rawDesc = []byte{ 0x01, 0x10, 0x02, 0x22, 0x33, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, - 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0xc5, 0x0f, 0x0a, 0x0d, 0x4d, 0x41, 0x43, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, - 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, 0x6d, 0x61, - 0x78, 0x45, 0x69, 0x72, 0x70, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x64, 0x72, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x61, 0x64, 0x72, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x34, 0x0a, - 0x12, 0x61, 0x64, 0x72, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, - 0x18, 0x0f, 0x52, 0x0f, 0x61, 0x64, 0x72, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x0c, 0x61, 0x64, 0x72, 0x5f, 0x6e, 0x62, 0x5f, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, - 0x18, 0x0f, 0x52, 0x0a, 0x61, 0x64, 0x72, 0x4e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x12, 0x26, - 0x0a, 0x0d, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x61, 0x64, 0x72, 0x41, 0x63, - 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, - 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, - 0x01, 0x52, 0x0b, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x3e, - 0x0a, 0x09, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x72, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x59, - 0x0a, 0x14, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x56, 0x0a, 0x13, 0x72, 0x78, 0x32, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x2e, 0x0a, 0x0d, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, - 0xa0, 0x8d, 0x06, 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x12, 0x53, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, - 0x63, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, 0x75, 0x74, - 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x17, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, - 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, - 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x15, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, - 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x67, 0x0a, 0x18, - 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x72, - 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, + 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x95, 0x03, 0x0a, 0x1c, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x4d, 0x0a, 0x0e, 0x72, 0x65, 0x73, + 0x65, 0x74, 0x5f, 0x62, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x65, 0x74, + 0x42, 0x65, 0x68, 0x61, 0x76, 0x69, 0x6f, 0x72, 0x12, 0x47, 0x0a, 0x0d, 0x6a, 0x6f, 0x69, 0x6e, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x73, 0x52, 0x0c, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x73, 0x12, 0x48, 0x0a, 0x0d, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x0d, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x4b, 0x0a, 0x0f, 0x75, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x07, 0x6f, 0x76, 0x65, 0x72, + 0x61, 0x6c, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x07, 0x6f, + 0x76, 0x65, 0x72, 0x61, 0x6c, 0x6c, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, + 0x22, 0xf7, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x40, + 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x16, 0x72, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, - 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, - 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x10, 0x20, 0x01, - 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, - 0x11, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x12, 0x5b, 0x0a, 0x19, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x11, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x42, 0x02, 0x18, 0x01, 0x52, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, - 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x36, 0x0a, 0x10, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, - 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x4b, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x45, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, - 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x69, - 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x13, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, - 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x5d, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, - 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x5d, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, - 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, - 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, - 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x67, 0x0a, 0x1f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, - 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x1a, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0xda, 0x02, - 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x10, 0x75, 0x70, 0x6c, - 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, - 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x12, 0x38, 0x0a, 0x12, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, - 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x56, 0x0a, 0x13, 0x6d, - 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x12, 0x1f, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x77, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x57, 0x46, 0x43, 0x6e, + 0x74, 0x12, 0x47, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0xfa, 0x42, 0x27, 0x72, 0x25, 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, 0xd0, 0x01, 0x01, + 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xb6, 0x03, 0x0a, 0x16, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x49, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x3c, 0x0a, 0x15, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, + 0x0a, 0x0f, 0x63, 0x61, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x41, + 0x44, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x63, 0x61, 0x64, 0x50, 0x65, 0x72, 0x69, 0x6f, + 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x6b, 0x0a, 0x17, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x5f, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6c, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x75, + 0x6c, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x10, 0x10, 0x52, 0x15, 0x75, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x73, 0x52, 0x06, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, + 0x01, 0x10, 0x01, 0x22, 0xe2, 0x03, 0x0a, 0x15, 0x53, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x42, 0x0a, + 0x06, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x6c, 0x77, + 0x61, 0x79, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x06, 0x61, 0x6c, 0x77, 0x61, 0x79, + 0x73, 0x12, 0x45, 0x0a, 0x07, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, + 0x07, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x12, 0x62, 0x0a, 0x15, 0x65, 0x6e, 0x64, 0x5f, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x13, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x07, + 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x2a, 0x02, 0x18, 0x3f, 0x52, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, + 0x49, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0d, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x53, 0x0a, 0x11, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xfa, 0x42, 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, 0x52, 0x0f, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x3a, + 0x0a, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x0b, 0x0a, 0x04, 0x6d, + 0x6f, 0x64, 0x65, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0f, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x42, 0x0a, 0x07, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, + 0x12, 0x3f, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, + 0x64, 0x3a, 0x0a, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x0b, 0x0a, + 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xfc, 0x0f, 0x0a, 0x0d, 0x4d, + 0x41, 0x43, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x19, 0x0a, 0x08, + 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x07, + 0x6d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x12, 0x56, 0x0a, 0x13, 0x61, 0x64, 0x72, 0x5f, 0x64, + 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x61, + 0x64, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x34, 0x0a, 0x12, 0x61, 0x64, 0x72, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0f, 0x61, 0x64, 0x72, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x0c, 0x61, 0x64, 0x72, 0x5f, 0x6e, 0x62, 0x5f, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, + 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0a, 0x61, 0x64, 0x72, 0x4e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x12, 0x26, 0x0a, 0x0d, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x61, 0x64, 0x72, + 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x61, 0x64, 0x72, 0x5f, + 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x42, + 0x02, 0x18, 0x01, 0x52, 0x0b, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x12, 0x3e, 0x0a, 0x09, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x72, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x12, 0x59, 0x0a, 0x14, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x56, 0x0a, 0x13, 0x72, + 0x78, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, - 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, - 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, - 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, - 0x22, 0xfa, 0x05, 0x0a, 0x10, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x4d, - 0x0a, 0x0f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x54, 0x0a, - 0x13, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x11, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x06, 0x70, 0x68, 0x6f, 0x74, - 0x6f, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, - 0x10, 0x0a, 0x52, 0x06, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, - 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, - 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x4d, - 0x0a, 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x4d, 0x61, 0x63, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x23, 0x0a, - 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, - 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, - 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, - 0x4a, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x12, 0x64, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x22, 0xad, 0x0b, - 0x0a, 0x0b, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, - 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, - 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12, - 0x43, 0x0a, 0x07, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, - 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x64, 0x79, 0x6e, - 0x61, 0x6d, 0x69, 0x63, 0x12, 0x46, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x01, 0x52, 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x0d, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, + 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x79, 0x12, 0x53, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, + 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, + 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x17, 0x72, 0x65, 0x6a, 0x6f, + 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, + 0x69, 0x74, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, + 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x15, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, + 0x69, 0x6d, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x67, + 0x0a, 0x18, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, + 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x16, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x69, + 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x3b, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x5f, + 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, + 0x06, 0x52, 0x11, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x12, 0x5b, 0x0a, 0x19, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, + 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x02, 0x18, 0x01, 0x52, 0x15, 0x70, 0x69, 0x6e, 0x67, + 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x12, 0x36, 0x0a, 0x10, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, + 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, + 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x4b, 0x0a, 0x08, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x08, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x45, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x75, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x49, 0x0a, + 0x13, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x44, + 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x5d, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, + 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, + 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x5d, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, 0x61, + 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, + 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, + 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x67, 0x0a, 0x1f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, + 0x6c, 0x6f, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x1a, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x35, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x52, + 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x1a, 0xda, 0x02, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x36, 0x0a, 0x10, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, + 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e, + 0x6b, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x38, 0x0a, 0x12, 0x64, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, + 0x06, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x46, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, + 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x75, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, + 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, + 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0xfa, 0x05, 0x0a, 0x10, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x47, + 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x54, 0x0a, 0x13, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x5f, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, + 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, + 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x49, + 0x64, 0x12, 0x20, 0x0a, 0x06, 0x70, 0x68, 0x6f, 0x74, 0x6f, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x10, 0x0a, 0x52, 0x06, 0x70, 0x68, 0x6f, + 0x74, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, + 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, + 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x4d, 0x0a, 0x14, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x4d, 0x61, 0x63, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x66, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, + 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x6d, + 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6a, 0x6f, 0x69, + 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x5f, + 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x6e, + 0x63, 0x65, 0x73, 0x12, 0x61, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x46, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x22, 0xad, 0x0b, 0x0a, 0x0b, 0x41, 0x44, 0x52, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x40, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, - 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, - 0x48, 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0xbc, 0x01, 0x0a, - 0x0a, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, - 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2d, 0x0a, 0x0e, - 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0c, 0x74, - 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x08, 0x6e, - 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, - 0x42, 0x06, 0x2a, 0x04, 0x18, 0x0f, 0x28, 0x01, 0x52, 0x07, 0x6e, 0x62, 0x54, 0x72, 0x61, 0x6e, - 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0xe1, 0x07, 0x0a, 0x0b, - 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6d, - 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, - 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, - 0x12, 0x51, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, - 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x6e, 0x67, 0x73, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x12, 0x43, 0x0a, 0x07, 0x64, 0x79, 0x6e, 0x61, + 0x6d, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, + 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x12, 0x46, 0x0a, + 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0xbc, 0x01, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x51, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, - 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x52, 0x0a, 0x12, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x78, - 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 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, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x54, 0x78, - 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x52, 0x0a, 0x12, 0x6d, 0x61, - 0x78, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x05, 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, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0f, 0x6d, - 0x61, 0x78, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x49, - 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x06, - 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, 0x03, 0x28, 0x01, 0x52, 0x0a, 0x6d, - 0x69, 0x6e, 0x4e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x0c, 0x6d, 0x61, 0x78, - 0x5f, 0x6e, 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, + 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0c, 0x74, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x08, 0x6e, 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, 0x04, 0x18, 0x0f, 0x28, + 0x01, 0x52, 0x07, 0x6e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, + 0x08, 0x01, 0x10, 0x01, 0x1a, 0xe1, 0x07, 0x0a, 0x0b, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, + 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x51, 0x0a, 0x13, 0x6d, 0x69, 0x6e, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x51, 0x0a, 0x13, + 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x6d, + 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, + 0x52, 0x0a, 0x12, 0x6d, 0x69, 0x6e, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 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, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, + 0x18, 0x0f, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x52, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, + 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x05, 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, 0x03, 0x28, 0x01, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x4e, 0x62, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x12, 0x6a, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, - 0x73, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, - 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, - 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, - 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, - 0x1a, 0xc2, 0x02, 0x0a, 0x17, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, - 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x71, 0x0a, 0x0b, - 0x6c, 0x6f, 0x72, 0x61, 0x5f, 0x6e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x4e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, - 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x52, 0x61, 0x4e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x6f, 0x64, - 0x65, 0x48, 0x00, 0x52, 0x0a, 0x6c, 0x6f, 0x72, 0x61, 0x4e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x12, - 0x6a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x4c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, - 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x48, - 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x1a, 0x1a, 0x0a, 0x0e, 0x4c, - 0x6f, 0x52, 0x61, 0x4e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x18, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, - 0x01, 0x3a, 0x0a, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x06, 0x0a, - 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, - 0x18, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x3a, - 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x0a, 0xf2, 0xaa, 0x19, 0x06, 0x08, - 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0xf2, 0x15, - 0x0a, 0x0b, 0x4d, 0x41, 0x43, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x41, 0x0a, - 0x0f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x18, 0x01, 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, 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x12, 0x57, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x70, 0x65, - 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, - 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x5c, 0x0a, 0x19, 0x70, 0x69, 0x6e, - 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, + 0x66, 0x2e, 0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x54, 0x78, 0x50, 0x6f, 0x77, + 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x49, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x6e, + 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x06, 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, 0x03, 0x28, 0x01, 0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x4e, 0x62, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x6e, 0x62, 0x5f, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x18, 0x07, 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, 0x03, 0x28, + 0x01, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x4e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x12, 0x6a, 0x0a, + 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x73, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, + 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, 0x64, 0x65, + 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0xc2, 0x02, 0x0a, 0x17, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x71, 0x0a, 0x0b, 0x6c, 0x6f, 0x72, 0x61, 0x5f, 0x6e, 0x61, + 0x72, 0x72, 0x6f, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4e, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, + 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x4c, 0x6f, 0x52, 0x61, + 0x4e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x6c, 0x6f, + 0x72, 0x61, 0x4e, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x12, 0x6a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4c, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, + 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x74, 0x65, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x1a, 0x1a, 0x0a, 0x0e, 0x4c, 0x6f, 0x52, 0x61, 0x4e, 0x61, 0x72, 0x72, + 0x6f, 0x77, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, + 0x1a, 0x18, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x0a, 0xf2, 0xaa, 0x19, 0x06, + 0x08, 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x18, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, + 0x10, 0x01, 0x3a, 0x0a, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x20, 0x01, 0x42, 0x06, + 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0xef, 0x16, 0x0a, 0x0b, 0x4d, 0x41, 0x43, 0x53, 0x65, + 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x41, 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, + 0x62, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 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, 0x0d, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x42, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x57, 0x0a, 0x15, 0x70, 0x69, 0x6e, + 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, + 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, + 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x70, + 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, + 0x74, 0x79, 0x12, 0x5c, 0x0a, 0x19, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x53, + 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x56, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x5a, + 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x51, 0x0a, 0x10, 0x62, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x19, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x41, 0x0a, 0x0f, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, + 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, + 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x39, + 0x0a, 0x09, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x08, 0x72, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x54, 0x0a, 0x14, 0x72, 0x78, 0x31, + 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, + 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, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x72, 0x78, + 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, + 0x51, 0x0a, 0x13, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, - 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x5f, - 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x70, 0x69, - 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, - 0x51, 0x0a, 0x10, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, - 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x12, 0x41, 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 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, 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x54, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x39, 0x0a, 0x09, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, - 0x61, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, - 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x72, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, - 0x12, 0x54, 0x0a, 0x14, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, - 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 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, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x11, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x51, 0x0a, 0x13, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x43, 0x0a, 0x0d, 0x72, 0x78, 0x32, - 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x46, - 0x0a, 0x1a, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, - 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, - 0x28, 0x04, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x10, 0x60, 0x52, 0x18, 0x66, 0x61, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, 0x65, 0x73, 0x65, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x4e, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, - 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, - 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, 0x75, 0x74, - 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x4b, 0x0a, 0x15, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, - 0x74, 0x73, 0x5f, 0x33, 0x32, 0x5f, 0x62, 0x69, 0x74, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, - 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x33, 0x32, 0x42, 0x69, 0x74, 0x46, - 0x43, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x72, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, - 0x02, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x41, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x61, - 0x64, 0x72, 0x5f, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x02, 0x18, 0x01, - 0x52, 0x09, 0x61, 0x64, 0x72, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x3b, 0x0a, 0x0c, 0x72, - 0x65, 0x73, 0x65, 0x74, 0x73, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x72, 0x65, - 0x73, 0x65, 0x74, 0x73, 0x46, 0x43, 0x6e, 0x74, 0x12, 0x51, 0x0a, 0x17, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, - 0x69, 0x74, 0x79, 0x18, 0x10, 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, 0x15, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x69, 0x6d, 0x65, - 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x56, 0x0a, 0x18, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, - 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x11, 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, 0x52, 0x16, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, - 0x69, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x11, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, - 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x52, 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x43, 0x0a, 0x0d, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x46, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x46, 0x0a, 0x1a, 0x66, 0x61, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x5f, 0x70, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x04, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x92, 0x01, 0x02, 0x10, 0x60, 0x52, 0x18, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x72, + 0x65, 0x73, 0x65, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, + 0x4e, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, + 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, + 0x4b, 0x0a, 0x15, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x33, 0x32, 0x5f, 0x62, + 0x69, 0x74, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x64, 0x65, - 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x63, 0x0a, - 0x1c, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x13, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x18, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, - 0x64, 0x52, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x12, 0x60, 0x0a, 0x1b, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x78, - 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x73, 0x33, 0x32, 0x42, 0x69, 0x74, 0x46, 0x43, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x5f, 0x61, 0x64, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, + 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, + 0x65, 0x41, 0x64, 0x72, 0x12, 0x3e, 0x0a, 0x0a, 0x61, 0x64, 0x72, 0x5f, 0x6d, 0x61, 0x72, 0x67, + 0x69, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x64, 0x72, 0x4d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x12, 0x3b, 0x0a, 0x0c, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x5f, 0x66, + 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x46, 0x43, 0x6e, + 0x74, 0x12, 0x51, 0x0a, 0x17, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x10, 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, 0x15, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x54, 0x69, 0x6d, 0x65, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, + 0x63, 0x69, 0x74, 0x79, 0x12, 0x56, 0x0a, 0x18, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, + 0x18, 0x11, 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, 0x52, 0x16, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x48, 0x0a, 0x11, + 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65, 0x6c, 0x61, + 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, + 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x63, 0x0a, 0x1c, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, + 0x64, 0x5f, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x18, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x31, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x60, 0x0a, 0x1b, 0x64, + 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x32, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x52, 0x0a, + 0x15, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x46, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x64, 0x65, + 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x12, 0x5d, 0x0a, 0x16, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x6d, 0x61, 0x78, + 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, + 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, + 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x78, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, + 0x12, 0x6c, 0x0a, 0x1e, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, + 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x1a, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x41, 0x64, 0x72, 0x41, 0x63, + 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x6c, + 0x0a, 0x1e, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, + 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, + 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x1a, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x41, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, + 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x6b, 0x0a, 0x21, + 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, + 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, - 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x17, 0x64, 0x65, 0x73, - 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x32, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x12, 0x52, 0x0a, 0x15, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, - 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x78, 0x32, 0x46, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x5d, 0x0a, 0x16, 0x64, 0x65, 0x73, 0x69, - 0x72, 0x65, 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, - 0x6c, 0x65, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x13, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x78, 0x44, 0x75, - 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x6c, 0x0a, 0x1e, 0x64, 0x65, 0x73, 0x69, 0x72, - 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, - 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1a, 0x64, 0x65, 0x73, 0x69, 0x72, - 0x65, 0x64, 0x41, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x6c, 0x0a, 0x1e, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, - 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, - 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, - 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1a, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, - 0x41, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x12, 0x6b, 0x0a, 0x21, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, - 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x1c, 0x64, 0x65, 0x73, + 0x69, 0x72, 0x65, 0x64, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x65, 0x0a, 0x1b, 0x64, 0x65, 0x73, + 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x1c, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x50, 0x69, 0x6e, 0x67, 0x53, - 0x6c, 0x6f, 0x74, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x12, 0x65, 0x0a, 0x1b, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x69, 0x6e, 0x67, - 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x18, 0x64, - 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x60, 0x0a, 0x18, 0x64, 0x65, 0x73, 0x69, 0x72, - 0x65, 0x64, 0x5f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, - 0x6e, 0x63, 0x79, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, - 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x16, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x49, 0x0a, 0x10, 0x64, 0x65, 0x73, - 0x69, 0x72, 0x65, 0x64, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x1e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x78, - 0x45, 0x69, 0x72, 0x70, 0x12, 0x57, 0x0a, 0x1b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, - 0x63, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x76, 0x61, 0x6c, 0x18, 0x1f, 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, 0x17, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x44, 0x6f, 0x77, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x45, 0x0a, - 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x13, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, - 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, + 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x18, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x50, + 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x60, 0x0a, 0x18, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x62, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x1d, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x16, 0x64, 0x65, 0x73, 0x69, + 0x72, 0x65, 0x64, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x12, 0x49, 0x0a, 0x10, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x6d, 0x61, + 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x64, + 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x4d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x12, 0x57, 0x0a, + 0x1b, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x63, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x1f, 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, 0x17, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x42, 0x43, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x45, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x2d, 0x0a, 0x03, 0x61, 0x64, 0x72, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, - 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x03, 0x61, 0x64, 0x72, 0x12, 0x48, - 0x0a, 0x12, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, + 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x75, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x49, 0x0a, + 0x13, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, - 0x10, 0x01, 0x22, 0x96, 0x28, 0x0a, 0x08, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x56, 0x0a, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x74, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x44, + 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x03, 0x61, 0x64, 0x72, 0x18, + 0x22, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x52, 0x03, 0x61, 0x64, 0x72, 0x12, 0x48, 0x0a, 0x12, 0x73, 0x63, 0x68, 0x65, 0x64, + 0x75, 0x6c, 0x65, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x23, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x11, + 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x73, 0x12, 0x35, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x52, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x44, 0x0a, 0x0d, 0x64, 0x65, 0x73, 0x69, + 0x72, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x52, 0x0c, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xef, 0x29, 0x0a, 0x08, 0x4d, 0x41, 0x43, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x12, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x63, 0x75, 0x72, 0x72, + 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, + 0x12, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x11, 0x64, 0x65, 0x73, 0x69, 0x72, 0x65, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x42, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x57, 0x0a, 0x1a, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, 0x18, 0x05, 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, 0x17, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, + 0x74, 0x12, 0x35, 0x0a, 0x18, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x46, 0x43, 0x6e, 0x74, 0x55, 0x70, 0x12, 0x57, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, + 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, + 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, + 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x70, 0x69, + 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, + 0x79, 0x12, 0x65, 0x0a, 0x1c, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, + 0x6b, 0x18, 0x08, 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, 0x52, 0x1a, 0x70, 0x65, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x45, 0x0a, 0x10, 0x71, 0x75, 0x65, 0x75, + 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x0f, + 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, + 0x45, 0x0a, 0x10, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x51, 0x0a, 0x12, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, + 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4a, 0x6f, 0x69, + 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x52, 0x10, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x4a, + 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x56, 0x0a, 0x14, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x12, 0x70, + 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x30, 0x0a, 0x14, 0x72, 0x78, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, + 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x12, 0x72, 0x78, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x12, 0x4d, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x56, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x69, 0x72, - 0x65, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x11, 0x64, 0x65, - 0x73, 0x69, 0x72, 0x65, 0x64, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, - 0x42, 0x0a, 0x0c, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, - 0x61, 0x73, 0x73, 0x12, 0x4d, 0x0a, 0x0f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x0e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x57, 0x0a, 0x1a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, - 0x18, 0x05, 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, 0x17, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, - 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x74, 0x12, 0x35, 0x0a, 0x18, 0x6c, - 0x61, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x66, - 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6c, - 0x61, 0x73, 0x74, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x46, 0x43, 0x6e, 0x74, - 0x55, 0x70, 0x12, 0x57, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, - 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, - 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, - 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x65, 0x0a, 0x1c, 0x70, - 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x08, 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, 0x52, 0x1a, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x41, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x12, 0x45, 0x0a, 0x10, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x0f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x10, 0x70, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, 0x0a, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, - 0x12, 0x51, 0x0a, 0x12, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, - 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x6c, 0x69, 0x6e, + 0x6b, 0x73, 0x12, 0x53, 0x0a, 0x10, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, - 0x74, 0x52, 0x10, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, - 0x65, 0x70, 0x74, 0x12, 0x56, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6a, - 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x12, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x30, 0x0a, 0x14, 0x72, - 0x78, 0x5f, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x72, 0x78, 0x57, 0x69, 0x6e, - 0x64, 0x6f, 0x77, 0x73, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x4d, 0x0a, - 0x0e, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, - 0x0e, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, - 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0d, 0x72, - 0x65, 0x63, 0x65, 0x6e, 0x74, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x53, 0x0a, 0x10, - 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, - 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x52, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, - 0x73, 0x12, 0x66, 0x0a, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, - 0x6b, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, - 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, 0x18, 0x10, 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, 0x1e, 0x6c, 0x61, 0x73, 0x74, 0x4e, - 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x74, 0x12, 0x72, 0x0a, 0x1e, 0x72, 0x65, 0x6a, - 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, - 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, - 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x42, 0x0f, 0xfa, 0x42, 0x0c, 0x92, 0x01, 0x09, 0x10, 0x0f, 0x22, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x1a, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x41, 0x64, 0x72, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x50, 0x0a, - 0x1d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x74, 0x78, - 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x18, 0x12, - 0x20, 0x03, 0x28, 0x0d, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x92, 0x01, 0x08, 0x10, 0x0f, 0x22, 0x04, - 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x19, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x41, 0x64, - 0x72, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, - 0x41, 0x0a, 0x14, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x04, 0x42, 0x0e, 0xfa, - 0x42, 0x0b, 0x92, 0x01, 0x08, 0x22, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x13, 0x72, - 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, - 0x65, 0x73, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, 0x18, 0x14, 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, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x74, 0x12, 0x6f, 0x0a, 0x19, 0x72, 0x65, 0x6a, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x72, - 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x74, + 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x0f, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x44, 0x6f, + 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x66, 0x0a, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, 0x18, 0x10, 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, + 0x1e, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x6e, 0x69, 0x74, + 0x69, 0x61, 0x74, 0x65, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x74, 0x12, + 0x72, 0x0a, 0x1e, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x64, 0x72, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, + 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x0f, 0xfa, 0x42, 0x0c, 0x92, 0x01, 0x09, 0x10, 0x0f, + 0x22, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x1a, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x41, 0x64, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x65, 0x73, 0x12, 0x50, 0x0a, 0x1d, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, + 0x61, 0x64, 0x72, 0x5f, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x65, 0x73, 0x18, 0x12, 0x20, 0x03, 0x28, 0x0d, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x92, + 0x01, 0x08, 0x10, 0x0f, 0x22, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x19, 0x72, 0x65, 0x6a, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x41, 0x64, 0x72, 0x54, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x14, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x13, 0x20, + 0x03, 0x28, 0x04, 0x42, 0x0e, 0xfa, 0x42, 0x0b, 0x92, 0x01, 0x08, 0x22, 0x06, 0x32, 0x04, 0x28, + 0xa0, 0x8d, 0x06, 0x52, 0x13, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, + 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x74, 0x18, 0x14, 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, 0x0e, + 0x6c, 0x61, 0x73, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x74, 0x12, 0x6f, + 0x0a, 0x19, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x72, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x16, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, + 0x35, 0x0a, 0x18, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x18, 0x16, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x41, 0x64, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x46, 0x43, 0x6e, 0x74, 0x55, 0x70, 0x12, 0x69, 0x0a, 0x1e, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, + 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x24, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x52, 0x1b, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x63, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, + 0x73, 0x12, 0x5d, 0x0a, 0x16, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x6c, + 0x61, 0x79, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x18, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x44, + 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x52, 0x14, 0x70, 0x65, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x1a, 0x83, 0x02, 0x0a, 0x0b, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x51, 0x0a, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x4c, 0x53, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x10, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x53, 0x65, 0x74, 0x74, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x3c, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x72, 0x78, 0x44, 0x65, 0x6c, 0x61, + 0x79, 0x12, 0x2f, 0x0a, 0x07, 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x46, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x06, 0x63, 0x66, 0x4c, 0x69, + 0x73, 0x74, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, + 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, + 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x1a, 0xd1, 0x07, 0x0a, 0x0a, 0x4a, 0x6f, 0x69, 0x6e, 0x41, + 0x63, 0x63, 0x65, 0x70, 0x74, 0x12, 0x23, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x10, 0x11, 0x18, + 0x21, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x16, 0x72, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x18, 0x6c, 0x61, 0x73, - 0x74, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x66, 0x5f, 0x63, - 0x6e, 0x74, 0x5f, 0x75, 0x70, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x13, 0x6c, 0x61, 0x73, - 0x74, 0x41, 0x64, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x46, 0x43, 0x6e, 0x74, 0x55, 0x70, - 0x12, 0x69, 0x0a, 0x1e, 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x63, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x1b, - 0x72, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x4d, 0x61, 0x63, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x1a, 0x83, 0x02, 0x0a, 0x0b, - 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x51, 0x0a, 0x11, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x4c, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x64, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3c, - 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, - 0x02, 0x10, 0x01, 0x52, 0x07, 0x72, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2f, 0x0a, 0x07, - 0x63, 0x66, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, - 0x46, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x06, 0x63, 0x66, 0x4c, 0x69, 0x73, 0x74, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, - 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, - 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x4a, 0x04, 0x08, 0x0a, 0x10, - 0x0b, 0x1a, 0xd1, 0x07, 0x0a, 0x0a, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, - 0x12, 0x23, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x10, 0x11, 0x18, 0x21, 0x52, 0x07, 0x70, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x48, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x39, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, - 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x04, 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, 0xed, 0x02, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0c, 0x42, 0xd1, 0x02, 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, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, - 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x34, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, - 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, - 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, - 0x72, 0x12, 0xe7, 0x02, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0c, 0x42, 0xcf, 0x02, 0x92, 0x41, 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, - 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, - 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x39, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x73, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, + 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x04, 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, 0xed, 0x02, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xd1, 0x02, 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, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0xf2, - 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, - 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, - 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, - 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, - 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, - 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, 0x74, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x52, 0x05, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0xf9, 0x07, 0x0a, 0x0d, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x70, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x57, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 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, 0x52, 0x0a, - 0x0b, 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x6c, - 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, - 0x18, 0x06, 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, 0x35, - 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x07, 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, 0x3a, 0x0a, 0x14, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x12, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x1a, 0x53, 0x0a, 0x0a, 0x54, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, - 0x3f, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x4a, 0x04, 0x08, 0x02, 0x10, 0x0a, 0x1a, 0xe0, 0x03, 0x0a, 0x0a, 0x52, 0x78, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4d, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, - 0x72, 0x73, 0x73, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x52, 0x73, 0x73, 0x69, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x6e, 0x72, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x6a, 0x0a, 0x18, 0x64, 0x6f, 0x77, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x6f, 0x77, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, - 0x69, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x16, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x75, 0x70, 0x6c, - 0x69, 0x6e, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x6b, 0x0a, 0x0d, 0x70, 0x61, 0x63, 0x6b, - 0x65, 0x74, 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x46, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, - 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x1a, 0x1c, 0x0a, 0x14, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, - 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, - 0x01, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, - 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x4a, 0x04, 0x08, 0x10, 0x10, - 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, 0x4a, 0x04, 0x08, - 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x63, 0x10, 0x64, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, - 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0a, 0x10, - 0x0b, 0x1a, 0x97, 0x04, 0x0a, 0x0f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, - 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x69, 0x64, 0x73, 0x18, 0x06, 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, 0x1a, 0xee, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x54, 0x0a, 0x05, 0x6d, 0x5f, 0x68, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x6f, - 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x48, 0x44, 0x52, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6d, 0x48, 0x64, 0x72, 0x12, 0x5c, 0x0a, 0x0b, 0x6d, 0x61, - 0x63, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x3b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0a, 0x6d, 0x61, - 0x63, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x44, 0x0a, 0x04, 0x4d, 0x48, 0x44, 0x52, - 0x12, 0x36, 0x0a, 0x06, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x4d, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x05, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0x5d, - 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x06, - 0x66, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a, - 0x0a, 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x46, 0x43, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, - 0x02, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, - 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, - 0x04, 0x08, 0x03, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x1a, 0xc9, 0x01, 0x0a, 0x0d, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x56, 0x0a, - 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, - 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x61, 0x78, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x08, 0xf2, - 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x64, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x06, 0x72, 0x61, 0x6e, - 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, - 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x06, 0x72, 0x61, 0x6e, - 0x67, 0x65, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x72, 0x0a, - 0x1b, 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, - 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3d, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x6b, 0x2f, 0x76, 0x33, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, + 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, + 0x4e, 0x65, 0x77, 0x34, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, + 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, + 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, + 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, 0xe7, 0x02, 0x0a, 0x06, 0x6e, 0x65, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xcf, 0x02, 0x92, 0x41, 0x17, 0x4a, 0x08, 0x22, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, 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, 0x33, 0x42, + 0x79, 0x74, 0x65, 0x73, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, + 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x33, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, + 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, + 0x78, 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x05, 0x6e, 0x65, 0x74, 0x49, 0x64, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0xf3, 0x08, 0x0a, 0x0d, 0x55, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x3b, 0x0a, 0x07, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, - 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x1b, - 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1a, 0xfa, 0x42, 0x17, 0x72, - 0x15, 0x32, 0x13, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, - 0x31, 0x2c, 0x33, 0x32, 0x7d, 0x24, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x39, 0x0a, - 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x5f, 0x74, 0x6f, 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, 0x07, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x6f, 0x3a, - 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xd7, 0x21, 0x0a, 0x09, 0x45, 0x6e, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x03, 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, 0x10, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, 0x01, 0x52, 0x03, 0x69, 0x64, - 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, - 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x18, 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x72, 0x03, 0x18, 0xd0, 0x0f, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x80, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 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, 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, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07, 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, 0x35, 0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x10, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0xc5, 0x01, 0x0a, - 0x16, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, - 0xfa, 0x42, 0x8a, 0x01, 0x72, 0x87, 0x01, 0x32, 0x84, 0x01, 0x5e, 0x28, 0x3f, 0x3a, 0x28, 0x3f, - 0x3a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x61, 0x2d, - 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, - 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, - 0x5d, 0x29, 0x5c, 0x2e, 0x29, 0x2a, 0x28, 0x3f, 0x3a, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, - 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, - 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x41, - 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x28, 0x3f, 0x3a, 0x3a, 0x5b, 0x30, - 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x14, - 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x18, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x6b, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x18, 0x2f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x10, - 0x52, 0x15, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, - 0x65, 0x6b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0xcd, 0x01, 0x0a, 0x1a, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, 0xfa, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x57, 0x0a, 0x08, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 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, 0x52, 0x0a, 0x0b, 0x72, 0x78, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x72, 0x78, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, + 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x06, 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, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07, 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, 0x3a, 0x0a, 0x14, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, + 0xff, 0x01, 0x52, 0x12, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x53, 0x0a, 0x0a, 0x54, 0x78, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3f, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x0a, 0x1a, 0xda, 0x04, 0x0a, 0x0a, + 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4d, 0x0a, 0x0b, 0x67, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x67, + 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x73, 0x73, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, + 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x73, 0x73, 0x69, 0x12, 0x10, 0x0a, 0x03, + 0x73, 0x6e, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x6a, + 0x0a, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, + 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, + 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, + 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x6b, 0x0a, + 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x12, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x46, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x78, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, + 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0c, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x12, 0x55, 0x0a, 0x05, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x52, 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x05, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x1a, 0x1c, 0x0a, 0x14, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, + 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x0b, 0x1a, + 0x15, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x4a, 0x04, 0x08, 0x01, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0a, + 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x0c, 0x10, 0x0d, 0x4a, 0x04, 0x08, 0x0d, 0x10, 0x0e, 0x4a, 0x04, + 0x08, 0x10, 0x10, 0x11, 0x4a, 0x04, 0x08, 0x11, 0x10, 0x12, 0x4a, 0x04, 0x08, 0x13, 0x10, 0x14, + 0x4a, 0x04, 0x08, 0x14, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x15, 0x10, 0x16, 0x4a, 0x04, 0x08, 0x16, + 0x10, 0x17, 0x4a, 0x04, 0x08, 0x63, 0x10, 0x64, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, + 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, + 0x1a, 0x97, 0x04, 0x0a, 0x0f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x73, 0x18, 0x06, 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, 0x1a, 0xee, 0x02, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x54, 0x0a, 0x05, 0x6d, 0x5f, 0x68, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x48, 0x44, 0x52, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x04, 0x6d, 0x48, 0x64, 0x72, 0x12, 0x5c, 0x0a, 0x0b, 0x6d, 0x61, 0x63, + 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, + 0x6b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x0a, 0x6d, 0x61, 0x63, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x1a, 0x44, 0x0a, 0x04, 0x4d, 0x48, 0x44, 0x52, 0x12, + 0x36, 0x0a, 0x06, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x05, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x1a, 0x5d, 0x0a, + 0x0a, 0x4d, 0x41, 0x43, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1f, 0x0a, 0x06, 0x66, + 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x05, 0x66, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1c, 0x0a, 0x0a, + 0x66, 0x75, 0x6c, 0x6c, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x46, 0x43, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, + 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x02, + 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, + 0x08, 0x03, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x1a, 0xc9, 0x01, 0x0a, 0x0d, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x56, 0x0a, 0x13, + 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x61, 0x74, 0x61, + 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x08, 0xf2, 0xaa, + 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x64, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, + 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x06, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, 0x61, 0x6e, 0x67, 0x65, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, 0x08, 0x01, 0x52, 0x06, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x1a, 0x72, 0x0a, 0x1b, + 0x52, 0x65, 0x6a, 0x65, 0x63, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, + 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3d, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, + 0x43, 0x53, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x52, + 0x61, 0x6e, 0x67, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xcb, 0x01, 0x0a, 0x1b, 0x45, + 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1a, 0xfa, 0x42, 0x17, 0x72, 0x15, + 0x32, 0x13, 0x5e, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, + 0x2c, 0x33, 0x32, 0x7d, 0x24, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x39, 0x0a, 0x0a, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x12, 0x35, 0x0a, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x5f, 0x74, 0x6f, 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, 0x07, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x54, 0x6f, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xd7, 0x21, 0x0a, 0x09, 0x45, 0x6e, 0x64, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x03, 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, 0x10, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x28, 0x01, 0x52, 0x03, 0x69, 0x64, 0x73, + 0x12, 0x43, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x43, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 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, 0x42, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x00, 0x10, 0x00, 0x52, + 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, + 0x32, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0x18, 0xd0, 0x0f, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x80, 0x01, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 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, 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, 0x12, 0x4c, 0x0a, 0x0b, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07, 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, 0x35, 0x0a, 0x12, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x12, 0xc5, 0x01, 0x0a, 0x16, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, 0xfa, + 0x42, 0x8a, 0x01, 0x72, 0x87, 0x01, 0x32, 0x84, 0x01, 0x5e, 0x28, 0x3f, 0x3a, 0x28, 0x3f, 0x3a, + 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x61, 0x2d, 0x7a, + 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, + 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, + 0x29, 0x5c, 0x2e, 0x29, 0x2a, 0x28, 0x3f, 0x3a, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, + 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, + 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x41, 0x2d, + 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x28, 0x3f, 0x3a, 0x3a, 0x5b, 0x30, 0x2d, + 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x14, 0x6e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x41, 0x0a, 0x18, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x6b, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, + 0x2f, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x10, 0x52, + 0x15, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, + 0x6b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0xcd, 0x01, 0x0a, 0x1a, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, 0xfa, 0x42, + 0x8a, 0x01, 0x72, 0x87, 0x01, 0x32, 0x84, 0x01, 0x5e, 0x28, 0x3f, 0x3a, 0x28, 0x3f, 0x3a, 0x5b, + 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x61, 0x2d, 0x7a, 0x41, + 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, + 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x29, + 0x5c, 0x2e, 0x29, 0x2a, 0x28, 0x3f, 0x3a, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, + 0x39, 0x5d, 0x7c, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x41, + 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x41, 0x2d, 0x5a, + 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x28, 0x3f, 0x3a, 0x3a, 0x5b, 0x30, 0x2d, 0x39, + 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x18, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x49, 0x0a, 0x1c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x6b, + 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x30, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0x18, 0x80, 0x10, 0x52, 0x19, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x6b, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x12, 0x3b, 0x0a, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, 0xbf, + 0x01, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, 0xfa, 0x42, 0x8a, 0x01, 0x72, 0x87, 0x01, 0x32, 0x84, 0x01, 0x5e, 0x28, 0x3f, 0x3a, 0x28, 0x3f, 0x3a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, @@ -5150,448 +5852,427 @@ var file_ttn_lorawan_v3_end_device_proto_rawDesc = []byte{ 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x28, 0x3f, 0x3a, 0x3a, 0x5b, 0x30, 0x2d, - 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x18, 0x61, - 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x49, 0x0a, 0x1c, 0x61, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x6b, 0x65, - 0x6b, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x30, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x10, 0x52, 0x19, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4b, 0x65, 0x6b, 0x4c, 0x61, 0x62, - 0x65, 0x6c, 0x12, 0x3b, 0x0a, 0x15, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x31, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, 0x13, 0x61, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x49, 0x64, 0x12, - 0xbf, 0x01, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x42, 0x8e, 0x01, - 0xfa, 0x42, 0x8a, 0x01, 0x72, 0x87, 0x01, 0x32, 0x84, 0x01, 0x5e, 0x28, 0x3f, 0x3a, 0x28, 0x3f, - 0x3a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x61, 0x2d, - 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5d, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, - 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, - 0x5d, 0x29, 0x5c, 0x2e, 0x29, 0x2a, 0x28, 0x3f, 0x3a, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, - 0x30, 0x2d, 0x39, 0x5d, 0x7c, 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, - 0x5b, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5c, 0x2d, 0x5d, 0x2a, 0x5b, 0x41, - 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x29, 0x28, 0x3f, 0x3a, 0x3a, 0x5b, 0x30, - 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x11, - 0x6a, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x12, 0x74, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 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, 0x2e, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x2c, - 0xfa, 0x42, 0x29, 0x9a, 0x01, 0x26, 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, 0x52, 0x09, 0x6c, 0x6f, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, - 0x72, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x52, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, - 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, - 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, - 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, - 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x4d, - 0x0a, 0x0f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x54, 0x0a, - 0x13, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x11, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x5f, 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, - 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, - 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x0c, 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, - 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x13, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6a, - 0x6f, 0x69, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x74, - 0x73, 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x15, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x4e, - 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, - 0x79, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x4b, 0x65, - 0x79, 0x73, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0xe7, 0x02, 0x0a, - 0x06, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xcf, 0x02, - 0x92, 0x41, 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, - 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, - 0x03, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, + 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x35, 0x7d, 0x29, 0x3f, 0x24, 0x7c, 0x5e, 0x24, 0x52, 0x11, 0x6a, + 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x74, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0c, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x28, 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, 0x2e, 0x4c, + 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x2c, 0xfa, + 0x42, 0x29, 0x9a, 0x01, 0x26, 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, 0x52, 0x09, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x52, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x0d, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, + 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, + 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x4d, 0x0a, + 0x0f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x54, 0x0a, 0x13, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x5f, 0x70, 0x68, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x48, 0x59, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x11, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x50, 0x68, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x11, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, + 0x70, 0x6c, 0x61, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x50, 0x6c, 0x61, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, + 0x6d, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x0a, 0x0d, + 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6a, 0x6f, + 0x69, 0x6e, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, + 0x5f, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x72, 0x65, 0x73, 0x65, 0x74, 0x73, 0x4a, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x6b, 0x65, 0x79, + 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, + 0x73, 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x12, 0xe7, 0x02, 0x0a, 0x06, + 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xcf, 0x02, 0x92, + 0x41, 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, + 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, + 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, 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, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, - 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, - 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, - 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, - 0x4e, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, - 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, - 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, - 0x05, 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x53, 0x65, - 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, - 0x11, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x70, 0x6b, 0x67, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, + 0x68, 0x61, 0x6c, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, + 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, + 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x2e, 0x4e, 0x65, 0x77, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, + 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, + 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x05, + 0x6e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x3e, 0x0a, 0x0c, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x74, + 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, + 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x53, 0x65, 0x74, + 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x09, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x52, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x63, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, - 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x76, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x26, - 0x0a, 0x0f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, - 0x73, 0x18, 0x1d, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x64, 0x44, 0x65, 0x76, - 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6a, - 0x6f, 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, - 0x0d, 0x6c, 0x61, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, - 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x6a, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, - 0x30, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x6a, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x30, 0x12, 0x25, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x6a, - 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x31, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, - 0x6c, 0x61, 0x73, 0x74, 0x52, 0x6a, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x31, 0x12, 0x58, 0x0a, 0x1b, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, - 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x21, 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, 0x17, 0x6c, - 0x61, 0x73, 0x74, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x63, 0x65, - 0x69, 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x6f, 0x77, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x0e, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0xf2, 0xaa, 0x19, 0x02, 0x10, 0x00, 0x52, 0x0a, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x5b, 0x0a, 0x12, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x70, - 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0f, 0xfa, 0x42, - 0x0c, 0x0a, 0x0a, 0x1d, 0x00, 0x00, 0x80, 0x3f, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x52, 0x11, 0x62, - 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, - 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x61, 0x72, - 0x67, 0x69, 0x6e, 0x18, 0x24, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, - 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x1c, 0x71, 0x75, 0x65, - 0x75, 0x65, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, - 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x28, 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, 0x1a, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, - 0x12, 0x48, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x18, 0x29, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x2a, 0xfa, 0x42, 0x27, 0x72, 0x25, 0x18, 0x24, 0x32, 0x21, 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, 0x7c, 0x5e, 0x24, 0x52, 0x0d, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x44, 0x0a, - 0x11, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x2b, 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, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x73, 0x74, - 0x18, 0x2d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x73, - 0x74, 0x12, 0x67, 0x0a, 0x19, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x2e, - 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, 0x41, - 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, - 0x65, 0x52, 0x17, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x18, 0x33, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x61, 0x79, - 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x12, 0x5b, 0x0a, 0x1c, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, + 0x74, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x44, 0x0a, 0x11, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x52, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x63, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x0f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0e, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x5f, + 0x64, 0x65, 0x76, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x44, 0x65, 0x76, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x26, 0x0a, + 0x0f, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x73, + 0x18, 0x1d, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x0d, 0x75, 0x73, 0x65, 0x64, 0x44, 0x65, 0x76, 0x4e, + 0x6f, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6a, 0x6f, + 0x69, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, + 0x6c, 0x61, 0x73, 0x74, 0x4a, 0x6f, 0x69, 0x6e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, + 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x6a, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x30, + 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x52, 0x6a, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x30, 0x12, 0x25, 0x0a, 0x0f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x72, 0x6a, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x31, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6c, + 0x61, 0x73, 0x74, 0x52, 0x6a, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x31, 0x12, 0x58, 0x0a, 0x1b, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x5f, 0x72, + 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x19, 0x73, 0x6b, - 0x69, 0x70, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x35, 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, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, - 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x18, 0x36, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x17, 0x6c, 0x61, + 0x73, 0x74, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x64, 0x41, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x22, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x6f, 0x77, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x42, 0x0e, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0xf2, 0xaa, 0x19, 0x02, 0x10, 0x00, 0x52, 0x0a, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x5b, 0x0a, 0x12, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x5f, 0x70, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x0f, 0xfa, 0x42, 0x0c, + 0x0a, 0x0a, 0x1d, 0x00, 0x00, 0x80, 0x3f, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x52, 0x11, 0x62, 0x61, + 0x74, 0x74, 0x65, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x12, + 0x27, 0x0a, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x61, 0x72, 0x67, + 0x69, 0x6e, 0x18, 0x24, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, + 0x6e, 0x6b, 0x4d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x65, 0x0a, 0x1c, 0x71, 0x75, 0x65, 0x75, + 0x65, 0x64, 0x5f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, + 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x28, 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, 0x1a, 0x71, 0x75, 0x65, 0x75, 0x65, 0x64, 0x41, 0x70, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, + 0x48, 0x0a, 0x0a, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x18, 0x29, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0a, 0x66, + 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x73, 0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x2a, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x2a, 0xfa, 0x42, 0x27, 0x72, 0x25, 0x18, 0x24, 0x32, 0x21, 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, 0x7c, 0x5e, 0x24, 0x52, 0x0d, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x11, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x2b, 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, 0x10, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x73, 0x74, 0x18, + 0x2d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x73, 0x74, + 0x12, 0x67, 0x0a, 0x19, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x2e, 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, 0x41, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, + 0x52, 0x17, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x18, 0x33, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x12, 0x5b, 0x0a, 0x1c, 0x73, 0x6b, 0x69, + 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x34, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x19, 0x73, 0x6b, 0x69, + 0x70, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x3d, 0x0a, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x35, 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, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, - 0x65, 0x6e, 0x41, 0x74, 0x12, 0x4f, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0xfa, 0x42, 0x27, - 0x72, 0x25, 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, 0xd0, 0x01, 0x01, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x69, 0x0a, 0x19, 0x6c, 0x6f, 0x72, 0x61, 0x5f, 0x61, 0x6c, - 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, - 0x64, 0x73, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x52, 0x61, 0x41, 0x6c, - 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x16, 0x6c, 0x6f, 0x72, 0x61, 0x41, 0x6c, - 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 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, 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, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x26, 0x4a, 0x04, 0x08, 0x26, 0x10, 0x27, 0x4a, 0x04, 0x08, - 0x27, 0x10, 0x28, 0x22, 0x48, 0x0a, 0x0a, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x3a, 0x0a, 0x0b, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 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, 0x52, 0x0a, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0xf2, 0x01, - 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 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, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, + 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x18, 0x36, 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, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, + 0x6e, 0x41, 0x74, 0x12, 0x4f, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x18, 0x37, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0xfa, 0x42, 0x27, 0x72, + 0x25, 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, 0xd0, 0x01, 0x01, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x12, 0x69, 0x0a, 0x19, 0x6c, 0x6f, 0x72, 0x61, 0x5f, 0x61, 0x6c, 0x6c, + 0x69, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x69, 0x64, + 0x73, 0x18, 0x38, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x52, 0x61, 0x41, 0x6c, 0x6c, + 0x69, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x16, 0x6c, 0x6f, 0x72, 0x61, 0x41, 0x6c, 0x6c, + 0x69, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 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, 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, + 0x4a, 0x04, 0x08, 0x25, 0x10, 0x26, 0x4a, 0x04, 0x08, 0x26, 0x10, 0x27, 0x4a, 0x04, 0x08, 0x27, + 0x10, 0x28, 0x22, 0x48, 0x0a, 0x0a, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x3a, 0x0a, 0x0b, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 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, + 0x52, 0x0a, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0xf2, 0x01, 0x0a, + 0x0d, 0x44, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 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, 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, 0x16, 0x0a, 0x06, 0x6c, 0x65, - 0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x22, 0x5c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, - 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x19, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x22, 0x97, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, + 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, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x22, 0x5c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, - 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, - 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xa8, 0x02, 0x0a, 0x23, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x65, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x99, 0x01, 0x0a, 0x17, 0x45, 0x6e, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x03, 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, 0x03, 0x69, 0x64, 0x73, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, - 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x53, - 0x65, 0x65, 0x6e, 0x41, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, - 0x44, 0x65, 0x76, 0x69, 0x63, 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, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xcb, - 0x03, 0x0a, 0x25, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x55, 0x49, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xd0, 0x01, 0x0a, 0x08, 0x6a, 0x6f, 0x69, - 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, 0x92, 0x41, - 0x21, 0x4a, 0x12, 0x22, 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, 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, 0x08, 0x70, 0x01, 0xea, 0xaa, 0x19, 0x82, 0x01, - 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, + 0x97, 0x01, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0a, 0x65, 0x6e, + 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, + 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, + 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xa8, 0x02, 0x0a, 0x23, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x65, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x45, + 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x1a, 0x99, 0x01, 0x0a, 0x17, 0x45, 0x6e, 0x64, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x03, 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, 0x03, 0x69, 0x64, 0x73, 0x12, 0x3c, 0x0a, 0x0c, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, + 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, + 0x65, 0x6e, 0x41, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 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, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, + 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xcb, 0x03, + 0x0a, 0x25, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x46, 0x6f, 0x72, 0x45, 0x55, 0x49, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xd0, 0x01, 0x0a, 0x08, 0x6a, 0x6f, 0x69, 0x6e, + 0x5f, 0x65, 0x75, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, 0x92, 0x41, 0x21, + 0x4a, 0x12, 0x22, 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, 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, 0x08, 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, 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, + 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x38, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x07, 0x6a, 0x6f, 0x69, 0x6e, 0x45, 0x75, 0x69, 0x12, 0xce, 0x01, 0x0a, 0x07, 0x64, + 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, 0x92, + 0x41, 0x21, 0x4a, 0x12, 0x22, 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, 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, 0x08, 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, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x38, 0x42, 0x79, 0x74, - 0x65, 0x73, 0x52, 0x07, 0x6a, 0x6f, 0x69, 0x6e, 0x45, 0x75, 0x69, 0x12, 0xce, 0x01, 0x0a, 0x07, - 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, - 0x92, 0x41, 0x21, 0x4a, 0x12, 0x22, 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, - 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, 0x08, 0x70, 0x01, 0xea, 0xaa, 0x19, - 0x82, 0x01, 0x0a, 0x3f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, + 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, 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, 0x38, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x97, 0x03, 0x0a, - 0x15, 0x4c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x70, 0x65, 0x73, 0x2e, 0x55, 0x6e, 0x6d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x38, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x52, 0x06, 0x64, 0x65, 0x76, 0x45, 0x75, 0x69, 0x22, 0x97, 0x03, 0x0a, 0x15, + 0x4c, 0x69, 0x73, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4f, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, + 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, + 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, + 0x6b, 0x12, 0xbd, 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0xa2, 0x01, 0x72, 0x9f, 0x01, 0x52, 0x00, 0x52, 0x09, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x09, + 0x2d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x07, 0x64, 0x65, 0x76, 0x5f, 0x65, + 0x75, 0x69, 0x52, 0x08, 0x2d, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, + 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0c, 0x6c, + 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x0d, 0x2d, 0x6c, 0x61, + 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x45, 0x6e, 0x64, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, + 0x0a, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 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, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, + 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xae, 0x01, 0x0a, + 0x1b, 0x52, 0x65, 0x73, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 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, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, + 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xbc, 0x01, + 0x0a, 0x11, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, - 0x73, 0x6b, 0x12, 0xbd, 0x01, 0x0a, 0x05, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0xa6, 0x01, 0xfa, 0x42, 0xa2, 0x01, 0x72, 0x9f, 0x01, 0x52, 0x00, 0x52, 0x09, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x0a, 0x2d, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x52, 0x08, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, - 0x09, 0x2d, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x07, 0x64, 0x65, 0x76, 0x5f, - 0x65, 0x75, 0x69, 0x52, 0x08, 0x2d, 0x64, 0x65, 0x76, 0x5f, 0x65, 0x75, 0x69, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x52, 0x05, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x52, 0x0b, 0x2d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x52, 0x0c, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x0d, 0x2d, 0x6c, - 0x61, 0x73, 0x74, 0x5f, 0x73, 0x65, 0x65, 0x6e, 0x5f, 0x61, 0x74, 0x52, 0x05, 0x6f, 0x72, 0x64, - 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xe8, 0x07, 0x52, 0x05, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, 0x22, 0x94, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x45, 0x6e, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, - 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x19, 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, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, - 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xae, 0x01, - 0x0a, 0x1b, 0x52, 0x65, 0x73, 0x65, 0x74, 0x41, 0x6e, 0x64, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, - 0x44, 0x65, 0x76, 0x69, 0x63, 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, + 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x64, + 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0xb8, 0x01, 0x0a, + 0x17, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x64, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x2b, 0xfa, 0x42, 0x28, 0x92, + 0x01, 0x25, 0x10, 0x64, 0x18, 0x01, 0x22, 0x1f, 0x72, 0x1d, 0x32, 0x1b, 0x5e, 0x28, 0x3f, 0x3a, + 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x31, 0x36, 0x7d, + 0x29, 0x7b, 0x31, 0x2c, 0x32, 0x7d, 0x24, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, 0x74, + 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x18, 0x45, 0x6e, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x73, 0x12, 0x7d, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 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, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0xbc, - 0x01, 0x0a, 0x11, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x12, 0x42, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 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, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x65, - 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, - 0x61, 0x73, 0x6b, 0x12, 0x28, 0x0a, 0x0b, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, - 0x64, 0x52, 0x0a, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x22, 0xb8, 0x01, - 0x0a, 0x17, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x64, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x54, 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x42, 0x2b, 0xfa, 0x42, 0x28, - 0x92, 0x01, 0x25, 0x10, 0x64, 0x18, 0x01, 0x22, 0x1f, 0x72, 0x1d, 0x32, 0x1b, 0x5e, 0x28, 0x3f, - 0x3a, 0x5c, 0x2e, 0x5b, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x31, 0x2c, 0x31, 0x36, - 0x7d, 0x29, 0x7b, 0x31, 0x2c, 0x32, 0x7d, 0x24, 0x52, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x45, 0x78, - 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xfe, 0x01, 0x0a, 0x18, 0x45, 0x6e, 0x64, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x73, 0x12, 0x7d, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x2e, + 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x2c, 0xfa, 0x42, + 0x29, 0x9a, 0x01, 0x26, 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, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x73, 0x1a, 0x63, 0x0a, 0x0c, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 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, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdd, 0x01, 0x0a, 0x1f, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x09, + 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x27, 0xfa, 0x42, 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, 0x52, 0x08, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x60, 0x0a, 0x16, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, + 0x18, 0x03, 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, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, - 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x2c, 0xfa, - 0x42, 0x29, 0x9a, 0x01, 0x26, 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, 0x52, 0x07, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x73, 0x1a, 0x63, 0x0a, 0x0c, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 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, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 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, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xdd, 0x01, 0x0a, 0x1f, 0x43, 0x6f, - 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, - 0x09, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x27, 0xfa, 0x42, 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, 0x52, 0x08, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x60, 0x0a, 0x16, 0x65, 0x6e, 0x64, 0x5f, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x03, 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, 0x13, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0xca, 0x01, 0x0a, 0x1c, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, - 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x4f, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, 0x2d, 0x92, 0x01, - 0x2a, 0x08, 0x01, 0x10, 0x14, 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, 0x52, 0x09, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0xa8, 0x02, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x47, 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, - 0x4f, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, 0x2d, 0x92, 0x01, 0x2a, 0x08, 0x01, 0x10, 0x14, 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, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, - 0x12, 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, - 0x52, 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x4a, 0x04, 0x08, 0x04, 0x10, - 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x52, 0x05, 0x6f, - 0x72, 0x64, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x04, 0x70, 0x61, 0x67, - 0x65, 0x2a, 0x55, 0x0a, 0x0a, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x11, 0x0a, 0x0d, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x42, 0x41, 0x54, 0x54, - 0x45, 0x52, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x45, - 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x18, - 0x01, 0x2a, 0x05, 0x50, 0x4f, 0x57, 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, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x52, 0x13, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x22, 0xca, 0x01, 0x0a, 0x1c, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x64, 0x73, 0x12, 0x4f, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, 0x2d, 0x92, 0x01, 0x2a, + 0x08, 0x01, 0x10, 0x14, 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, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x64, 0x73, 0x22, 0xa8, 0x02, 0x0a, 0x19, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, + 0x65, 0x74, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x59, 0x0a, 0x0f, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 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, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73, 0x12, 0x4f, + 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, 0x2d, 0x92, 0x01, 0x2a, 0x08, 0x01, 0x10, 0x14, 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, 0x52, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x73, 0x12, + 0x39, 0x0a, 0x0a, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 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, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, + 0x09, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, + 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x52, 0x05, 0x6f, 0x72, + 0x64, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x04, 0x70, 0x61, 0x67, 0x65, + 0x2a, 0x55, 0x0a, 0x0a, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, + 0x0a, 0x0d, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x42, 0x41, 0x54, 0x54, 0x45, + 0x52, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x4f, 0x57, 0x45, 0x52, 0x5f, 0x45, 0x58, + 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x18, 0x01, + 0x2a, 0x05, 0x50, 0x4f, 0x57, 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 ( @@ -5607,272 +6288,308 @@ func file_ttn_lorawan_v3_end_device_proto_rawDescGZIP() []byte { } var file_ttn_lorawan_v3_end_device_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_ttn_lorawan_v3_end_device_proto_msgTypes = make([]protoimpl.MessageInfo, 49) +var file_ttn_lorawan_v3_end_device_proto_msgTypes = make([]protoimpl.MessageInfo, 55) var file_ttn_lorawan_v3_end_device_proto_goTypes = []interface{}{ (PowerState)(0), // 0: ttn.lorawan.v3.PowerState (*Session)(nil), // 1: ttn.lorawan.v3.Session (*BoolValue)(nil), // 2: ttn.lorawan.v3.BoolValue - (*MACParameters)(nil), // 3: ttn.lorawan.v3.MACParameters - (*EndDeviceVersion)(nil), // 4: ttn.lorawan.v3.EndDeviceVersion - (*ADRSettings)(nil), // 5: ttn.lorawan.v3.ADRSettings - (*MACSettings)(nil), // 6: ttn.lorawan.v3.MACSettings - (*MACState)(nil), // 7: ttn.lorawan.v3.MACState - (*EndDeviceAuthenticationCode)(nil), // 8: ttn.lorawan.v3.EndDeviceAuthenticationCode - (*EndDevice)(nil), // 9: ttn.lorawan.v3.EndDevice - (*EndDevices)(nil), // 10: ttn.lorawan.v3.EndDevices - (*DevAddrPrefix)(nil), // 11: ttn.lorawan.v3.DevAddrPrefix - (*CreateEndDeviceRequest)(nil), // 12: ttn.lorawan.v3.CreateEndDeviceRequest - (*UpdateEndDeviceRequest)(nil), // 13: ttn.lorawan.v3.UpdateEndDeviceRequest - (*BatchUpdateEndDeviceLastSeenRequest)(nil), // 14: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest - (*GetEndDeviceRequest)(nil), // 15: ttn.lorawan.v3.GetEndDeviceRequest - (*GetEndDeviceIdentifiersForEUIsRequest)(nil), // 16: ttn.lorawan.v3.GetEndDeviceIdentifiersForEUIsRequest - (*ListEndDevicesRequest)(nil), // 17: ttn.lorawan.v3.ListEndDevicesRequest - (*SetEndDeviceRequest)(nil), // 18: ttn.lorawan.v3.SetEndDeviceRequest - (*ResetAndGetEndDeviceRequest)(nil), // 19: ttn.lorawan.v3.ResetAndGetEndDeviceRequest - (*EndDeviceTemplate)(nil), // 20: ttn.lorawan.v3.EndDeviceTemplate - (*EndDeviceTemplateFormat)(nil), // 21: ttn.lorawan.v3.EndDeviceTemplateFormat - (*EndDeviceTemplateFormats)(nil), // 22: ttn.lorawan.v3.EndDeviceTemplateFormats - (*ConvertEndDeviceTemplateRequest)(nil), // 23: ttn.lorawan.v3.ConvertEndDeviceTemplateRequest - (*BatchDeleteEndDevicesRequest)(nil), // 24: ttn.lorawan.v3.BatchDeleteEndDevicesRequest - (*BatchGetEndDevicesRequest)(nil), // 25: ttn.lorawan.v3.BatchGetEndDevicesRequest - (*MACParameters_Channel)(nil), // 26: ttn.lorawan.v3.MACParameters.Channel - (*ADRSettings_StaticMode)(nil), // 27: ttn.lorawan.v3.ADRSettings.StaticMode - (*ADRSettings_DynamicMode)(nil), // 28: ttn.lorawan.v3.ADRSettings.DynamicMode - (*ADRSettings_DisabledMode)(nil), // 29: ttn.lorawan.v3.ADRSettings.DisabledMode - (*ADRSettings_DynamicMode_ChannelSteeringSettings)(nil), // 30: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings - (*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode)(nil), // 31: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.LoRaNarrowMode - (*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode)(nil), // 32: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.DisabledMode - (*MACState_JoinRequest)(nil), // 33: ttn.lorawan.v3.MACState.JoinRequest - (*MACState_JoinAccept)(nil), // 34: ttn.lorawan.v3.MACState.JoinAccept - (*MACState_UplinkMessage)(nil), // 35: ttn.lorawan.v3.MACState.UplinkMessage - (*MACState_DownlinkMessage)(nil), // 36: ttn.lorawan.v3.MACState.DownlinkMessage - (*MACState_DataRateRange)(nil), // 37: ttn.lorawan.v3.MACState.DataRateRange - (*MACState_DataRateRanges)(nil), // 38: ttn.lorawan.v3.MACState.DataRateRanges - nil, // 39: ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry - (*MACState_UplinkMessage_TxSettings)(nil), // 40: ttn.lorawan.v3.MACState.UplinkMessage.TxSettings - (*MACState_UplinkMessage_RxMetadata)(nil), // 41: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata - (*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata)(nil), // 42: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata - (*MACState_DownlinkMessage_Message)(nil), // 43: ttn.lorawan.v3.MACState.DownlinkMessage.Message - (*MACState_DownlinkMessage_Message_MHDR)(nil), // 44: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR - (*MACState_DownlinkMessage_Message_MACPayload)(nil), // 45: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MACPayload - nil, // 46: ttn.lorawan.v3.EndDevice.AttributesEntry - nil, // 47: ttn.lorawan.v3.EndDevice.LocationsEntry - (*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate)(nil), // 48: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate - nil, // 49: ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry - (*SessionKeys)(nil), // 50: ttn.lorawan.v3.SessionKeys - (*timestamppb.Timestamp)(nil), // 51: google.protobuf.Timestamp - (*ApplicationDownlink)(nil), // 52: ttn.lorawan.v3.ApplicationDownlink - (DataRateIndex)(0), // 53: ttn.lorawan.v3.DataRateIndex - (RxDelay)(0), // 54: ttn.lorawan.v3.RxDelay - (DataRateOffset)(0), // 55: ttn.lorawan.v3.DataRateOffset - (AggregatedDutyCycle)(0), // 56: ttn.lorawan.v3.AggregatedDutyCycle - (RejoinTimeExponent)(0), // 57: ttn.lorawan.v3.RejoinTimeExponent - (RejoinCountExponent)(0), // 58: ttn.lorawan.v3.RejoinCountExponent - (*ADRAckLimitExponentValue)(nil), // 59: ttn.lorawan.v3.ADRAckLimitExponentValue - (*ADRAckDelayExponentValue)(nil), // 60: ttn.lorawan.v3.ADRAckDelayExponentValue - (*DataRateIndexValue)(nil), // 61: ttn.lorawan.v3.DataRateIndexValue - (*EndDeviceVersionIdentifiers)(nil), // 62: ttn.lorawan.v3.EndDeviceVersionIdentifiers - (MACVersion)(0), // 63: ttn.lorawan.v3.MACVersion - (PHYVersion)(0), // 64: ttn.lorawan.v3.PHYVersion - (*MessagePayloadFormatters)(nil), // 65: ttn.lorawan.v3.MessagePayloadFormatters - (*durationpb.Duration)(nil), // 66: google.protobuf.Duration - (*PingSlotPeriodValue)(nil), // 67: ttn.lorawan.v3.PingSlotPeriodValue - (*ZeroableFrequencyValue)(nil), // 68: ttn.lorawan.v3.ZeroableFrequencyValue - (*RxDelayValue)(nil), // 69: ttn.lorawan.v3.RxDelayValue - (*DataRateOffsetValue)(nil), // 70: ttn.lorawan.v3.DataRateOffsetValue - (*FrequencyValue)(nil), // 71: ttn.lorawan.v3.FrequencyValue - (*AggregatedDutyCycleValue)(nil), // 72: ttn.lorawan.v3.AggregatedDutyCycleValue - (*wrapperspb.FloatValue)(nil), // 73: google.protobuf.FloatValue - (*wrapperspb.UInt32Value)(nil), // 74: google.protobuf.UInt32Value - (*DeviceEIRPValue)(nil), // 75: ttn.lorawan.v3.DeviceEIRPValue - (Class)(0), // 76: ttn.lorawan.v3.Class - (*MACCommand)(nil), // 77: ttn.lorawan.v3.MACCommand - (MACCommandIdentifier)(0), // 78: ttn.lorawan.v3.MACCommandIdentifier - (*EndDeviceIdentifiers)(nil), // 79: ttn.lorawan.v3.EndDeviceIdentifiers - (*Picture)(nil), // 80: ttn.lorawan.v3.Picture - (*RootKeys)(nil), // 81: ttn.lorawan.v3.RootKeys - (*structpb.Struct)(nil), // 82: google.protobuf.Struct - (*wrapperspb.BoolValue)(nil), // 83: google.protobuf.BoolValue - (*LoRaAllianceProfileIdentifiers)(nil), // 84: ttn.lorawan.v3.LoRaAllianceProfileIdentifiers - (*fieldmaskpb.FieldMask)(nil), // 85: google.protobuf.FieldMask - (*ApplicationIdentifiers)(nil), // 86: ttn.lorawan.v3.ApplicationIdentifiers - (*DLSettings)(nil), // 87: ttn.lorawan.v3.DLSettings - (*CFList)(nil), // 88: ttn.lorawan.v3.CFList - (*Message)(nil), // 89: ttn.lorawan.v3.Message - (*DataRate)(nil), // 90: ttn.lorawan.v3.DataRate - (*GatewayIdentifiers)(nil), // 91: ttn.lorawan.v3.GatewayIdentifiers - (DownlinkPathConstraint)(0), // 92: ttn.lorawan.v3.DownlinkPathConstraint - (MType)(0), // 93: ttn.lorawan.v3.MType - (*Location)(nil), // 94: ttn.lorawan.v3.Location + (*ServingRelayForwardingLimits)(nil), // 3: ttn.lorawan.v3.ServingRelayForwardingLimits + (*RelayUplinkForwardingRule)(nil), // 4: ttn.lorawan.v3.RelayUplinkForwardingRule + (*ServingRelayParameters)(nil), // 5: ttn.lorawan.v3.ServingRelayParameters + (*ServedRelayParameters)(nil), // 6: ttn.lorawan.v3.ServedRelayParameters + (*RelayParameters)(nil), // 7: ttn.lorawan.v3.RelayParameters + (*MACParameters)(nil), // 8: ttn.lorawan.v3.MACParameters + (*EndDeviceVersion)(nil), // 9: ttn.lorawan.v3.EndDeviceVersion + (*ADRSettings)(nil), // 10: ttn.lorawan.v3.ADRSettings + (*MACSettings)(nil), // 11: ttn.lorawan.v3.MACSettings + (*MACState)(nil), // 12: ttn.lorawan.v3.MACState + (*EndDeviceAuthenticationCode)(nil), // 13: ttn.lorawan.v3.EndDeviceAuthenticationCode + (*EndDevice)(nil), // 14: ttn.lorawan.v3.EndDevice + (*EndDevices)(nil), // 15: ttn.lorawan.v3.EndDevices + (*DevAddrPrefix)(nil), // 16: ttn.lorawan.v3.DevAddrPrefix + (*CreateEndDeviceRequest)(nil), // 17: ttn.lorawan.v3.CreateEndDeviceRequest + (*UpdateEndDeviceRequest)(nil), // 18: ttn.lorawan.v3.UpdateEndDeviceRequest + (*BatchUpdateEndDeviceLastSeenRequest)(nil), // 19: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest + (*GetEndDeviceRequest)(nil), // 20: ttn.lorawan.v3.GetEndDeviceRequest + (*GetEndDeviceIdentifiersForEUIsRequest)(nil), // 21: ttn.lorawan.v3.GetEndDeviceIdentifiersForEUIsRequest + (*ListEndDevicesRequest)(nil), // 22: ttn.lorawan.v3.ListEndDevicesRequest + (*SetEndDeviceRequest)(nil), // 23: ttn.lorawan.v3.SetEndDeviceRequest + (*ResetAndGetEndDeviceRequest)(nil), // 24: ttn.lorawan.v3.ResetAndGetEndDeviceRequest + (*EndDeviceTemplate)(nil), // 25: ttn.lorawan.v3.EndDeviceTemplate + (*EndDeviceTemplateFormat)(nil), // 26: ttn.lorawan.v3.EndDeviceTemplateFormat + (*EndDeviceTemplateFormats)(nil), // 27: ttn.lorawan.v3.EndDeviceTemplateFormats + (*ConvertEndDeviceTemplateRequest)(nil), // 28: ttn.lorawan.v3.ConvertEndDeviceTemplateRequest + (*BatchDeleteEndDevicesRequest)(nil), // 29: ttn.lorawan.v3.BatchDeleteEndDevicesRequest + (*BatchGetEndDevicesRequest)(nil), // 30: ttn.lorawan.v3.BatchGetEndDevicesRequest + (*MACParameters_Channel)(nil), // 31: ttn.lorawan.v3.MACParameters.Channel + (*ADRSettings_StaticMode)(nil), // 32: ttn.lorawan.v3.ADRSettings.StaticMode + (*ADRSettings_DynamicMode)(nil), // 33: ttn.lorawan.v3.ADRSettings.DynamicMode + (*ADRSettings_DisabledMode)(nil), // 34: ttn.lorawan.v3.ADRSettings.DisabledMode + (*ADRSettings_DynamicMode_ChannelSteeringSettings)(nil), // 35: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings + (*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode)(nil), // 36: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.LoRaNarrowMode + (*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode)(nil), // 37: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.DisabledMode + (*MACState_JoinRequest)(nil), // 38: ttn.lorawan.v3.MACState.JoinRequest + (*MACState_JoinAccept)(nil), // 39: ttn.lorawan.v3.MACState.JoinAccept + (*MACState_UplinkMessage)(nil), // 40: ttn.lorawan.v3.MACState.UplinkMessage + (*MACState_DownlinkMessage)(nil), // 41: ttn.lorawan.v3.MACState.DownlinkMessage + (*MACState_DataRateRange)(nil), // 42: ttn.lorawan.v3.MACState.DataRateRange + (*MACState_DataRateRanges)(nil), // 43: ttn.lorawan.v3.MACState.DataRateRanges + nil, // 44: ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry + (*MACState_UplinkMessage_TxSettings)(nil), // 45: ttn.lorawan.v3.MACState.UplinkMessage.TxSettings + (*MACState_UplinkMessage_RxMetadata)(nil), // 46: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata + (*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata)(nil), // 47: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata + (*MACState_UplinkMessage_RxMetadata_RelayMetadata)(nil), // 48: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.RelayMetadata + (*MACState_DownlinkMessage_Message)(nil), // 49: ttn.lorawan.v3.MACState.DownlinkMessage.Message + (*MACState_DownlinkMessage_Message_MHDR)(nil), // 50: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR + (*MACState_DownlinkMessage_Message_MACPayload)(nil), // 51: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MACPayload + nil, // 52: ttn.lorawan.v3.EndDevice.AttributesEntry + nil, // 53: ttn.lorawan.v3.EndDevice.LocationsEntry + (*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate)(nil), // 54: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate + nil, // 55: ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry + (*SessionKeys)(nil), // 56: ttn.lorawan.v3.SessionKeys + (*timestamppb.Timestamp)(nil), // 57: google.protobuf.Timestamp + (*ApplicationDownlink)(nil), // 58: ttn.lorawan.v3.ApplicationDownlink + (RelayResetLimitCounter)(0), // 59: ttn.lorawan.v3.RelayResetLimitCounter + (*RelayForwardLimits)(nil), // 60: ttn.lorawan.v3.RelayForwardLimits + (*RelayUplinkForwardLimits)(nil), // 61: ttn.lorawan.v3.RelayUplinkForwardLimits + (*RelaySecondChannel)(nil), // 62: ttn.lorawan.v3.RelaySecondChannel + (RelayCADPeriodicity)(0), // 63: ttn.lorawan.v3.RelayCADPeriodicity + (*RelayEndDeviceAlwaysMode)(nil), // 64: ttn.lorawan.v3.RelayEndDeviceAlwaysMode + (*RelayEndDeviceDynamicMode)(nil), // 65: ttn.lorawan.v3.RelayEndDeviceDynamicMode + (*RelayEndDeviceControlledMode)(nil), // 66: ttn.lorawan.v3.RelayEndDeviceControlledMode + (DataRateIndex)(0), // 67: ttn.lorawan.v3.DataRateIndex + (RxDelay)(0), // 68: ttn.lorawan.v3.RxDelay + (DataRateOffset)(0), // 69: ttn.lorawan.v3.DataRateOffset + (AggregatedDutyCycle)(0), // 70: ttn.lorawan.v3.AggregatedDutyCycle + (RejoinTimeExponent)(0), // 71: ttn.lorawan.v3.RejoinTimeExponent + (RejoinCountExponent)(0), // 72: ttn.lorawan.v3.RejoinCountExponent + (*ADRAckLimitExponentValue)(nil), // 73: ttn.lorawan.v3.ADRAckLimitExponentValue + (*ADRAckDelayExponentValue)(nil), // 74: ttn.lorawan.v3.ADRAckDelayExponentValue + (*DataRateIndexValue)(nil), // 75: ttn.lorawan.v3.DataRateIndexValue + (*EndDeviceVersionIdentifiers)(nil), // 76: ttn.lorawan.v3.EndDeviceVersionIdentifiers + (MACVersion)(0), // 77: ttn.lorawan.v3.MACVersion + (PHYVersion)(0), // 78: ttn.lorawan.v3.PHYVersion + (*MessagePayloadFormatters)(nil), // 79: ttn.lorawan.v3.MessagePayloadFormatters + (*durationpb.Duration)(nil), // 80: google.protobuf.Duration + (*PingSlotPeriodValue)(nil), // 81: ttn.lorawan.v3.PingSlotPeriodValue + (*ZeroableFrequencyValue)(nil), // 82: ttn.lorawan.v3.ZeroableFrequencyValue + (*RxDelayValue)(nil), // 83: ttn.lorawan.v3.RxDelayValue + (*DataRateOffsetValue)(nil), // 84: ttn.lorawan.v3.DataRateOffsetValue + (*FrequencyValue)(nil), // 85: ttn.lorawan.v3.FrequencyValue + (*AggregatedDutyCycleValue)(nil), // 86: ttn.lorawan.v3.AggregatedDutyCycleValue + (*wrapperspb.FloatValue)(nil), // 87: google.protobuf.FloatValue + (*wrapperspb.UInt32Value)(nil), // 88: google.protobuf.UInt32Value + (*DeviceEIRPValue)(nil), // 89: ttn.lorawan.v3.DeviceEIRPValue + (Class)(0), // 90: ttn.lorawan.v3.Class + (*MACCommand)(nil), // 91: ttn.lorawan.v3.MACCommand + (MACCommandIdentifier)(0), // 92: ttn.lorawan.v3.MACCommandIdentifier + (*RelayForwardDownlinkReq)(nil), // 93: ttn.lorawan.v3.RelayForwardDownlinkReq + (*EndDeviceIdentifiers)(nil), // 94: ttn.lorawan.v3.EndDeviceIdentifiers + (*Picture)(nil), // 95: ttn.lorawan.v3.Picture + (*RootKeys)(nil), // 96: ttn.lorawan.v3.RootKeys + (*structpb.Struct)(nil), // 97: google.protobuf.Struct + (*wrapperspb.BoolValue)(nil), // 98: google.protobuf.BoolValue + (*LoRaAllianceProfileIdentifiers)(nil), // 99: ttn.lorawan.v3.LoRaAllianceProfileIdentifiers + (*fieldmaskpb.FieldMask)(nil), // 100: google.protobuf.FieldMask + (*ApplicationIdentifiers)(nil), // 101: ttn.lorawan.v3.ApplicationIdentifiers + (*DLSettings)(nil), // 102: ttn.lorawan.v3.DLSettings + (*CFList)(nil), // 103: ttn.lorawan.v3.CFList + (*Message)(nil), // 104: ttn.lorawan.v3.Message + (*DataRate)(nil), // 105: ttn.lorawan.v3.DataRate + (*GatewayIdentifiers)(nil), // 106: ttn.lorawan.v3.GatewayIdentifiers + (DownlinkPathConstraint)(0), // 107: ttn.lorawan.v3.DownlinkPathConstraint + (MType)(0), // 108: ttn.lorawan.v3.MType + (*Location)(nil), // 109: ttn.lorawan.v3.Location } var file_ttn_lorawan_v3_end_device_proto_depIdxs = []int32{ - 50, // 0: ttn.lorawan.v3.Session.keys:type_name -> ttn.lorawan.v3.SessionKeys - 51, // 1: ttn.lorawan.v3.Session.started_at:type_name -> google.protobuf.Timestamp - 52, // 2: ttn.lorawan.v3.Session.queued_application_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 53, // 3: ttn.lorawan.v3.MACParameters.adr_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 54, // 4: ttn.lorawan.v3.MACParameters.rx1_delay:type_name -> ttn.lorawan.v3.RxDelay - 55, // 5: ttn.lorawan.v3.MACParameters.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffset - 53, // 6: ttn.lorawan.v3.MACParameters.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 56, // 7: ttn.lorawan.v3.MACParameters.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycle - 57, // 8: ttn.lorawan.v3.MACParameters.rejoin_time_periodicity:type_name -> ttn.lorawan.v3.RejoinTimeExponent - 58, // 9: ttn.lorawan.v3.MACParameters.rejoin_count_periodicity:type_name -> ttn.lorawan.v3.RejoinCountExponent - 53, // 10: ttn.lorawan.v3.MACParameters.ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 26, // 11: ttn.lorawan.v3.MACParameters.channels:type_name -> ttn.lorawan.v3.MACParameters.Channel - 2, // 12: ttn.lorawan.v3.MACParameters.uplink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue - 2, // 13: ttn.lorawan.v3.MACParameters.downlink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue - 59, // 14: ttn.lorawan.v3.MACParameters.adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponentValue - 60, // 15: ttn.lorawan.v3.MACParameters.adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponentValue - 61, // 16: ttn.lorawan.v3.MACParameters.ping_slot_data_rate_index_value:type_name -> ttn.lorawan.v3.DataRateIndexValue - 62, // 17: ttn.lorawan.v3.EndDeviceVersion.ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers - 63, // 18: ttn.lorawan.v3.EndDeviceVersion.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion - 64, // 19: ttn.lorawan.v3.EndDeviceVersion.lorawan_phy_version:type_name -> ttn.lorawan.v3.PHYVersion - 6, // 20: ttn.lorawan.v3.EndDeviceVersion.default_mac_settings:type_name -> ttn.lorawan.v3.MACSettings - 65, // 21: ttn.lorawan.v3.EndDeviceVersion.default_formatters:type_name -> ttn.lorawan.v3.MessagePayloadFormatters - 27, // 22: ttn.lorawan.v3.ADRSettings.static:type_name -> ttn.lorawan.v3.ADRSettings.StaticMode - 28, // 23: ttn.lorawan.v3.ADRSettings.dynamic:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode - 29, // 24: ttn.lorawan.v3.ADRSettings.disabled:type_name -> ttn.lorawan.v3.ADRSettings.DisabledMode - 66, // 25: ttn.lorawan.v3.MACSettings.class_b_timeout:type_name -> google.protobuf.Duration - 67, // 26: ttn.lorawan.v3.MACSettings.ping_slot_periodicity:type_name -> ttn.lorawan.v3.PingSlotPeriodValue - 61, // 27: ttn.lorawan.v3.MACSettings.ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 68, // 28: ttn.lorawan.v3.MACSettings.ping_slot_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue - 68, // 29: ttn.lorawan.v3.MACSettings.beacon_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue - 66, // 30: ttn.lorawan.v3.MACSettings.class_c_timeout:type_name -> google.protobuf.Duration - 69, // 31: ttn.lorawan.v3.MACSettings.rx1_delay:type_name -> ttn.lorawan.v3.RxDelayValue - 70, // 32: ttn.lorawan.v3.MACSettings.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffsetValue - 61, // 33: ttn.lorawan.v3.MACSettings.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 71, // 34: ttn.lorawan.v3.MACSettings.rx2_frequency:type_name -> ttn.lorawan.v3.FrequencyValue - 72, // 35: ttn.lorawan.v3.MACSettings.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycleValue - 2, // 36: ttn.lorawan.v3.MACSettings.supports_32_bit_f_cnt:type_name -> ttn.lorawan.v3.BoolValue - 2, // 37: ttn.lorawan.v3.MACSettings.use_adr:type_name -> ttn.lorawan.v3.BoolValue - 73, // 38: ttn.lorawan.v3.MACSettings.adr_margin:type_name -> google.protobuf.FloatValue - 2, // 39: ttn.lorawan.v3.MACSettings.resets_f_cnt:type_name -> ttn.lorawan.v3.BoolValue - 66, // 40: ttn.lorawan.v3.MACSettings.status_time_periodicity:type_name -> google.protobuf.Duration - 74, // 41: ttn.lorawan.v3.MACSettings.status_count_periodicity:type_name -> google.protobuf.UInt32Value - 69, // 42: ttn.lorawan.v3.MACSettings.desired_rx1_delay:type_name -> ttn.lorawan.v3.RxDelayValue - 70, // 43: ttn.lorawan.v3.MACSettings.desired_rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffsetValue - 61, // 44: ttn.lorawan.v3.MACSettings.desired_rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 71, // 45: ttn.lorawan.v3.MACSettings.desired_rx2_frequency:type_name -> ttn.lorawan.v3.FrequencyValue - 72, // 46: ttn.lorawan.v3.MACSettings.desired_max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycleValue - 59, // 47: ttn.lorawan.v3.MACSettings.desired_adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponentValue - 60, // 48: ttn.lorawan.v3.MACSettings.desired_adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponentValue - 61, // 49: ttn.lorawan.v3.MACSettings.desired_ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 68, // 50: ttn.lorawan.v3.MACSettings.desired_ping_slot_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue - 68, // 51: ttn.lorawan.v3.MACSettings.desired_beacon_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue - 75, // 52: ttn.lorawan.v3.MACSettings.desired_max_eirp:type_name -> ttn.lorawan.v3.DeviceEIRPValue - 66, // 53: ttn.lorawan.v3.MACSettings.class_b_c_downlink_interval:type_name -> google.protobuf.Duration - 2, // 54: ttn.lorawan.v3.MACSettings.uplink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue - 2, // 55: ttn.lorawan.v3.MACSettings.downlink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue - 5, // 56: ttn.lorawan.v3.MACSettings.adr:type_name -> ttn.lorawan.v3.ADRSettings - 2, // 57: ttn.lorawan.v3.MACSettings.schedule_downlinks:type_name -> ttn.lorawan.v3.BoolValue - 3, // 58: ttn.lorawan.v3.MACState.current_parameters:type_name -> ttn.lorawan.v3.MACParameters - 3, // 59: ttn.lorawan.v3.MACState.desired_parameters:type_name -> ttn.lorawan.v3.MACParameters - 76, // 60: ttn.lorawan.v3.MACState.device_class:type_name -> ttn.lorawan.v3.Class - 63, // 61: ttn.lorawan.v3.MACState.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion - 51, // 62: ttn.lorawan.v3.MACState.last_confirmed_downlink_at:type_name -> google.protobuf.Timestamp - 67, // 63: ttn.lorawan.v3.MACState.ping_slot_periodicity:type_name -> ttn.lorawan.v3.PingSlotPeriodValue - 52, // 64: ttn.lorawan.v3.MACState.pending_application_downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink - 77, // 65: ttn.lorawan.v3.MACState.queued_responses:type_name -> ttn.lorawan.v3.MACCommand - 77, // 66: ttn.lorawan.v3.MACState.pending_requests:type_name -> ttn.lorawan.v3.MACCommand - 34, // 67: ttn.lorawan.v3.MACState.queued_join_accept:type_name -> ttn.lorawan.v3.MACState.JoinAccept - 33, // 68: ttn.lorawan.v3.MACState.pending_join_request:type_name -> ttn.lorawan.v3.MACState.JoinRequest - 35, // 69: ttn.lorawan.v3.MACState.recent_uplinks:type_name -> ttn.lorawan.v3.MACState.UplinkMessage - 36, // 70: ttn.lorawan.v3.MACState.recent_downlinks:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage - 51, // 71: ttn.lorawan.v3.MACState.last_network_initiated_downlink_at:type_name -> google.protobuf.Timestamp - 53, // 72: ttn.lorawan.v3.MACState.rejected_adr_data_rate_indexes:type_name -> ttn.lorawan.v3.DataRateIndex - 51, // 73: ttn.lorawan.v3.MACState.last_downlink_at:type_name -> google.protobuf.Timestamp - 39, // 74: ttn.lorawan.v3.MACState.rejected_data_rate_ranges:type_name -> ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry - 78, // 75: ttn.lorawan.v3.MACState.recent_mac_command_identifiers:type_name -> ttn.lorawan.v3.MACCommandIdentifier - 51, // 76: ttn.lorawan.v3.EndDeviceAuthenticationCode.valid_from:type_name -> google.protobuf.Timestamp - 51, // 77: ttn.lorawan.v3.EndDeviceAuthenticationCode.valid_to:type_name -> google.protobuf.Timestamp - 79, // 78: ttn.lorawan.v3.EndDevice.ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 51, // 79: ttn.lorawan.v3.EndDevice.created_at:type_name -> google.protobuf.Timestamp - 51, // 80: ttn.lorawan.v3.EndDevice.updated_at:type_name -> google.protobuf.Timestamp - 46, // 81: ttn.lorawan.v3.EndDevice.attributes:type_name -> ttn.lorawan.v3.EndDevice.AttributesEntry - 62, // 82: ttn.lorawan.v3.EndDevice.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers - 47, // 83: ttn.lorawan.v3.EndDevice.locations:type_name -> ttn.lorawan.v3.EndDevice.LocationsEntry - 80, // 84: ttn.lorawan.v3.EndDevice.picture:type_name -> ttn.lorawan.v3.Picture - 63, // 85: ttn.lorawan.v3.EndDevice.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion - 64, // 86: ttn.lorawan.v3.EndDevice.lorawan_phy_version:type_name -> ttn.lorawan.v3.PHYVersion - 81, // 87: ttn.lorawan.v3.EndDevice.root_keys:type_name -> ttn.lorawan.v3.RootKeys - 6, // 88: ttn.lorawan.v3.EndDevice.mac_settings:type_name -> ttn.lorawan.v3.MACSettings - 7, // 89: ttn.lorawan.v3.EndDevice.mac_state:type_name -> ttn.lorawan.v3.MACState - 7, // 90: ttn.lorawan.v3.EndDevice.pending_mac_state:type_name -> ttn.lorawan.v3.MACState - 1, // 91: ttn.lorawan.v3.EndDevice.session:type_name -> ttn.lorawan.v3.Session - 1, // 92: ttn.lorawan.v3.EndDevice.pending_session:type_name -> ttn.lorawan.v3.Session - 51, // 93: ttn.lorawan.v3.EndDevice.last_dev_status_received_at:type_name -> google.protobuf.Timestamp - 0, // 94: ttn.lorawan.v3.EndDevice.power_state:type_name -> ttn.lorawan.v3.PowerState - 73, // 95: ttn.lorawan.v3.EndDevice.battery_percentage:type_name -> google.protobuf.FloatValue - 52, // 96: ttn.lorawan.v3.EndDevice.queued_application_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink - 65, // 97: ttn.lorawan.v3.EndDevice.formatters:type_name -> ttn.lorawan.v3.MessagePayloadFormatters - 82, // 98: ttn.lorawan.v3.EndDevice.provisioning_data:type_name -> google.protobuf.Struct - 8, // 99: ttn.lorawan.v3.EndDevice.claim_authentication_code:type_name -> ttn.lorawan.v3.EndDeviceAuthenticationCode - 83, // 100: ttn.lorawan.v3.EndDevice.skip_payload_crypto_override:type_name -> google.protobuf.BoolValue - 51, // 101: ttn.lorawan.v3.EndDevice.activated_at:type_name -> google.protobuf.Timestamp - 51, // 102: ttn.lorawan.v3.EndDevice.last_seen_at:type_name -> google.protobuf.Timestamp - 84, // 103: ttn.lorawan.v3.EndDevice.lora_alliance_profile_ids:type_name -> ttn.lorawan.v3.LoRaAllianceProfileIdentifiers - 9, // 104: ttn.lorawan.v3.EndDevices.end_devices:type_name -> ttn.lorawan.v3.EndDevice - 9, // 105: ttn.lorawan.v3.CreateEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice - 9, // 106: ttn.lorawan.v3.UpdateEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice - 85, // 107: ttn.lorawan.v3.UpdateEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask - 48, // 108: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.updates:type_name -> ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate - 79, // 109: ttn.lorawan.v3.GetEndDeviceRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 85, // 110: ttn.lorawan.v3.GetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask - 86, // 111: ttn.lorawan.v3.ListEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers - 85, // 112: ttn.lorawan.v3.ListEndDevicesRequest.field_mask:type_name -> google.protobuf.FieldMask - 9, // 113: ttn.lorawan.v3.SetEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice - 85, // 114: ttn.lorawan.v3.SetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask - 79, // 115: ttn.lorawan.v3.ResetAndGetEndDeviceRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 85, // 116: ttn.lorawan.v3.ResetAndGetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask - 9, // 117: ttn.lorawan.v3.EndDeviceTemplate.end_device:type_name -> ttn.lorawan.v3.EndDevice - 85, // 118: ttn.lorawan.v3.EndDeviceTemplate.field_mask:type_name -> google.protobuf.FieldMask - 49, // 119: ttn.lorawan.v3.EndDeviceTemplateFormats.formats:type_name -> ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry - 62, // 120: ttn.lorawan.v3.ConvertEndDeviceTemplateRequest.end_device_version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers - 86, // 121: ttn.lorawan.v3.BatchDeleteEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers - 86, // 122: ttn.lorawan.v3.BatchGetEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers - 85, // 123: ttn.lorawan.v3.BatchGetEndDevicesRequest.field_mask:type_name -> google.protobuf.FieldMask - 53, // 124: ttn.lorawan.v3.MACParameters.Channel.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 53, // 125: ttn.lorawan.v3.MACParameters.Channel.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 53, // 126: ttn.lorawan.v3.ADRSettings.StaticMode.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 73, // 127: ttn.lorawan.v3.ADRSettings.DynamicMode.margin:type_name -> google.protobuf.FloatValue - 61, // 128: ttn.lorawan.v3.ADRSettings.DynamicMode.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 61, // 129: ttn.lorawan.v3.ADRSettings.DynamicMode.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue - 74, // 130: ttn.lorawan.v3.ADRSettings.DynamicMode.min_tx_power_index:type_name -> google.protobuf.UInt32Value - 74, // 131: ttn.lorawan.v3.ADRSettings.DynamicMode.max_tx_power_index:type_name -> google.protobuf.UInt32Value - 74, // 132: ttn.lorawan.v3.ADRSettings.DynamicMode.min_nb_trans:type_name -> google.protobuf.UInt32Value - 74, // 133: ttn.lorawan.v3.ADRSettings.DynamicMode.max_nb_trans:type_name -> google.protobuf.UInt32Value - 30, // 134: ttn.lorawan.v3.ADRSettings.DynamicMode.channel_steering:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings - 31, // 135: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.lora_narrow:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.LoRaNarrowMode - 32, // 136: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.disabled:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.DisabledMode - 87, // 137: ttn.lorawan.v3.MACState.JoinRequest.downlink_settings:type_name -> ttn.lorawan.v3.DLSettings - 54, // 138: ttn.lorawan.v3.MACState.JoinRequest.rx_delay:type_name -> ttn.lorawan.v3.RxDelay - 88, // 139: ttn.lorawan.v3.MACState.JoinRequest.cf_list:type_name -> ttn.lorawan.v3.CFList - 33, // 140: ttn.lorawan.v3.MACState.JoinAccept.request:type_name -> ttn.lorawan.v3.MACState.JoinRequest - 50, // 141: ttn.lorawan.v3.MACState.JoinAccept.keys:type_name -> ttn.lorawan.v3.SessionKeys - 89, // 142: ttn.lorawan.v3.MACState.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message - 40, // 143: ttn.lorawan.v3.MACState.UplinkMessage.settings:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.TxSettings - 41, // 144: ttn.lorawan.v3.MACState.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata - 51, // 145: ttn.lorawan.v3.MACState.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp - 43, // 146: ttn.lorawan.v3.MACState.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message - 53, // 147: ttn.lorawan.v3.MACState.DataRateRange.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 53, // 148: ttn.lorawan.v3.MACState.DataRateRange.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 37, // 149: ttn.lorawan.v3.MACState.DataRateRanges.ranges:type_name -> ttn.lorawan.v3.MACState.DataRateRange - 38, // 150: ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry.value:type_name -> ttn.lorawan.v3.MACState.DataRateRanges - 90, // 151: ttn.lorawan.v3.MACState.UplinkMessage.TxSettings.data_rate:type_name -> ttn.lorawan.v3.DataRate - 91, // 152: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers - 92, // 153: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.downlink_path_constraint:type_name -> ttn.lorawan.v3.DownlinkPathConstraint - 42, // 154: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.packet_broker:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata - 44, // 155: ttn.lorawan.v3.MACState.DownlinkMessage.Message.m_hdr:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR - 45, // 156: ttn.lorawan.v3.MACState.DownlinkMessage.Message.mac_payload:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message.MACPayload - 93, // 157: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR.m_type:type_name -> ttn.lorawan.v3.MType - 94, // 158: ttn.lorawan.v3.EndDevice.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location - 79, // 159: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate.ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers - 51, // 160: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate.last_seen_at:type_name -> google.protobuf.Timestamp - 21, // 161: ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry.value:type_name -> ttn.lorawan.v3.EndDeviceTemplateFormat - 162, // [162:162] is the sub-list for method output_type - 162, // [162:162] is the sub-list for method input_type - 162, // [162:162] is the sub-list for extension type_name - 162, // [162:162] is the sub-list for extension extendee - 0, // [0:162] is the sub-list for field type_name + 56, // 0: ttn.lorawan.v3.Session.keys:type_name -> ttn.lorawan.v3.SessionKeys + 57, // 1: ttn.lorawan.v3.Session.started_at:type_name -> google.protobuf.Timestamp + 58, // 2: ttn.lorawan.v3.Session.queued_application_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 59, // 3: ttn.lorawan.v3.ServingRelayForwardingLimits.reset_behavior:type_name -> ttn.lorawan.v3.RelayResetLimitCounter + 60, // 4: ttn.lorawan.v3.ServingRelayForwardingLimits.join_requests:type_name -> ttn.lorawan.v3.RelayForwardLimits + 60, // 5: ttn.lorawan.v3.ServingRelayForwardingLimits.notifications:type_name -> ttn.lorawan.v3.RelayForwardLimits + 60, // 6: ttn.lorawan.v3.ServingRelayForwardingLimits.uplink_messages:type_name -> ttn.lorawan.v3.RelayForwardLimits + 60, // 7: ttn.lorawan.v3.ServingRelayForwardingLimits.overall:type_name -> ttn.lorawan.v3.RelayForwardLimits + 61, // 8: ttn.lorawan.v3.RelayUplinkForwardingRule.limits:type_name -> ttn.lorawan.v3.RelayUplinkForwardLimits + 62, // 9: ttn.lorawan.v3.ServingRelayParameters.second_channel:type_name -> ttn.lorawan.v3.RelaySecondChannel + 63, // 10: ttn.lorawan.v3.ServingRelayParameters.cad_periodicity:type_name -> ttn.lorawan.v3.RelayCADPeriodicity + 4, // 11: ttn.lorawan.v3.ServingRelayParameters.uplink_forwarding_rules:type_name -> ttn.lorawan.v3.RelayUplinkForwardingRule + 3, // 12: ttn.lorawan.v3.ServingRelayParameters.limits:type_name -> ttn.lorawan.v3.ServingRelayForwardingLimits + 64, // 13: ttn.lorawan.v3.ServedRelayParameters.always:type_name -> ttn.lorawan.v3.RelayEndDeviceAlwaysMode + 65, // 14: ttn.lorawan.v3.ServedRelayParameters.dynamic:type_name -> ttn.lorawan.v3.RelayEndDeviceDynamicMode + 66, // 15: ttn.lorawan.v3.ServedRelayParameters.end_device_controlled:type_name -> ttn.lorawan.v3.RelayEndDeviceControlledMode + 62, // 16: ttn.lorawan.v3.ServedRelayParameters.second_channel:type_name -> ttn.lorawan.v3.RelaySecondChannel + 5, // 17: ttn.lorawan.v3.RelayParameters.serving:type_name -> ttn.lorawan.v3.ServingRelayParameters + 6, // 18: ttn.lorawan.v3.RelayParameters.served:type_name -> ttn.lorawan.v3.ServedRelayParameters + 67, // 19: ttn.lorawan.v3.MACParameters.adr_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 68, // 20: ttn.lorawan.v3.MACParameters.rx1_delay:type_name -> ttn.lorawan.v3.RxDelay + 69, // 21: ttn.lorawan.v3.MACParameters.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffset + 67, // 22: ttn.lorawan.v3.MACParameters.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 70, // 23: ttn.lorawan.v3.MACParameters.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycle + 71, // 24: ttn.lorawan.v3.MACParameters.rejoin_time_periodicity:type_name -> ttn.lorawan.v3.RejoinTimeExponent + 72, // 25: ttn.lorawan.v3.MACParameters.rejoin_count_periodicity:type_name -> ttn.lorawan.v3.RejoinCountExponent + 67, // 26: ttn.lorawan.v3.MACParameters.ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 31, // 27: ttn.lorawan.v3.MACParameters.channels:type_name -> ttn.lorawan.v3.MACParameters.Channel + 2, // 28: ttn.lorawan.v3.MACParameters.uplink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue + 2, // 29: ttn.lorawan.v3.MACParameters.downlink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue + 73, // 30: ttn.lorawan.v3.MACParameters.adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponentValue + 74, // 31: ttn.lorawan.v3.MACParameters.adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponentValue + 75, // 32: ttn.lorawan.v3.MACParameters.ping_slot_data_rate_index_value:type_name -> ttn.lorawan.v3.DataRateIndexValue + 7, // 33: ttn.lorawan.v3.MACParameters.relay:type_name -> ttn.lorawan.v3.RelayParameters + 76, // 34: ttn.lorawan.v3.EndDeviceVersion.ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 77, // 35: ttn.lorawan.v3.EndDeviceVersion.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion + 78, // 36: ttn.lorawan.v3.EndDeviceVersion.lorawan_phy_version:type_name -> ttn.lorawan.v3.PHYVersion + 11, // 37: ttn.lorawan.v3.EndDeviceVersion.default_mac_settings:type_name -> ttn.lorawan.v3.MACSettings + 79, // 38: ttn.lorawan.v3.EndDeviceVersion.default_formatters:type_name -> ttn.lorawan.v3.MessagePayloadFormatters + 32, // 39: ttn.lorawan.v3.ADRSettings.static:type_name -> ttn.lorawan.v3.ADRSettings.StaticMode + 33, // 40: ttn.lorawan.v3.ADRSettings.dynamic:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode + 34, // 41: ttn.lorawan.v3.ADRSettings.disabled:type_name -> ttn.lorawan.v3.ADRSettings.DisabledMode + 80, // 42: ttn.lorawan.v3.MACSettings.class_b_timeout:type_name -> google.protobuf.Duration + 81, // 43: ttn.lorawan.v3.MACSettings.ping_slot_periodicity:type_name -> ttn.lorawan.v3.PingSlotPeriodValue + 75, // 44: ttn.lorawan.v3.MACSettings.ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 82, // 45: ttn.lorawan.v3.MACSettings.ping_slot_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue + 82, // 46: ttn.lorawan.v3.MACSettings.beacon_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue + 80, // 47: ttn.lorawan.v3.MACSettings.class_c_timeout:type_name -> google.protobuf.Duration + 83, // 48: ttn.lorawan.v3.MACSettings.rx1_delay:type_name -> ttn.lorawan.v3.RxDelayValue + 84, // 49: ttn.lorawan.v3.MACSettings.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffsetValue + 75, // 50: ttn.lorawan.v3.MACSettings.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 85, // 51: ttn.lorawan.v3.MACSettings.rx2_frequency:type_name -> ttn.lorawan.v3.FrequencyValue + 86, // 52: ttn.lorawan.v3.MACSettings.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycleValue + 2, // 53: ttn.lorawan.v3.MACSettings.supports_32_bit_f_cnt:type_name -> ttn.lorawan.v3.BoolValue + 2, // 54: ttn.lorawan.v3.MACSettings.use_adr:type_name -> ttn.lorawan.v3.BoolValue + 87, // 55: ttn.lorawan.v3.MACSettings.adr_margin:type_name -> google.protobuf.FloatValue + 2, // 56: ttn.lorawan.v3.MACSettings.resets_f_cnt:type_name -> ttn.lorawan.v3.BoolValue + 80, // 57: ttn.lorawan.v3.MACSettings.status_time_periodicity:type_name -> google.protobuf.Duration + 88, // 58: ttn.lorawan.v3.MACSettings.status_count_periodicity:type_name -> google.protobuf.UInt32Value + 83, // 59: ttn.lorawan.v3.MACSettings.desired_rx1_delay:type_name -> ttn.lorawan.v3.RxDelayValue + 84, // 60: ttn.lorawan.v3.MACSettings.desired_rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffsetValue + 75, // 61: ttn.lorawan.v3.MACSettings.desired_rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 85, // 62: ttn.lorawan.v3.MACSettings.desired_rx2_frequency:type_name -> ttn.lorawan.v3.FrequencyValue + 86, // 63: ttn.lorawan.v3.MACSettings.desired_max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycleValue + 73, // 64: ttn.lorawan.v3.MACSettings.desired_adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponentValue + 74, // 65: ttn.lorawan.v3.MACSettings.desired_adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponentValue + 75, // 66: ttn.lorawan.v3.MACSettings.desired_ping_slot_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 82, // 67: ttn.lorawan.v3.MACSettings.desired_ping_slot_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue + 82, // 68: ttn.lorawan.v3.MACSettings.desired_beacon_frequency:type_name -> ttn.lorawan.v3.ZeroableFrequencyValue + 89, // 69: ttn.lorawan.v3.MACSettings.desired_max_eirp:type_name -> ttn.lorawan.v3.DeviceEIRPValue + 80, // 70: ttn.lorawan.v3.MACSettings.class_b_c_downlink_interval:type_name -> google.protobuf.Duration + 2, // 71: ttn.lorawan.v3.MACSettings.uplink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue + 2, // 72: ttn.lorawan.v3.MACSettings.downlink_dwell_time:type_name -> ttn.lorawan.v3.BoolValue + 10, // 73: ttn.lorawan.v3.MACSettings.adr:type_name -> ttn.lorawan.v3.ADRSettings + 2, // 74: ttn.lorawan.v3.MACSettings.schedule_downlinks:type_name -> ttn.lorawan.v3.BoolValue + 7, // 75: ttn.lorawan.v3.MACSettings.relay:type_name -> ttn.lorawan.v3.RelayParameters + 7, // 76: ttn.lorawan.v3.MACSettings.desired_relay:type_name -> ttn.lorawan.v3.RelayParameters + 8, // 77: ttn.lorawan.v3.MACState.current_parameters:type_name -> ttn.lorawan.v3.MACParameters + 8, // 78: ttn.lorawan.v3.MACState.desired_parameters:type_name -> ttn.lorawan.v3.MACParameters + 90, // 79: ttn.lorawan.v3.MACState.device_class:type_name -> ttn.lorawan.v3.Class + 77, // 80: ttn.lorawan.v3.MACState.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion + 57, // 81: ttn.lorawan.v3.MACState.last_confirmed_downlink_at:type_name -> google.protobuf.Timestamp + 81, // 82: ttn.lorawan.v3.MACState.ping_slot_periodicity:type_name -> ttn.lorawan.v3.PingSlotPeriodValue + 58, // 83: ttn.lorawan.v3.MACState.pending_application_downlink:type_name -> ttn.lorawan.v3.ApplicationDownlink + 91, // 84: ttn.lorawan.v3.MACState.queued_responses:type_name -> ttn.lorawan.v3.MACCommand + 91, // 85: ttn.lorawan.v3.MACState.pending_requests:type_name -> ttn.lorawan.v3.MACCommand + 39, // 86: ttn.lorawan.v3.MACState.queued_join_accept:type_name -> ttn.lorawan.v3.MACState.JoinAccept + 38, // 87: ttn.lorawan.v3.MACState.pending_join_request:type_name -> ttn.lorawan.v3.MACState.JoinRequest + 40, // 88: ttn.lorawan.v3.MACState.recent_uplinks:type_name -> ttn.lorawan.v3.MACState.UplinkMessage + 41, // 89: ttn.lorawan.v3.MACState.recent_downlinks:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage + 57, // 90: ttn.lorawan.v3.MACState.last_network_initiated_downlink_at:type_name -> google.protobuf.Timestamp + 67, // 91: ttn.lorawan.v3.MACState.rejected_adr_data_rate_indexes:type_name -> ttn.lorawan.v3.DataRateIndex + 57, // 92: ttn.lorawan.v3.MACState.last_downlink_at:type_name -> google.protobuf.Timestamp + 44, // 93: ttn.lorawan.v3.MACState.rejected_data_rate_ranges:type_name -> ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry + 92, // 94: ttn.lorawan.v3.MACState.recent_mac_command_identifiers:type_name -> ttn.lorawan.v3.MACCommandIdentifier + 93, // 95: ttn.lorawan.v3.MACState.pending_relay_downlink:type_name -> ttn.lorawan.v3.RelayForwardDownlinkReq + 57, // 96: ttn.lorawan.v3.EndDeviceAuthenticationCode.valid_from:type_name -> google.protobuf.Timestamp + 57, // 97: ttn.lorawan.v3.EndDeviceAuthenticationCode.valid_to:type_name -> google.protobuf.Timestamp + 94, // 98: ttn.lorawan.v3.EndDevice.ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 57, // 99: ttn.lorawan.v3.EndDevice.created_at:type_name -> google.protobuf.Timestamp + 57, // 100: ttn.lorawan.v3.EndDevice.updated_at:type_name -> google.protobuf.Timestamp + 52, // 101: ttn.lorawan.v3.EndDevice.attributes:type_name -> ttn.lorawan.v3.EndDevice.AttributesEntry + 76, // 102: ttn.lorawan.v3.EndDevice.version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 53, // 103: ttn.lorawan.v3.EndDevice.locations:type_name -> ttn.lorawan.v3.EndDevice.LocationsEntry + 95, // 104: ttn.lorawan.v3.EndDevice.picture:type_name -> ttn.lorawan.v3.Picture + 77, // 105: ttn.lorawan.v3.EndDevice.lorawan_version:type_name -> ttn.lorawan.v3.MACVersion + 78, // 106: ttn.lorawan.v3.EndDevice.lorawan_phy_version:type_name -> ttn.lorawan.v3.PHYVersion + 96, // 107: ttn.lorawan.v3.EndDevice.root_keys:type_name -> ttn.lorawan.v3.RootKeys + 11, // 108: ttn.lorawan.v3.EndDevice.mac_settings:type_name -> ttn.lorawan.v3.MACSettings + 12, // 109: ttn.lorawan.v3.EndDevice.mac_state:type_name -> ttn.lorawan.v3.MACState + 12, // 110: ttn.lorawan.v3.EndDevice.pending_mac_state:type_name -> ttn.lorawan.v3.MACState + 1, // 111: ttn.lorawan.v3.EndDevice.session:type_name -> ttn.lorawan.v3.Session + 1, // 112: ttn.lorawan.v3.EndDevice.pending_session:type_name -> ttn.lorawan.v3.Session + 57, // 113: ttn.lorawan.v3.EndDevice.last_dev_status_received_at:type_name -> google.protobuf.Timestamp + 0, // 114: ttn.lorawan.v3.EndDevice.power_state:type_name -> ttn.lorawan.v3.PowerState + 87, // 115: ttn.lorawan.v3.EndDevice.battery_percentage:type_name -> google.protobuf.FloatValue + 58, // 116: ttn.lorawan.v3.EndDevice.queued_application_downlinks:type_name -> ttn.lorawan.v3.ApplicationDownlink + 79, // 117: ttn.lorawan.v3.EndDevice.formatters:type_name -> ttn.lorawan.v3.MessagePayloadFormatters + 97, // 118: ttn.lorawan.v3.EndDevice.provisioning_data:type_name -> google.protobuf.Struct + 13, // 119: ttn.lorawan.v3.EndDevice.claim_authentication_code:type_name -> ttn.lorawan.v3.EndDeviceAuthenticationCode + 98, // 120: ttn.lorawan.v3.EndDevice.skip_payload_crypto_override:type_name -> google.protobuf.BoolValue + 57, // 121: ttn.lorawan.v3.EndDevice.activated_at:type_name -> google.protobuf.Timestamp + 57, // 122: ttn.lorawan.v3.EndDevice.last_seen_at:type_name -> google.protobuf.Timestamp + 99, // 123: ttn.lorawan.v3.EndDevice.lora_alliance_profile_ids:type_name -> ttn.lorawan.v3.LoRaAllianceProfileIdentifiers + 14, // 124: ttn.lorawan.v3.EndDevices.end_devices:type_name -> ttn.lorawan.v3.EndDevice + 14, // 125: ttn.lorawan.v3.CreateEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice + 14, // 126: ttn.lorawan.v3.UpdateEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice + 100, // 127: ttn.lorawan.v3.UpdateEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask + 54, // 128: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.updates:type_name -> ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate + 94, // 129: ttn.lorawan.v3.GetEndDeviceRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 100, // 130: ttn.lorawan.v3.GetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask + 101, // 131: ttn.lorawan.v3.ListEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers + 100, // 132: ttn.lorawan.v3.ListEndDevicesRequest.field_mask:type_name -> google.protobuf.FieldMask + 14, // 133: ttn.lorawan.v3.SetEndDeviceRequest.end_device:type_name -> ttn.lorawan.v3.EndDevice + 100, // 134: ttn.lorawan.v3.SetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask + 94, // 135: ttn.lorawan.v3.ResetAndGetEndDeviceRequest.end_device_ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 100, // 136: ttn.lorawan.v3.ResetAndGetEndDeviceRequest.field_mask:type_name -> google.protobuf.FieldMask + 14, // 137: ttn.lorawan.v3.EndDeviceTemplate.end_device:type_name -> ttn.lorawan.v3.EndDevice + 100, // 138: ttn.lorawan.v3.EndDeviceTemplate.field_mask:type_name -> google.protobuf.FieldMask + 55, // 139: ttn.lorawan.v3.EndDeviceTemplateFormats.formats:type_name -> ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry + 76, // 140: ttn.lorawan.v3.ConvertEndDeviceTemplateRequest.end_device_version_ids:type_name -> ttn.lorawan.v3.EndDeviceVersionIdentifiers + 101, // 141: ttn.lorawan.v3.BatchDeleteEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers + 101, // 142: ttn.lorawan.v3.BatchGetEndDevicesRequest.application_ids:type_name -> ttn.lorawan.v3.ApplicationIdentifiers + 100, // 143: ttn.lorawan.v3.BatchGetEndDevicesRequest.field_mask:type_name -> google.protobuf.FieldMask + 67, // 144: ttn.lorawan.v3.MACParameters.Channel.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 67, // 145: ttn.lorawan.v3.MACParameters.Channel.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 67, // 146: ttn.lorawan.v3.ADRSettings.StaticMode.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 87, // 147: ttn.lorawan.v3.ADRSettings.DynamicMode.margin:type_name -> google.protobuf.FloatValue + 75, // 148: ttn.lorawan.v3.ADRSettings.DynamicMode.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 75, // 149: ttn.lorawan.v3.ADRSettings.DynamicMode.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndexValue + 88, // 150: ttn.lorawan.v3.ADRSettings.DynamicMode.min_tx_power_index:type_name -> google.protobuf.UInt32Value + 88, // 151: ttn.lorawan.v3.ADRSettings.DynamicMode.max_tx_power_index:type_name -> google.protobuf.UInt32Value + 88, // 152: ttn.lorawan.v3.ADRSettings.DynamicMode.min_nb_trans:type_name -> google.protobuf.UInt32Value + 88, // 153: ttn.lorawan.v3.ADRSettings.DynamicMode.max_nb_trans:type_name -> google.protobuf.UInt32Value + 35, // 154: ttn.lorawan.v3.ADRSettings.DynamicMode.channel_steering:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings + 36, // 155: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.lora_narrow:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.LoRaNarrowMode + 37, // 156: ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.disabled:type_name -> ttn.lorawan.v3.ADRSettings.DynamicMode.ChannelSteeringSettings.DisabledMode + 102, // 157: ttn.lorawan.v3.MACState.JoinRequest.downlink_settings:type_name -> ttn.lorawan.v3.DLSettings + 68, // 158: ttn.lorawan.v3.MACState.JoinRequest.rx_delay:type_name -> ttn.lorawan.v3.RxDelay + 103, // 159: ttn.lorawan.v3.MACState.JoinRequest.cf_list:type_name -> ttn.lorawan.v3.CFList + 38, // 160: ttn.lorawan.v3.MACState.JoinAccept.request:type_name -> ttn.lorawan.v3.MACState.JoinRequest + 56, // 161: ttn.lorawan.v3.MACState.JoinAccept.keys:type_name -> ttn.lorawan.v3.SessionKeys + 104, // 162: ttn.lorawan.v3.MACState.UplinkMessage.payload:type_name -> ttn.lorawan.v3.Message + 45, // 163: ttn.lorawan.v3.MACState.UplinkMessage.settings:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.TxSettings + 46, // 164: ttn.lorawan.v3.MACState.UplinkMessage.rx_metadata:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata + 57, // 165: ttn.lorawan.v3.MACState.UplinkMessage.received_at:type_name -> google.protobuf.Timestamp + 49, // 166: ttn.lorawan.v3.MACState.DownlinkMessage.payload:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message + 67, // 167: ttn.lorawan.v3.MACState.DataRateRange.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 67, // 168: ttn.lorawan.v3.MACState.DataRateRange.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 42, // 169: ttn.lorawan.v3.MACState.DataRateRanges.ranges:type_name -> ttn.lorawan.v3.MACState.DataRateRange + 43, // 170: ttn.lorawan.v3.MACState.RejectedDataRateRangesEntry.value:type_name -> ttn.lorawan.v3.MACState.DataRateRanges + 105, // 171: ttn.lorawan.v3.MACState.UplinkMessage.TxSettings.data_rate:type_name -> ttn.lorawan.v3.DataRate + 106, // 172: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers + 107, // 173: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.downlink_path_constraint:type_name -> ttn.lorawan.v3.DownlinkPathConstraint + 47, // 174: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.packet_broker:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.PacketBrokerMetadata + 48, // 175: ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.relay:type_name -> ttn.lorawan.v3.MACState.UplinkMessage.RxMetadata.RelayMetadata + 50, // 176: ttn.lorawan.v3.MACState.DownlinkMessage.Message.m_hdr:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR + 51, // 177: ttn.lorawan.v3.MACState.DownlinkMessage.Message.mac_payload:type_name -> ttn.lorawan.v3.MACState.DownlinkMessage.Message.MACPayload + 108, // 178: ttn.lorawan.v3.MACState.DownlinkMessage.Message.MHDR.m_type:type_name -> ttn.lorawan.v3.MType + 109, // 179: ttn.lorawan.v3.EndDevice.LocationsEntry.value:type_name -> ttn.lorawan.v3.Location + 94, // 180: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate.ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 57, // 181: ttn.lorawan.v3.BatchUpdateEndDeviceLastSeenRequest.EndDeviceLastSeenUpdate.last_seen_at:type_name -> google.protobuf.Timestamp + 26, // 182: ttn.lorawan.v3.EndDeviceTemplateFormats.FormatsEntry.value:type_name -> ttn.lorawan.v3.EndDeviceTemplateFormat + 183, // [183:183] is the sub-list for method output_type + 183, // [183:183] is the sub-list for method input_type + 183, // [183:183] is the sub-list for extension type_name + 183, // [183:183] is the sub-list for extension extendee + 0, // [0:183] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_end_device_proto_init() } @@ -5913,7 +6630,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACParameters); i { + switch v := v.(*ServingRelayForwardingLimits); i { case 0: return &v.state case 1: @@ -5925,7 +6642,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDeviceVersion); i { + switch v := v.(*RelayUplinkForwardingRule); i { case 0: return &v.state case 1: @@ -5937,7 +6654,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings); i { + switch v := v.(*ServingRelayParameters); i { case 0: return &v.state case 1: @@ -5949,7 +6666,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACSettings); i { + switch v := v.(*ServedRelayParameters); i { case 0: return &v.state case 1: @@ -5961,7 +6678,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState); i { + switch v := v.(*RelayParameters); i { case 0: return &v.state case 1: @@ -5973,7 +6690,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDeviceAuthenticationCode); i { + switch v := v.(*MACParameters); i { case 0: return &v.state case 1: @@ -5985,7 +6702,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDevice); i { + switch v := v.(*EndDeviceVersion); i { case 0: return &v.state case 1: @@ -5997,7 +6714,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDevices); i { + switch v := v.(*ADRSettings); i { case 0: return &v.state case 1: @@ -6009,7 +6726,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DevAddrPrefix); i { + switch v := v.(*MACSettings); i { case 0: return &v.state case 1: @@ -6021,7 +6738,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateEndDeviceRequest); i { + switch v := v.(*MACState); i { case 0: return &v.state case 1: @@ -6033,7 +6750,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateEndDeviceRequest); i { + switch v := v.(*EndDeviceAuthenticationCode); i { case 0: return &v.state case 1: @@ -6045,7 +6762,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchUpdateEndDeviceLastSeenRequest); i { + switch v := v.(*EndDevice); i { case 0: return &v.state case 1: @@ -6057,7 +6774,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetEndDeviceRequest); i { + switch v := v.(*EndDevices); i { case 0: return &v.state case 1: @@ -6069,7 +6786,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetEndDeviceIdentifiersForEUIsRequest); i { + switch v := v.(*DevAddrPrefix); i { case 0: return &v.state case 1: @@ -6081,7 +6798,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ListEndDevicesRequest); i { + switch v := v.(*CreateEndDeviceRequest); i { case 0: return &v.state case 1: @@ -6093,7 +6810,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetEndDeviceRequest); i { + switch v := v.(*UpdateEndDeviceRequest); i { case 0: return &v.state case 1: @@ -6105,7 +6822,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResetAndGetEndDeviceRequest); i { + switch v := v.(*BatchUpdateEndDeviceLastSeenRequest); i { case 0: return &v.state case 1: @@ -6117,7 +6834,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDeviceTemplate); i { + switch v := v.(*GetEndDeviceRequest); i { case 0: return &v.state case 1: @@ -6129,7 +6846,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDeviceTemplateFormat); i { + switch v := v.(*GetEndDeviceIdentifiersForEUIsRequest); i { case 0: return &v.state case 1: @@ -6141,7 +6858,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*EndDeviceTemplateFormats); i { + switch v := v.(*ListEndDevicesRequest); i { case 0: return &v.state case 1: @@ -6153,7 +6870,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConvertEndDeviceTemplateRequest); i { + switch v := v.(*SetEndDeviceRequest); i { case 0: return &v.state case 1: @@ -6165,7 +6882,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchDeleteEndDevicesRequest); i { + switch v := v.(*ResetAndGetEndDeviceRequest); i { case 0: return &v.state case 1: @@ -6177,7 +6894,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchGetEndDevicesRequest); i { + switch v := v.(*EndDeviceTemplate); i { case 0: return &v.state case 1: @@ -6189,7 +6906,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACParameters_Channel); i { + switch v := v.(*EndDeviceTemplateFormat); i { case 0: return &v.state case 1: @@ -6201,7 +6918,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_StaticMode); i { + switch v := v.(*EndDeviceTemplateFormats); i { case 0: return &v.state case 1: @@ -6213,7 +6930,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_DynamicMode); i { + switch v := v.(*ConvertEndDeviceTemplateRequest); i { case 0: return &v.state case 1: @@ -6225,7 +6942,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_DisabledMode); i { + switch v := v.(*BatchDeleteEndDevicesRequest); i { case 0: return &v.state case 1: @@ -6237,7 +6954,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings); i { + switch v := v.(*BatchGetEndDevicesRequest); i { case 0: return &v.state case 1: @@ -6249,7 +6966,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode); i { + switch v := v.(*MACParameters_Channel); i { case 0: return &v.state case 1: @@ -6261,7 +6978,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode); i { + switch v := v.(*ADRSettings_StaticMode); i { case 0: return &v.state case 1: @@ -6273,7 +6990,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_JoinRequest); i { + switch v := v.(*ADRSettings_DynamicMode); i { case 0: return &v.state case 1: @@ -6285,7 +7002,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_JoinAccept); i { + switch v := v.(*ADRSettings_DisabledMode); i { case 0: return &v.state case 1: @@ -6297,7 +7014,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_UplinkMessage); i { + switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings); i { case 0: return &v.state case 1: @@ -6309,7 +7026,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_DownlinkMessage); i { + switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings_LoRaNarrowMode); i { case 0: return &v.state case 1: @@ -6321,7 +7038,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_DataRateRange); i { + switch v := v.(*ADRSettings_DynamicMode_ChannelSteeringSettings_DisabledMode); i { case 0: return &v.state case 1: @@ -6333,7 +7050,19 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_DataRateRanges); i { + switch v := v.(*MACState_JoinRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_JoinAccept); i { case 0: return &v.state case 1: @@ -6345,7 +7074,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_UplinkMessage_TxSettings); i { + switch v := v.(*MACState_UplinkMessage); i { case 0: return &v.state case 1: @@ -6357,7 +7086,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_UplinkMessage_RxMetadata); i { + switch v := v.(*MACState_DownlinkMessage); i { case 0: return &v.state case 1: @@ -6369,7 +7098,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata); i { + switch v := v.(*MACState_DataRateRange); i { case 0: return &v.state case 1: @@ -6381,6 +7110,66 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } file_ttn_lorawan_v3_end_device_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_DataRateRanges); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_UplinkMessage_TxSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_UplinkMessage_RxMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACState_UplinkMessage_RxMetadata_RelayMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MACState_DownlinkMessage_Message); i { case 0: return &v.state @@ -6392,7 +7181,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { return nil } } - file_ttn_lorawan_v3_end_device_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_ttn_lorawan_v3_end_device_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MACState_DownlinkMessage_Message_MHDR); i { case 0: return &v.state @@ -6404,7 +7193,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { return nil } } - file_ttn_lorawan_v3_end_device_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_ttn_lorawan_v3_end_device_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MACState_DownlinkMessage_Message_MACPayload); i { case 0: return &v.state @@ -6416,7 +7205,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { return nil } } - file_ttn_lorawan_v3_end_device_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + file_ttn_lorawan_v3_end_device_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BatchUpdateEndDeviceLastSeenRequest_EndDeviceLastSeenUpdate); i { case 0: return &v.state @@ -6429,12 +7218,21 @@ func file_ttn_lorawan_v3_end_device_proto_init() { } } } - file_ttn_lorawan_v3_end_device_proto_msgTypes[4].OneofWrappers = []interface{}{ + file_ttn_lorawan_v3_end_device_proto_msgTypes[5].OneofWrappers = []interface{}{ + (*ServedRelayParameters_Always)(nil), + (*ServedRelayParameters_Dynamic)(nil), + (*ServedRelayParameters_EndDeviceControlled)(nil), + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[6].OneofWrappers = []interface{}{ + (*RelayParameters_Serving)(nil), + (*RelayParameters_Served)(nil), + } + file_ttn_lorawan_v3_end_device_proto_msgTypes[9].OneofWrappers = []interface{}{ (*ADRSettings_Static)(nil), (*ADRSettings_Dynamic)(nil), (*ADRSettings_Disabled)(nil), } - file_ttn_lorawan_v3_end_device_proto_msgTypes[29].OneofWrappers = []interface{}{ + file_ttn_lorawan_v3_end_device_proto_msgTypes[34].OneofWrappers = []interface{}{ (*ADRSettings_DynamicMode_ChannelSteeringSettings_LoraNarrow)(nil), (*ADRSettings_DynamicMode_ChannelSteeringSettings_Disabled)(nil), } @@ -6444,7 +7242,7 @@ func file_ttn_lorawan_v3_end_device_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ttn_lorawan_v3_end_device_proto_rawDesc, NumEnums: 1, - NumMessages: 49, + NumMessages: 55, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/ttnpb/end_device.pb.paths.fm.go b/pkg/ttnpb/end_device.pb.paths.fm.go index 8a4bf5852b..d93d2affac 100644 --- a/pkg/ttnpb/end_device.pb.paths.fm.go +++ b/pkg/ttnpb/end_device.pb.paths.fm.go @@ -47,6 +47,136 @@ var BoolValueFieldPathsNested = []string{ var BoolValueFieldPathsTopLevel = []string{ "value", } +var ServingRelayForwardingLimitsFieldPathsNested = []string{ + "join_requests", + "join_requests.bucket_size", + "join_requests.reload_rate", + "notifications", + "notifications.bucket_size", + "notifications.reload_rate", + "overall", + "overall.bucket_size", + "overall.reload_rate", + "reset_behavior", + "uplink_messages", + "uplink_messages.bucket_size", + "uplink_messages.reload_rate", +} + +var ServingRelayForwardingLimitsFieldPathsTopLevel = []string{ + "join_requests", + "notifications", + "overall", + "reset_behavior", + "uplink_messages", +} +var RelayUplinkForwardingRuleFieldPathsNested = []string{ + "device_id", + "last_w_f_cnt", + "limits", + "limits.bucket_size", + "limits.reload_rate", + "session_key_id", +} + +var RelayUplinkForwardingRuleFieldPathsTopLevel = []string{ + "device_id", + "last_w_f_cnt", + "limits", + "session_key_id", +} +var ServingRelayParametersFieldPathsNested = []string{ + "cad_periodicity", + "default_channel_index", + "limits", + "limits.join_requests", + "limits.join_requests.bucket_size", + "limits.join_requests.reload_rate", + "limits.notifications", + "limits.notifications.bucket_size", + "limits.notifications.reload_rate", + "limits.overall", + "limits.overall.bucket_size", + "limits.overall.reload_rate", + "limits.reset_behavior", + "limits.uplink_messages", + "limits.uplink_messages.bucket_size", + "limits.uplink_messages.reload_rate", + "second_channel", + "second_channel.ack_offset", + "second_channel.data_rate_index", + "second_channel.frequency", + "uplink_forwarding_rules", +} + +var ServingRelayParametersFieldPathsTopLevel = []string{ + "cad_periodicity", + "default_channel_index", + "limits", + "second_channel", + "uplink_forwarding_rules", +} +var ServedRelayParametersFieldPathsNested = []string{ + "backoff", + "mode", + "mode.always", + "mode.dynamic", + "mode.dynamic.smart_enable_level", + "mode.end_device_controlled", + "second_channel", + "second_channel.ack_offset", + "second_channel.data_rate_index", + "second_channel.frequency", + "serving_device_id", +} + +var ServedRelayParametersFieldPathsTopLevel = []string{ + "backoff", + "mode", + "second_channel", + "serving_device_id", +} +var RelayParametersFieldPathsNested = []string{ + "mode", + "mode.served", + "mode.served.backoff", + "mode.served.mode", + "mode.served.mode.always", + "mode.served.mode.dynamic", + "mode.served.mode.dynamic.smart_enable_level", + "mode.served.mode.end_device_controlled", + "mode.served.second_channel", + "mode.served.second_channel.ack_offset", + "mode.served.second_channel.data_rate_index", + "mode.served.second_channel.frequency", + "mode.served.serving_device_id", + "mode.serving", + "mode.serving.cad_periodicity", + "mode.serving.default_channel_index", + "mode.serving.limits", + "mode.serving.limits.join_requests", + "mode.serving.limits.join_requests.bucket_size", + "mode.serving.limits.join_requests.reload_rate", + "mode.serving.limits.notifications", + "mode.serving.limits.notifications.bucket_size", + "mode.serving.limits.notifications.reload_rate", + "mode.serving.limits.overall", + "mode.serving.limits.overall.bucket_size", + "mode.serving.limits.overall.reload_rate", + "mode.serving.limits.reset_behavior", + "mode.serving.limits.uplink_messages", + "mode.serving.limits.uplink_messages.bucket_size", + "mode.serving.limits.uplink_messages.reload_rate", + "mode.serving.second_channel", + "mode.serving.second_channel.ack_offset", + "mode.serving.second_channel.data_rate_index", + "mode.serving.second_channel.frequency", + "mode.serving.uplink_forwarding_rules", +} + +var RelayParametersFieldPathsTopLevel = []string{ + "mode", +} var MACParametersFieldPathsNested = []string{ "adr_ack_delay", "adr_ack_delay_exponent", @@ -69,6 +199,42 @@ var MACParametersFieldPathsNested = []string{ "ping_slot_frequency", "rejoin_count_periodicity", "rejoin_time_periodicity", + "relay", + "relay.mode", + "relay.mode.served", + "relay.mode.served.backoff", + "relay.mode.served.mode", + "relay.mode.served.mode.always", + "relay.mode.served.mode.dynamic", + "relay.mode.served.mode.dynamic.smart_enable_level", + "relay.mode.served.mode.end_device_controlled", + "relay.mode.served.second_channel", + "relay.mode.served.second_channel.ack_offset", + "relay.mode.served.second_channel.data_rate_index", + "relay.mode.served.second_channel.frequency", + "relay.mode.served.serving_device_id", + "relay.mode.serving", + "relay.mode.serving.cad_periodicity", + "relay.mode.serving.default_channel_index", + "relay.mode.serving.limits", + "relay.mode.serving.limits.join_requests", + "relay.mode.serving.limits.join_requests.bucket_size", + "relay.mode.serving.limits.join_requests.reload_rate", + "relay.mode.serving.limits.notifications", + "relay.mode.serving.limits.notifications.bucket_size", + "relay.mode.serving.limits.notifications.reload_rate", + "relay.mode.serving.limits.overall", + "relay.mode.serving.limits.overall.bucket_size", + "relay.mode.serving.limits.overall.reload_rate", + "relay.mode.serving.limits.reset_behavior", + "relay.mode.serving.limits.uplink_messages", + "relay.mode.serving.limits.uplink_messages.bucket_size", + "relay.mode.serving.limits.uplink_messages.reload_rate", + "relay.mode.serving.second_channel", + "relay.mode.serving.second_channel.ack_offset", + "relay.mode.serving.second_channel.data_rate_index", + "relay.mode.serving.second_channel.frequency", + "relay.mode.serving.uplink_forwarding_rules", "rx1_data_rate_offset", "rx1_delay", "rx2_data_rate_index", @@ -95,6 +261,7 @@ var MACParametersFieldPathsTopLevel = []string{ "ping_slot_frequency", "rejoin_count_periodicity", "rejoin_time_periodicity", + "relay", "rx1_data_rate_offset", "rx1_delay", "rx2_data_rate_index", @@ -149,6 +316,42 @@ var EndDeviceVersionFieldPathsNested = []string{ "default_mac_settings.desired_ping_slot_data_rate_index.value", "default_mac_settings.desired_ping_slot_frequency", "default_mac_settings.desired_ping_slot_frequency.value", + "default_mac_settings.desired_relay", + "default_mac_settings.desired_relay.mode", + "default_mac_settings.desired_relay.mode.served", + "default_mac_settings.desired_relay.mode.served.backoff", + "default_mac_settings.desired_relay.mode.served.mode", + "default_mac_settings.desired_relay.mode.served.mode.always", + "default_mac_settings.desired_relay.mode.served.mode.dynamic", + "default_mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "default_mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "default_mac_settings.desired_relay.mode.served.second_channel", + "default_mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "default_mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "default_mac_settings.desired_relay.mode.served.second_channel.frequency", + "default_mac_settings.desired_relay.mode.served.serving_device_id", + "default_mac_settings.desired_relay.mode.serving", + "default_mac_settings.desired_relay.mode.serving.cad_periodicity", + "default_mac_settings.desired_relay.mode.serving.default_channel_index", + "default_mac_settings.desired_relay.mode.serving.limits", + "default_mac_settings.desired_relay.mode.serving.limits.join_requests", + "default_mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "default_mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "default_mac_settings.desired_relay.mode.serving.limits.notifications", + "default_mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "default_mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "default_mac_settings.desired_relay.mode.serving.limits.overall", + "default_mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "default_mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "default_mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "default_mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "default_mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "default_mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "default_mac_settings.desired_relay.mode.serving.second_channel", + "default_mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "default_mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "default_mac_settings.desired_relay.mode.serving.second_channel.frequency", + "default_mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "default_mac_settings.desired_rx1_data_rate_offset", "default_mac_settings.desired_rx1_data_rate_offset.value", "default_mac_settings.desired_rx1_delay", @@ -168,6 +371,42 @@ var EndDeviceVersionFieldPathsNested = []string{ "default_mac_settings.ping_slot_frequency.value", "default_mac_settings.ping_slot_periodicity", "default_mac_settings.ping_slot_periodicity.value", + "default_mac_settings.relay", + "default_mac_settings.relay.mode", + "default_mac_settings.relay.mode.served", + "default_mac_settings.relay.mode.served.backoff", + "default_mac_settings.relay.mode.served.mode", + "default_mac_settings.relay.mode.served.mode.always", + "default_mac_settings.relay.mode.served.mode.dynamic", + "default_mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "default_mac_settings.relay.mode.served.mode.end_device_controlled", + "default_mac_settings.relay.mode.served.second_channel", + "default_mac_settings.relay.mode.served.second_channel.ack_offset", + "default_mac_settings.relay.mode.served.second_channel.data_rate_index", + "default_mac_settings.relay.mode.served.second_channel.frequency", + "default_mac_settings.relay.mode.served.serving_device_id", + "default_mac_settings.relay.mode.serving", + "default_mac_settings.relay.mode.serving.cad_periodicity", + "default_mac_settings.relay.mode.serving.default_channel_index", + "default_mac_settings.relay.mode.serving.limits", + "default_mac_settings.relay.mode.serving.limits.join_requests", + "default_mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "default_mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "default_mac_settings.relay.mode.serving.limits.notifications", + "default_mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "default_mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "default_mac_settings.relay.mode.serving.limits.overall", + "default_mac_settings.relay.mode.serving.limits.overall.bucket_size", + "default_mac_settings.relay.mode.serving.limits.overall.reload_rate", + "default_mac_settings.relay.mode.serving.limits.reset_behavior", + "default_mac_settings.relay.mode.serving.limits.uplink_messages", + "default_mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "default_mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "default_mac_settings.relay.mode.serving.second_channel", + "default_mac_settings.relay.mode.serving.second_channel.ack_offset", + "default_mac_settings.relay.mode.serving.second_channel.data_rate_index", + "default_mac_settings.relay.mode.serving.second_channel.frequency", + "default_mac_settings.relay.mode.serving.uplink_forwarding_rules", "default_mac_settings.resets_f_cnt", "default_mac_settings.resets_f_cnt.value", "default_mac_settings.rx1_data_rate_offset", @@ -289,6 +528,42 @@ var MACSettingsFieldPathsNested = []string{ "desired_ping_slot_data_rate_index.value", "desired_ping_slot_frequency", "desired_ping_slot_frequency.value", + "desired_relay", + "desired_relay.mode", + "desired_relay.mode.served", + "desired_relay.mode.served.backoff", + "desired_relay.mode.served.mode", + "desired_relay.mode.served.mode.always", + "desired_relay.mode.served.mode.dynamic", + "desired_relay.mode.served.mode.dynamic.smart_enable_level", + "desired_relay.mode.served.mode.end_device_controlled", + "desired_relay.mode.served.second_channel", + "desired_relay.mode.served.second_channel.ack_offset", + "desired_relay.mode.served.second_channel.data_rate_index", + "desired_relay.mode.served.second_channel.frequency", + "desired_relay.mode.served.serving_device_id", + "desired_relay.mode.serving", + "desired_relay.mode.serving.cad_periodicity", + "desired_relay.mode.serving.default_channel_index", + "desired_relay.mode.serving.limits", + "desired_relay.mode.serving.limits.join_requests", + "desired_relay.mode.serving.limits.join_requests.bucket_size", + "desired_relay.mode.serving.limits.join_requests.reload_rate", + "desired_relay.mode.serving.limits.notifications", + "desired_relay.mode.serving.limits.notifications.bucket_size", + "desired_relay.mode.serving.limits.notifications.reload_rate", + "desired_relay.mode.serving.limits.overall", + "desired_relay.mode.serving.limits.overall.bucket_size", + "desired_relay.mode.serving.limits.overall.reload_rate", + "desired_relay.mode.serving.limits.reset_behavior", + "desired_relay.mode.serving.limits.uplink_messages", + "desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "desired_relay.mode.serving.second_channel", + "desired_relay.mode.serving.second_channel.ack_offset", + "desired_relay.mode.serving.second_channel.data_rate_index", + "desired_relay.mode.serving.second_channel.frequency", + "desired_relay.mode.serving.uplink_forwarding_rules", "desired_rx1_data_rate_offset", "desired_rx1_data_rate_offset.value", "desired_rx1_delay", @@ -308,6 +583,42 @@ var MACSettingsFieldPathsNested = []string{ "ping_slot_frequency.value", "ping_slot_periodicity", "ping_slot_periodicity.value", + "relay", + "relay.mode", + "relay.mode.served", + "relay.mode.served.backoff", + "relay.mode.served.mode", + "relay.mode.served.mode.always", + "relay.mode.served.mode.dynamic", + "relay.mode.served.mode.dynamic.smart_enable_level", + "relay.mode.served.mode.end_device_controlled", + "relay.mode.served.second_channel", + "relay.mode.served.second_channel.ack_offset", + "relay.mode.served.second_channel.data_rate_index", + "relay.mode.served.second_channel.frequency", + "relay.mode.served.serving_device_id", + "relay.mode.serving", + "relay.mode.serving.cad_periodicity", + "relay.mode.serving.default_channel_index", + "relay.mode.serving.limits", + "relay.mode.serving.limits.join_requests", + "relay.mode.serving.limits.join_requests.bucket_size", + "relay.mode.serving.limits.join_requests.reload_rate", + "relay.mode.serving.limits.notifications", + "relay.mode.serving.limits.notifications.bucket_size", + "relay.mode.serving.limits.notifications.reload_rate", + "relay.mode.serving.limits.overall", + "relay.mode.serving.limits.overall.bucket_size", + "relay.mode.serving.limits.overall.reload_rate", + "relay.mode.serving.limits.reset_behavior", + "relay.mode.serving.limits.uplink_messages", + "relay.mode.serving.limits.uplink_messages.bucket_size", + "relay.mode.serving.limits.uplink_messages.reload_rate", + "relay.mode.serving.second_channel", + "relay.mode.serving.second_channel.ack_offset", + "relay.mode.serving.second_channel.data_rate_index", + "relay.mode.serving.second_channel.frequency", + "relay.mode.serving.uplink_forwarding_rules", "resets_f_cnt", "resets_f_cnt.value", "rx1_data_rate_offset", @@ -344,6 +655,7 @@ var MACSettingsFieldPathsTopLevel = []string{ "desired_max_eirp", "desired_ping_slot_data_rate_index", "desired_ping_slot_frequency", + "desired_relay", "desired_rx1_data_rate_offset", "desired_rx1_delay", "desired_rx2_data_rate_index", @@ -354,6 +666,7 @@ var MACSettingsFieldPathsTopLevel = []string{ "ping_slot_data_rate_index", "ping_slot_frequency", "ping_slot_periodicity", + "relay", "resets_f_cnt", "rx1_data_rate_offset", "rx1_delay", @@ -389,6 +702,42 @@ var MACStateFieldPathsNested = []string{ "current_parameters.ping_slot_frequency", "current_parameters.rejoin_count_periodicity", "current_parameters.rejoin_time_periodicity", + "current_parameters.relay", + "current_parameters.relay.mode", + "current_parameters.relay.mode.served", + "current_parameters.relay.mode.served.backoff", + "current_parameters.relay.mode.served.mode", + "current_parameters.relay.mode.served.mode.always", + "current_parameters.relay.mode.served.mode.dynamic", + "current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "current_parameters.relay.mode.served.mode.end_device_controlled", + "current_parameters.relay.mode.served.second_channel", + "current_parameters.relay.mode.served.second_channel.ack_offset", + "current_parameters.relay.mode.served.second_channel.data_rate_index", + "current_parameters.relay.mode.served.second_channel.frequency", + "current_parameters.relay.mode.served.serving_device_id", + "current_parameters.relay.mode.serving", + "current_parameters.relay.mode.serving.cad_periodicity", + "current_parameters.relay.mode.serving.default_channel_index", + "current_parameters.relay.mode.serving.limits", + "current_parameters.relay.mode.serving.limits.join_requests", + "current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "current_parameters.relay.mode.serving.limits.notifications", + "current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "current_parameters.relay.mode.serving.limits.overall", + "current_parameters.relay.mode.serving.limits.overall.bucket_size", + "current_parameters.relay.mode.serving.limits.overall.reload_rate", + "current_parameters.relay.mode.serving.limits.reset_behavior", + "current_parameters.relay.mode.serving.limits.uplink_messages", + "current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "current_parameters.relay.mode.serving.second_channel", + "current_parameters.relay.mode.serving.second_channel.ack_offset", + "current_parameters.relay.mode.serving.second_channel.data_rate_index", + "current_parameters.relay.mode.serving.second_channel.frequency", + "current_parameters.relay.mode.serving.uplink_forwarding_rules", "current_parameters.rx1_data_rate_offset", "current_parameters.rx1_delay", "current_parameters.rx2_data_rate_index", @@ -417,6 +766,42 @@ var MACStateFieldPathsNested = []string{ "desired_parameters.ping_slot_frequency", "desired_parameters.rejoin_count_periodicity", "desired_parameters.rejoin_time_periodicity", + "desired_parameters.relay", + "desired_parameters.relay.mode", + "desired_parameters.relay.mode.served", + "desired_parameters.relay.mode.served.backoff", + "desired_parameters.relay.mode.served.mode", + "desired_parameters.relay.mode.served.mode.always", + "desired_parameters.relay.mode.served.mode.dynamic", + "desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "desired_parameters.relay.mode.served.mode.end_device_controlled", + "desired_parameters.relay.mode.served.second_channel", + "desired_parameters.relay.mode.served.second_channel.ack_offset", + "desired_parameters.relay.mode.served.second_channel.data_rate_index", + "desired_parameters.relay.mode.served.second_channel.frequency", + "desired_parameters.relay.mode.served.serving_device_id", + "desired_parameters.relay.mode.serving", + "desired_parameters.relay.mode.serving.cad_periodicity", + "desired_parameters.relay.mode.serving.default_channel_index", + "desired_parameters.relay.mode.serving.limits", + "desired_parameters.relay.mode.serving.limits.join_requests", + "desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "desired_parameters.relay.mode.serving.limits.notifications", + "desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "desired_parameters.relay.mode.serving.limits.overall", + "desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "desired_parameters.relay.mode.serving.limits.reset_behavior", + "desired_parameters.relay.mode.serving.limits.uplink_messages", + "desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "desired_parameters.relay.mode.serving.second_channel", + "desired_parameters.relay.mode.serving.second_channel.ack_offset", + "desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "desired_parameters.relay.mode.serving.second_channel.frequency", + "desired_parameters.relay.mode.serving.uplink_forwarding_rules", "desired_parameters.rx1_data_rate_offset", "desired_parameters.rx1_delay", "desired_parameters.rx2_data_rate_index", @@ -456,6 +841,8 @@ var MACStateFieldPathsNested = []string{ "pending_join_request.downlink_settings.rx1_dr_offset", "pending_join_request.downlink_settings.rx2_dr", "pending_join_request.rx_delay", + "pending_relay_downlink", + "pending_relay_downlink.raw_payload", "pending_requests", "ping_slot_periodicity", "ping_slot_periodicity.value", @@ -515,6 +902,7 @@ var MACStateFieldPathsTopLevel = []string{ "lorawan_version", "pending_application_downlink", "pending_join_request", + "pending_relay_downlink", "pending_requests", "ping_slot_periodicity", "queued_join_accept", @@ -621,6 +1009,42 @@ var EndDeviceFieldPathsNested = []string{ "mac_settings.desired_ping_slot_data_rate_index.value", "mac_settings.desired_ping_slot_frequency", "mac_settings.desired_ping_slot_frequency.value", + "mac_settings.desired_relay", + "mac_settings.desired_relay.mode", + "mac_settings.desired_relay.mode.served", + "mac_settings.desired_relay.mode.served.backoff", + "mac_settings.desired_relay.mode.served.mode", + "mac_settings.desired_relay.mode.served.mode.always", + "mac_settings.desired_relay.mode.served.mode.dynamic", + "mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "mac_settings.desired_relay.mode.served.second_channel", + "mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.served.second_channel.frequency", + "mac_settings.desired_relay.mode.served.serving_device_id", + "mac_settings.desired_relay.mode.serving", + "mac_settings.desired_relay.mode.serving.cad_periodicity", + "mac_settings.desired_relay.mode.serving.default_channel_index", + "mac_settings.desired_relay.mode.serving.limits", + "mac_settings.desired_relay.mode.serving.limits.join_requests", + "mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.notifications", + "mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.overall", + "mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.desired_relay.mode.serving.second_channel", + "mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.serving.second_channel.frequency", + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "mac_settings.desired_rx1_data_rate_offset", "mac_settings.desired_rx1_data_rate_offset.value", "mac_settings.desired_rx1_delay", @@ -640,6 +1064,42 @@ var EndDeviceFieldPathsNested = []string{ "mac_settings.ping_slot_frequency.value", "mac_settings.ping_slot_periodicity", "mac_settings.ping_slot_periodicity.value", + "mac_settings.relay", + "mac_settings.relay.mode", + "mac_settings.relay.mode.served", + "mac_settings.relay.mode.served.backoff", + "mac_settings.relay.mode.served.mode", + "mac_settings.relay.mode.served.mode.always", + "mac_settings.relay.mode.served.mode.dynamic", + "mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.relay.mode.served.mode.end_device_controlled", + "mac_settings.relay.mode.served.second_channel", + "mac_settings.relay.mode.served.second_channel.ack_offset", + "mac_settings.relay.mode.served.second_channel.data_rate_index", + "mac_settings.relay.mode.served.second_channel.frequency", + "mac_settings.relay.mode.served.serving_device_id", + "mac_settings.relay.mode.serving", + "mac_settings.relay.mode.serving.cad_periodicity", + "mac_settings.relay.mode.serving.default_channel_index", + "mac_settings.relay.mode.serving.limits", + "mac_settings.relay.mode.serving.limits.join_requests", + "mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.relay.mode.serving.limits.notifications", + "mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.relay.mode.serving.limits.overall", + "mac_settings.relay.mode.serving.limits.overall.bucket_size", + "mac_settings.relay.mode.serving.limits.overall.reload_rate", + "mac_settings.relay.mode.serving.limits.reset_behavior", + "mac_settings.relay.mode.serving.limits.uplink_messages", + "mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.relay.mode.serving.second_channel", + "mac_settings.relay.mode.serving.second_channel.ack_offset", + "mac_settings.relay.mode.serving.second_channel.data_rate_index", + "mac_settings.relay.mode.serving.second_channel.frequency", + "mac_settings.relay.mode.serving.uplink_forwarding_rules", "mac_settings.resets_f_cnt", "mac_settings.resets_f_cnt.value", "mac_settings.rx1_data_rate_offset", @@ -683,6 +1143,42 @@ var EndDeviceFieldPathsNested = []string{ "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay", + "mac_state.current_parameters.relay.mode", + "mac_state.current_parameters.relay.mode.served", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -711,6 +1207,42 @@ var EndDeviceFieldPathsNested = []string{ "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay", + "mac_state.desired_parameters.relay.mode", + "mac_state.desired_parameters.relay.mode.served", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -750,6 +1282,8 @@ var EndDeviceFieldPathsNested = []string{ "mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "mac_state.pending_join_request.downlink_settings.rx2_dr", "mac_state.pending_join_request.rx_delay", + "mac_state.pending_relay_downlink", + "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", "mac_state.ping_slot_periodicity", "mac_state.ping_slot_periodicity.value", @@ -825,6 +1359,42 @@ var EndDeviceFieldPathsNested = []string{ "pending_mac_state.current_parameters.ping_slot_frequency", "pending_mac_state.current_parameters.rejoin_count_periodicity", "pending_mac_state.current_parameters.rejoin_time_periodicity", + "pending_mac_state.current_parameters.relay", + "pending_mac_state.current_parameters.relay.mode", + "pending_mac_state.current_parameters.relay.mode.served", + "pending_mac_state.current_parameters.relay.mode.served.backoff", + "pending_mac_state.current_parameters.relay.mode.served.mode", + "pending_mac_state.current_parameters.relay.mode.served.mode.always", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.current_parameters.relay.mode.served.second_channel", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.current_parameters.relay.mode.serving", + "pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.limits", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.current_parameters.rx1_data_rate_offset", "pending_mac_state.current_parameters.rx1_delay", "pending_mac_state.current_parameters.rx2_data_rate_index", @@ -853,6 +1423,42 @@ var EndDeviceFieldPathsNested = []string{ "pending_mac_state.desired_parameters.ping_slot_frequency", "pending_mac_state.desired_parameters.rejoin_count_periodicity", "pending_mac_state.desired_parameters.rejoin_time_periodicity", + "pending_mac_state.desired_parameters.relay", + "pending_mac_state.desired_parameters.relay.mode", + "pending_mac_state.desired_parameters.relay.mode.served", + "pending_mac_state.desired_parameters.relay.mode.served.backoff", + "pending_mac_state.desired_parameters.relay.mode.served.mode", + "pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.desired_parameters.relay.mode.serving", + "pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.limits", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.desired_parameters.rx1_data_rate_offset", "pending_mac_state.desired_parameters.rx1_delay", "pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -892,6 +1498,8 @@ var EndDeviceFieldPathsNested = []string{ "pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "pending_mac_state.pending_join_request.rx_delay", + "pending_mac_state.pending_relay_downlink", + "pending_mac_state.pending_relay_downlink.raw_payload", "pending_mac_state.pending_requests", "pending_mac_state.ping_slot_periodicity", "pending_mac_state.ping_slot_periodicity.value", @@ -1180,6 +1788,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device.mac_settings.desired_ping_slot_frequency", "end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device.mac_settings.desired_relay", + "end_device.mac_settings.desired_relay.mode", + "end_device.mac_settings.desired_relay.mode.served", + "end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device.mac_settings.desired_relay.mode.served.mode", + "end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device.mac_settings.desired_relay.mode.serving", + "end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.desired_rx1_data_rate_offset", "end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device.mac_settings.desired_rx1_delay", @@ -1199,6 +1843,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.ping_slot_frequency.value", "end_device.mac_settings.ping_slot_periodicity", "end_device.mac_settings.ping_slot_periodicity.value", + "end_device.mac_settings.relay", + "end_device.mac_settings.relay.mode", + "end_device.mac_settings.relay.mode.served", + "end_device.mac_settings.relay.mode.served.backoff", + "end_device.mac_settings.relay.mode.served.mode", + "end_device.mac_settings.relay.mode.served.mode.always", + "end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.relay.mode.served.second_channel", + "end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device.mac_settings.relay.mode.serving", + "end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device.mac_settings.relay.mode.serving.limits", + "end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.relay.mode.serving.second_channel", + "end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.resets_f_cnt", "end_device.mac_settings.resets_f_cnt.value", "end_device.mac_settings.rx1_data_rate_offset", @@ -1242,6 +1922,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.current_parameters.ping_slot_frequency", "end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device.mac_state.current_parameters.relay", + "end_device.mac_state.current_parameters.relay.mode", + "end_device.mac_state.current_parameters.relay.mode.served", + "end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.current_parameters.relay.mode.serving", + "end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device.mac_state.current_parameters.rx1_delay", "end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -1270,6 +1986,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.mac_state.desired_parameters.relay", + "end_device.mac_state.desired_parameters.relay.mode", + "end_device.mac_state.desired_parameters.relay.mode.served", + "end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device.mac_state.desired_parameters.rx1_delay", "end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -1309,6 +2061,8 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.mac_state.pending_join_request.rx_delay", + "end_device.mac_state.pending_relay_downlink", + "end_device.mac_state.pending_relay_downlink.raw_payload", "end_device.mac_state.pending_requests", "end_device.mac_state.ping_slot_periodicity", "end_device.mac_state.ping_slot_periodicity.value", @@ -1384,6 +2138,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.current_parameters.relay", + "end_device.pending_mac_state.current_parameters.relay.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.current_parameters.rx1_delay", "end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -1412,6 +2202,42 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.desired_parameters.relay", + "end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -1451,6 +2277,8 @@ var CreateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device.pending_mac_state.pending_relay_downlink", + "end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device.pending_mac_state.pending_requests", "end_device.pending_mac_state.ping_slot_periodicity", "end_device.pending_mac_state.ping_slot_periodicity.value", @@ -1671,6 +2499,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device.mac_settings.desired_ping_slot_frequency", "end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device.mac_settings.desired_relay", + "end_device.mac_settings.desired_relay.mode", + "end_device.mac_settings.desired_relay.mode.served", + "end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device.mac_settings.desired_relay.mode.served.mode", + "end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device.mac_settings.desired_relay.mode.serving", + "end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.desired_rx1_data_rate_offset", "end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device.mac_settings.desired_rx1_delay", @@ -1690,6 +2554,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.ping_slot_frequency.value", "end_device.mac_settings.ping_slot_periodicity", "end_device.mac_settings.ping_slot_periodicity.value", + "end_device.mac_settings.relay", + "end_device.mac_settings.relay.mode", + "end_device.mac_settings.relay.mode.served", + "end_device.mac_settings.relay.mode.served.backoff", + "end_device.mac_settings.relay.mode.served.mode", + "end_device.mac_settings.relay.mode.served.mode.always", + "end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.relay.mode.served.second_channel", + "end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device.mac_settings.relay.mode.serving", + "end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device.mac_settings.relay.mode.serving.limits", + "end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.relay.mode.serving.second_channel", + "end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.resets_f_cnt", "end_device.mac_settings.resets_f_cnt.value", "end_device.mac_settings.rx1_data_rate_offset", @@ -1733,6 +2633,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.current_parameters.ping_slot_frequency", "end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device.mac_state.current_parameters.relay", + "end_device.mac_state.current_parameters.relay.mode", + "end_device.mac_state.current_parameters.relay.mode.served", + "end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.current_parameters.relay.mode.serving", + "end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device.mac_state.current_parameters.rx1_delay", "end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -1761,6 +2697,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.mac_state.desired_parameters.relay", + "end_device.mac_state.desired_parameters.relay.mode", + "end_device.mac_state.desired_parameters.relay.mode.served", + "end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device.mac_state.desired_parameters.rx1_delay", "end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -1800,6 +2772,8 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.mac_state.pending_join_request.rx_delay", + "end_device.mac_state.pending_relay_downlink", + "end_device.mac_state.pending_relay_downlink.raw_payload", "end_device.mac_state.pending_requests", "end_device.mac_state.ping_slot_periodicity", "end_device.mac_state.ping_slot_periodicity.value", @@ -1875,6 +2849,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.current_parameters.relay", + "end_device.pending_mac_state.current_parameters.relay.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.current_parameters.rx1_delay", "end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -1903,6 +2913,42 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.desired_parameters.relay", + "end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -1942,6 +2988,8 @@ var UpdateEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device.pending_mac_state.pending_relay_downlink", + "end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device.pending_mac_state.pending_requests", "end_device.pending_mac_state.ping_slot_periodicity", "end_device.pending_mac_state.ping_slot_periodicity.value", @@ -2211,6 +3259,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device.mac_settings.desired_ping_slot_frequency", "end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device.mac_settings.desired_relay", + "end_device.mac_settings.desired_relay.mode", + "end_device.mac_settings.desired_relay.mode.served", + "end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device.mac_settings.desired_relay.mode.served.mode", + "end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device.mac_settings.desired_relay.mode.serving", + "end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.desired_rx1_data_rate_offset", "end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device.mac_settings.desired_rx1_delay", @@ -2230,6 +3314,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_settings.ping_slot_frequency.value", "end_device.mac_settings.ping_slot_periodicity", "end_device.mac_settings.ping_slot_periodicity.value", + "end_device.mac_settings.relay", + "end_device.mac_settings.relay.mode", + "end_device.mac_settings.relay.mode.served", + "end_device.mac_settings.relay.mode.served.backoff", + "end_device.mac_settings.relay.mode.served.mode", + "end_device.mac_settings.relay.mode.served.mode.always", + "end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.relay.mode.served.second_channel", + "end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device.mac_settings.relay.mode.serving", + "end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device.mac_settings.relay.mode.serving.limits", + "end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.relay.mode.serving.second_channel", + "end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.resets_f_cnt", "end_device.mac_settings.resets_f_cnt.value", "end_device.mac_settings.rx1_data_rate_offset", @@ -2273,6 +3393,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.current_parameters.ping_slot_frequency", "end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device.mac_state.current_parameters.relay", + "end_device.mac_state.current_parameters.relay.mode", + "end_device.mac_state.current_parameters.relay.mode.served", + "end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.current_parameters.relay.mode.serving", + "end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device.mac_state.current_parameters.rx1_delay", "end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -2301,6 +3457,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.mac_state.desired_parameters.relay", + "end_device.mac_state.desired_parameters.relay.mode", + "end_device.mac_state.desired_parameters.relay.mode.served", + "end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device.mac_state.desired_parameters.rx1_delay", "end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -2340,6 +3532,8 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.mac_state.pending_join_request.rx_delay", + "end_device.mac_state.pending_relay_downlink", + "end_device.mac_state.pending_relay_downlink.raw_payload", "end_device.mac_state.pending_requests", "end_device.mac_state.ping_slot_periodicity", "end_device.mac_state.ping_slot_periodicity.value", @@ -2415,6 +3609,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.current_parameters.relay", + "end_device.pending_mac_state.current_parameters.relay.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.current_parameters.rx1_delay", "end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -2443,6 +3673,42 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.desired_parameters.relay", + "end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -2482,6 +3748,8 @@ var SetEndDeviceRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device.pending_mac_state.pending_relay_downlink", + "end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device.pending_mac_state.pending_requests", "end_device.pending_mac_state.ping_slot_periodicity", "end_device.pending_mac_state.ping_slot_periodicity.value", @@ -2719,6 +3987,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device.mac_settings.desired_ping_slot_frequency", "end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device.mac_settings.desired_relay", + "end_device.mac_settings.desired_relay.mode", + "end_device.mac_settings.desired_relay.mode.served", + "end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device.mac_settings.desired_relay.mode.served.mode", + "end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device.mac_settings.desired_relay.mode.serving", + "end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.desired_rx1_data_rate_offset", "end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device.mac_settings.desired_rx1_delay", @@ -2738,6 +4042,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_settings.ping_slot_frequency.value", "end_device.mac_settings.ping_slot_periodicity", "end_device.mac_settings.ping_slot_periodicity.value", + "end_device.mac_settings.relay", + "end_device.mac_settings.relay.mode", + "end_device.mac_settings.relay.mode.served", + "end_device.mac_settings.relay.mode.served.backoff", + "end_device.mac_settings.relay.mode.served.mode", + "end_device.mac_settings.relay.mode.served.mode.always", + "end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.relay.mode.served.second_channel", + "end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device.mac_settings.relay.mode.serving", + "end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device.mac_settings.relay.mode.serving.limits", + "end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.relay.mode.serving.second_channel", + "end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.resets_f_cnt", "end_device.mac_settings.resets_f_cnt.value", "end_device.mac_settings.rx1_data_rate_offset", @@ -2781,6 +4121,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_state.current_parameters.ping_slot_frequency", "end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device.mac_state.current_parameters.relay", + "end_device.mac_state.current_parameters.relay.mode", + "end_device.mac_state.current_parameters.relay.mode.served", + "end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.current_parameters.relay.mode.serving", + "end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device.mac_state.current_parameters.rx1_delay", "end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -2809,6 +4185,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.mac_state.desired_parameters.relay", + "end_device.mac_state.desired_parameters.relay.mode", + "end_device.mac_state.desired_parameters.relay.mode.served", + "end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device.mac_state.desired_parameters.rx1_delay", "end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -2848,6 +4260,8 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.mac_state.pending_join_request.rx_delay", + "end_device.mac_state.pending_relay_downlink", + "end_device.mac_state.pending_relay_downlink.raw_payload", "end_device.mac_state.pending_requests", "end_device.mac_state.ping_slot_periodicity", "end_device.mac_state.ping_slot_periodicity.value", @@ -2923,6 +4337,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.current_parameters.relay", + "end_device.pending_mac_state.current_parameters.relay.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.current_parameters.rx1_delay", "end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -2951,6 +4401,42 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.desired_parameters.relay", + "end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -2990,6 +4476,8 @@ var EndDeviceTemplateFieldPathsNested = []string{ "end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device.pending_mac_state.pending_relay_downlink", + "end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device.pending_mac_state.pending_requests", "end_device.pending_mac_state.ping_slot_periodicity", "end_device.pending_mac_state.ping_slot_periodicity.value", @@ -3442,6 +4930,7 @@ var MACState_UplinkMessage_RxMetadataFieldPathsNested = []string{ "gateway_ids.eui", "gateway_ids.gateway_id", "packet_broker", + "relay", "snr", "uplink_token", } @@ -3451,11 +4940,14 @@ var MACState_UplinkMessage_RxMetadataFieldPathsTopLevel = []string{ "downlink_path_constraint", "gateway_ids", "packet_broker", + "relay", "snr", "uplink_token", } var MACState_UplinkMessage_RxMetadata_PacketBrokerMetadataFieldPathsNested []string var MACState_UplinkMessage_RxMetadata_PacketBrokerMetadataFieldPathsTopLevel []string +var MACState_UplinkMessage_RxMetadata_RelayMetadataFieldPathsNested []string +var MACState_UplinkMessage_RxMetadata_RelayMetadataFieldPathsTopLevel []string var MACState_DownlinkMessage_MessageFieldPathsNested = []string{ "m_hdr", "m_hdr.m_type", diff --git a/pkg/ttnpb/end_device.pb.setters.fm.go b/pkg/ttnpb/end_device.pb.setters.fm.go index 542781d369..a3d903fb27 100644 --- a/pkg/ttnpb/end_device.pb.setters.fm.go +++ b/pkg/ttnpb/end_device.pb.setters.fm.go @@ -128,6 +128,569 @@ func (dst *BoolValue) SetFields(src *BoolValue, paths ...string) error { return nil } +func (dst *ServingRelayForwardingLimits) SetFields(src *ServingRelayForwardingLimits, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "reset_behavior": + if len(subs) > 0 { + return fmt.Errorf("'reset_behavior' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ResetBehavior = src.ResetBehavior + } else { + dst.ResetBehavior = 0 + } + case "join_requests": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.JoinRequests == nil) && dst.JoinRequests == nil { + continue + } + if src != nil { + newSrc = src.JoinRequests + } + if dst.JoinRequests != nil { + newDst = dst.JoinRequests + } else { + newDst = &RelayForwardLimits{} + dst.JoinRequests = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.JoinRequests = src.JoinRequests + } else { + dst.JoinRequests = nil + } + } + case "notifications": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.Notifications == nil) && dst.Notifications == nil { + continue + } + if src != nil { + newSrc = src.Notifications + } + if dst.Notifications != nil { + newDst = dst.Notifications + } else { + newDst = &RelayForwardLimits{} + dst.Notifications = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Notifications = src.Notifications + } else { + dst.Notifications = nil + } + } + case "uplink_messages": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.UplinkMessages == nil) && dst.UplinkMessages == nil { + continue + } + if src != nil { + newSrc = src.UplinkMessages + } + if dst.UplinkMessages != nil { + newDst = dst.UplinkMessages + } else { + newDst = &RelayForwardLimits{} + dst.UplinkMessages = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.UplinkMessages = src.UplinkMessages + } else { + dst.UplinkMessages = nil + } + } + case "overall": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.Overall == nil) && dst.Overall == nil { + continue + } + if src != nil { + newSrc = src.Overall + } + if dst.Overall != nil { + newDst = dst.Overall + } else { + newDst = &RelayForwardLimits{} + dst.Overall = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Overall = src.Overall + } else { + dst.Overall = nil + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayUplinkForwardingRule) SetFields(src *RelayUplinkForwardingRule, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "limits": + if len(subs) > 0 { + var newDst, newSrc *RelayUplinkForwardLimits + if (src == nil || src.Limits == nil) && dst.Limits == nil { + continue + } + if src != nil { + newSrc = src.Limits + } + if dst.Limits != nil { + newDst = dst.Limits + } else { + newDst = &RelayUplinkForwardLimits{} + dst.Limits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Limits = src.Limits + } else { + dst.Limits = nil + } + } + case "last_w_f_cnt": + if len(subs) > 0 { + return fmt.Errorf("'last_w_f_cnt' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.LastWFCnt = src.LastWFCnt + } else { + var zero uint32 + dst.LastWFCnt = zero + } + case "device_id": + if len(subs) > 0 { + return fmt.Errorf("'device_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DeviceId = src.DeviceId + } else { + var zero string + dst.DeviceId = zero + } + case "session_key_id": + if len(subs) > 0 { + return fmt.Errorf("'session_key_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.SessionKeyId = src.SessionKeyId + } else { + dst.SessionKeyId = nil + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *ServingRelayParameters) SetFields(src *ServingRelayParameters, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "second_channel": + if len(subs) > 0 { + var newDst, newSrc *RelaySecondChannel + if (src == nil || src.SecondChannel == nil) && dst.SecondChannel == nil { + continue + } + if src != nil { + newSrc = src.SecondChannel + } + if dst.SecondChannel != nil { + newDst = dst.SecondChannel + } else { + newDst = &RelaySecondChannel{} + dst.SecondChannel = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.SecondChannel = src.SecondChannel + } else { + dst.SecondChannel = nil + } + } + case "default_channel_index": + if len(subs) > 0 { + return fmt.Errorf("'default_channel_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DefaultChannelIndex = src.DefaultChannelIndex + } else { + var zero uint32 + dst.DefaultChannelIndex = zero + } + case "cad_periodicity": + if len(subs) > 0 { + return fmt.Errorf("'cad_periodicity' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.CadPeriodicity = src.CadPeriodicity + } else { + dst.CadPeriodicity = 0 + } + case "uplink_forwarding_rules": + if len(subs) > 0 { + return fmt.Errorf("'uplink_forwarding_rules' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.UplinkForwardingRules = src.UplinkForwardingRules + } else { + dst.UplinkForwardingRules = nil + } + case "limits": + if len(subs) > 0 { + var newDst, newSrc *ServingRelayForwardingLimits + if (src == nil || src.Limits == nil) && dst.Limits == nil { + continue + } + if src != nil { + newSrc = src.Limits + } + if dst.Limits != nil { + newDst = dst.Limits + } else { + newDst = &ServingRelayForwardingLimits{} + dst.Limits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Limits = src.Limits + } else { + dst.Limits = nil + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *ServedRelayParameters) SetFields(src *ServedRelayParameters, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "backoff": + if len(subs) > 0 { + return fmt.Errorf("'backoff' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Backoff = src.Backoff + } else { + var zero uint32 + dst.Backoff = zero + } + case "second_channel": + if len(subs) > 0 { + var newDst, newSrc *RelaySecondChannel + if (src == nil || src.SecondChannel == nil) && dst.SecondChannel == nil { + continue + } + if src != nil { + newSrc = src.SecondChannel + } + if dst.SecondChannel != nil { + newDst = dst.SecondChannel + } else { + newDst = &RelaySecondChannel{} + dst.SecondChannel = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.SecondChannel = src.SecondChannel + } else { + dst.SecondChannel = nil + } + } + case "serving_device_id": + if len(subs) > 0 { + return fmt.Errorf("'serving_device_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ServingDeviceId = src.ServingDeviceId + } else { + var zero string + dst.ServingDeviceId = zero + } + + case "mode": + if len(subs) == 0 && src == nil { + dst.Mode = nil + continue + } else if len(subs) == 0 { + dst.Mode = src.Mode + continue + } + + subPathMap := _processPaths(subs) + if len(subPathMap) > 1 { + return fmt.Errorf("more than one field specified for oneof field '%s'", name) + } + for oneofName, oneofSubs := range subPathMap { + switch oneofName { + case "always": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*ServedRelayParameters_Always) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'always', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*ServedRelayParameters_Always) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'always', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceAlwaysMode + if srcTypeOk { + newSrc = src.Mode.(*ServedRelayParameters_Always).Always + } + if dstTypeOk { + newDst = dst.Mode.(*ServedRelayParameters_Always).Always + } else if srcTypeOk { + newDst = &RelayEndDeviceAlwaysMode{} + dst.Mode = &ServedRelayParameters_Always{Always: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + case "dynamic": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*ServedRelayParameters_Dynamic) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'dynamic', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*ServedRelayParameters_Dynamic) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'dynamic', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceDynamicMode + if srcTypeOk { + newSrc = src.Mode.(*ServedRelayParameters_Dynamic).Dynamic + } + if dstTypeOk { + newDst = dst.Mode.(*ServedRelayParameters_Dynamic).Dynamic + } else if srcTypeOk { + newDst = &RelayEndDeviceDynamicMode{} + dst.Mode = &ServedRelayParameters_Dynamic{Dynamic: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + case "end_device_controlled": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*ServedRelayParameters_EndDeviceControlled) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'end_device_controlled', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*ServedRelayParameters_EndDeviceControlled) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'end_device_controlled', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceControlledMode + if srcTypeOk { + newSrc = src.Mode.(*ServedRelayParameters_EndDeviceControlled).EndDeviceControlled + } + if dstTypeOk { + newDst = dst.Mode.(*ServedRelayParameters_EndDeviceControlled).EndDeviceControlled + } else if srcTypeOk { + newDst = &RelayEndDeviceControlledMode{} + dst.Mode = &ServedRelayParameters_EndDeviceControlled{EndDeviceControlled: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + + default: + return fmt.Errorf("invalid oneof field: '%s.%s'", name, oneofName) + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayParameters) SetFields(src *RelayParameters, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + + case "mode": + if len(subs) == 0 && src == nil { + dst.Mode = nil + continue + } else if len(subs) == 0 { + dst.Mode = src.Mode + continue + } + + subPathMap := _processPaths(subs) + if len(subPathMap) > 1 { + return fmt.Errorf("more than one field specified for oneof field '%s'", name) + } + for oneofName, oneofSubs := range subPathMap { + switch oneofName { + case "serving": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*RelayParameters_Serving) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'serving', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*RelayParameters_Serving) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'serving', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *ServingRelayParameters + if srcTypeOk { + newSrc = src.Mode.(*RelayParameters_Serving).Serving + } + if dstTypeOk { + newDst = dst.Mode.(*RelayParameters_Serving).Serving + } else if srcTypeOk { + newDst = &ServingRelayParameters{} + dst.Mode = &RelayParameters_Serving{Serving: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + case "served": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*RelayParameters_Served) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'served', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*RelayParameters_Served) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'served', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *ServedRelayParameters + if srcTypeOk { + newSrc = src.Mode.(*RelayParameters_Served).Served + } + if dstTypeOk { + newDst = dst.Mode.(*RelayParameters_Served).Served + } else if srcTypeOk { + newDst = &ServedRelayParameters{} + dst.Mode = &RelayParameters_Served{Served: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + + default: + return fmt.Errorf("invalid oneof field: '%s.%s'", name, oneofName) + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + func (dst *MACParameters) SetFields(src *MACParameters, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { @@ -417,6 +980,31 @@ func (dst *MACParameters) SetFields(src *MACParameters, paths ...string) error { dst.PingSlotDataRateIndexValue = nil } } + case "relay": + if len(subs) > 0 { + var newDst, newSrc *RelayParameters + if (src == nil || src.Relay == nil) && dst.Relay == nil { + continue + } + if src != nil { + newSrc = src.Relay + } + if dst.Relay != nil { + newDst = dst.Relay + } else { + newDst = &RelayParameters{} + dst.Relay = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Relay = src.Relay + } else { + dst.Relay = nil + } + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1489,6 +2077,56 @@ func (dst *MACSettings) SetFields(src *MACSettings, paths ...string) error { dst.ScheduleDownlinks = nil } } + case "relay": + if len(subs) > 0 { + var newDst, newSrc *RelayParameters + if (src == nil || src.Relay == nil) && dst.Relay == nil { + continue + } + if src != nil { + newSrc = src.Relay + } + if dst.Relay != nil { + newDst = dst.Relay + } else { + newDst = &RelayParameters{} + dst.Relay = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Relay = src.Relay + } else { + dst.Relay = nil + } + } + case "desired_relay": + if len(subs) > 0 { + var newDst, newSrc *RelayParameters + if (src == nil || src.DesiredRelay == nil) && dst.DesiredRelay == nil { + continue + } + if src != nil { + newSrc = src.DesiredRelay + } + if dst.DesiredRelay != nil { + newDst = dst.DesiredRelay + } else { + newDst = &RelayParameters{} + dst.DesiredRelay = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.DesiredRelay = src.DesiredRelay + } else { + dst.DesiredRelay = nil + } + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -1806,6 +2444,31 @@ func (dst *MACState) SetFields(src *MACState, paths ...string) error { } else { dst.RecentMacCommandIdentifiers = nil } + case "pending_relay_downlink": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardDownlinkReq + if (src == nil || src.PendingRelayDownlink == nil) && dst.PendingRelayDownlink == nil { + continue + } + if src != nil { + newSrc = src.PendingRelayDownlink + } + if dst.PendingRelayDownlink != nil { + newDst = dst.PendingRelayDownlink + } else { + newDst = &RelayForwardDownlinkReq{} + dst.PendingRelayDownlink = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.PendingRelayDownlink = src.PendingRelayDownlink + } else { + dst.PendingRelayDownlink = nil + } + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -4058,6 +4721,31 @@ func (dst *MACState_UplinkMessage_RxMetadata) SetFields(src *MACState_UplinkMess dst.PacketBroker = nil } } + case "relay": + if len(subs) > 0 { + var newDst, newSrc *MACState_UplinkMessage_RxMetadata_RelayMetadata + if (src == nil || src.Relay == nil) && dst.Relay == nil { + continue + } + if src != nil { + newSrc = src.Relay + } + if dst.Relay != nil { + newDst = dst.Relay + } else { + newDst = &MACState_UplinkMessage_RxMetadata_RelayMetadata{} + dst.Relay = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Relay = src.Relay + } else { + dst.Relay = nil + } + } default: return fmt.Errorf("invalid field: '%s'", name) @@ -4073,6 +4761,13 @@ func (dst *MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata) SetFields(src return nil } +func (dst *MACState_UplinkMessage_RxMetadata_RelayMetadata) SetFields(src *MACState_UplinkMessage_RxMetadata_RelayMetadata, paths ...string) error { + if len(paths) != 0 { + return fmt.Errorf("message MACState_UplinkMessage_RxMetadata_RelayMetadata has no fields, but paths %s were specified", paths) + } + return nil +} + func (dst *MACState_DownlinkMessage_Message) SetFields(src *MACState_DownlinkMessage_Message, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { diff --git a/pkg/ttnpb/end_device.pb.validate.go b/pkg/ttnpb/end_device.pb.validate.go index 45654db403..f9f236ff2b 100644 --- a/pkg/ttnpb/end_device.pb.validate.go +++ b/pkg/ttnpb/end_device.pb.validate.go @@ -261,6 +261,718 @@ var _ interface { ErrorName() string } = BoolValueValidationError{} +// ValidateFields checks the field values on ServingRelayForwardingLimits with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *ServingRelayForwardingLimits) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ServingRelayForwardingLimitsFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "reset_behavior": + // no validation rules for ResetBehavior + case "join_requests": + + if v, ok := interface{}(m.GetJoinRequests()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayForwardingLimitsValidationError{ + field: "join_requests", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "notifications": + + if v, ok := interface{}(m.GetNotifications()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayForwardingLimitsValidationError{ + field: "notifications", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "uplink_messages": + + if v, ok := interface{}(m.GetUplinkMessages()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayForwardingLimitsValidationError{ + field: "uplink_messages", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "overall": + + if v, ok := interface{}(m.GetOverall()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayForwardingLimitsValidationError{ + field: "overall", + reason: "embedded message failed validation", + cause: err, + } + } + } + + default: + return ServingRelayForwardingLimitsValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ServingRelayForwardingLimitsValidationError is the validation error returned +// by ServingRelayForwardingLimits.ValidateFields if the designated +// constraints aren't met. +type ServingRelayForwardingLimitsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ServingRelayForwardingLimitsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ServingRelayForwardingLimitsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ServingRelayForwardingLimitsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ServingRelayForwardingLimitsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ServingRelayForwardingLimitsValidationError) ErrorName() string { + return "ServingRelayForwardingLimitsValidationError" +} + +// Error satisfies the builtin error interface +func (e ServingRelayForwardingLimitsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sServingRelayForwardingLimits.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ServingRelayForwardingLimitsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ServingRelayForwardingLimitsValidationError{} + +// ValidateFields checks the field values on RelayUplinkForwardingRule with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayUplinkForwardingRule) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayUplinkForwardingRuleFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "limits": + + if v, ok := interface{}(m.GetLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RelayUplinkForwardingRuleValidationError{ + field: "limits", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "last_w_f_cnt": + // no validation rules for LastWFCnt + case "device_id": + + if m.GetDeviceId() != "" { + + if utf8.RuneCountInString(m.GetDeviceId()) > 36 { + return RelayUplinkForwardingRuleValidationError{ + field: "device_id", + reason: "value length must be at most 36 runes", + } + } + + if !_RelayUplinkForwardingRule_DeviceId_Pattern.MatchString(m.GetDeviceId()) { + return RelayUplinkForwardingRuleValidationError{ + field: "device_id", + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + } + + case "session_key_id": + // no validation rules for SessionKeyId + default: + return RelayUplinkForwardingRuleValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayUplinkForwardingRuleValidationError is the validation error returned by +// RelayUplinkForwardingRule.ValidateFields if the designated constraints +// aren't met. +type RelayUplinkForwardingRuleValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayUplinkForwardingRuleValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayUplinkForwardingRuleValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayUplinkForwardingRuleValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayUplinkForwardingRuleValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayUplinkForwardingRuleValidationError) ErrorName() string { + return "RelayUplinkForwardingRuleValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayUplinkForwardingRuleValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayUplinkForwardingRule.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayUplinkForwardingRuleValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayUplinkForwardingRuleValidationError{} + +var _RelayUplinkForwardingRule_DeviceId_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + +// ValidateFields checks the field values on ServingRelayParameters with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *ServingRelayParameters) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ServingRelayParametersFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "second_channel": + + if v, ok := interface{}(m.GetSecondChannel()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayParametersValidationError{ + field: "second_channel", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "default_channel_index": + + if m.GetDefaultChannelIndex() > 255 { + return ServingRelayParametersValidationError{ + field: "default_channel_index", + reason: "value must be less than or equal to 255", + } + } + + case "cad_periodicity": + + if _, ok := RelayCADPeriodicity_name[int32(m.GetCadPeriodicity())]; !ok { + return ServingRelayParametersValidationError{ + field: "cad_periodicity", + reason: "value must be one of the defined enum values", + } + } + + case "uplink_forwarding_rules": + + if len(m.GetUplinkForwardingRules()) > 16 { + return ServingRelayParametersValidationError{ + field: "uplink_forwarding_rules", + reason: "value must contain no more than 16 item(s)", + } + } + + for idx, item := range m.GetUplinkForwardingRules() { + _, _ = idx, item + + if v, ok := interface{}(item).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayParametersValidationError{ + field: fmt.Sprintf("uplink_forwarding_rules[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + case "limits": + + if v, ok := interface{}(m.GetLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServingRelayParametersValidationError{ + field: "limits", + reason: "embedded message failed validation", + cause: err, + } + } + } + + default: + return ServingRelayParametersValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ServingRelayParametersValidationError is the validation error returned by +// ServingRelayParameters.ValidateFields if the designated constraints aren't met. +type ServingRelayParametersValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ServingRelayParametersValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ServingRelayParametersValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ServingRelayParametersValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ServingRelayParametersValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ServingRelayParametersValidationError) ErrorName() string { + return "ServingRelayParametersValidationError" +} + +// Error satisfies the builtin error interface +func (e ServingRelayParametersValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sServingRelayParameters.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ServingRelayParametersValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ServingRelayParametersValidationError{} + +// ValidateFields checks the field values on ServedRelayParameters with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *ServedRelayParameters) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ServedRelayParametersFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "backoff": + + if m.GetBackoff() > 63 { + return ServedRelayParametersValidationError{ + field: "backoff", + reason: "value must be less than or equal to 63", + } + } + + case "second_channel": + + if v, ok := interface{}(m.GetSecondChannel()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServedRelayParametersValidationError{ + field: "second_channel", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "serving_device_id": + + if utf8.RuneCountInString(m.GetServingDeviceId()) > 36 { + return ServedRelayParametersValidationError{ + field: "serving_device_id", + reason: "value length must be at most 36 runes", + } + } + + if !_ServedRelayParameters_ServingDeviceId_Pattern.MatchString(m.GetServingDeviceId()) { + return ServedRelayParametersValidationError{ + field: "serving_device_id", + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + case "mode": + if m.Mode == nil { + return ServedRelayParametersValidationError{ + field: "mode", + reason: "value is required", + } + } + if len(subs) == 0 { + subs = []string{ + "always", "dynamic", "end_device_controlled", + } + } + for name, subs := range _processPaths(subs) { + _ = subs + switch name { + case "always": + w, ok := m.Mode.(*ServedRelayParameters_Always) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetAlways()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServedRelayParametersValidationError{ + field: "always", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dynamic": + w, ok := m.Mode.(*ServedRelayParameters_Dynamic) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDynamic()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServedRelayParametersValidationError{ + field: "dynamic", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "end_device_controlled": + w, ok := m.Mode.(*ServedRelayParameters_EndDeviceControlled) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetEndDeviceControlled()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return ServedRelayParametersValidationError{ + field: "end_device_controlled", + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + default: + return ServedRelayParametersValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ServedRelayParametersValidationError is the validation error returned by +// ServedRelayParameters.ValidateFields if the designated constraints aren't met. +type ServedRelayParametersValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ServedRelayParametersValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ServedRelayParametersValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ServedRelayParametersValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ServedRelayParametersValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ServedRelayParametersValidationError) ErrorName() string { + return "ServedRelayParametersValidationError" +} + +// Error satisfies the builtin error interface +func (e ServedRelayParametersValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sServedRelayParameters.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ServedRelayParametersValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ServedRelayParametersValidationError{} + +var _ServedRelayParameters_ServingDeviceId_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + +// ValidateFields checks the field values on RelayParameters with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayParameters) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayParametersFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "mode": + if m.Mode == nil { + return RelayParametersValidationError{ + field: "mode", + reason: "value is required", + } + } + if len(subs) == 0 { + subs = []string{ + "serving", "served", + } + } + for name, subs := range _processPaths(subs) { + _ = subs + switch name { + case "serving": + w, ok := m.Mode.(*RelayParameters_Serving) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetServing()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RelayParametersValidationError{ + field: "serving", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "served": + w, ok := m.Mode.(*RelayParameters_Served) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetServed()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RelayParametersValidationError{ + field: "served", + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + } + default: + return RelayParametersValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayParametersValidationError is the validation error returned by +// RelayParameters.ValidateFields if the designated constraints aren't met. +type RelayParametersValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayParametersValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayParametersValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayParametersValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayParametersValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayParametersValidationError) ErrorName() string { return "RelayParametersValidationError" } + +// Error satisfies the builtin error interface +func (e RelayParametersValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayParameters.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayParametersValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayParametersValidationError{} + // ValidateFields checks the field values on MACParameters with the rules // defined in the proto definition for this message. If any rules are // violated, an error is returned. @@ -476,6 +1188,18 @@ func (m *MACParameters) ValidateFields(paths ...string) error { } } + case "relay": + + if v, ok := interface{}(m.GetRelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACParametersValidationError{ + field: "relay", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: return MACParametersValidationError{ field: name, @@ -1275,6 +1999,30 @@ func (m *MACSettings) ValidateFields(paths ...string) error { } } + case "relay": + + if v, ok := interface{}(m.GetRelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACSettingsValidationError{ + field: "relay", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "desired_relay": + + if v, ok := interface{}(m.GetDesiredRelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACSettingsValidationError{ + field: "desired_relay", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: return MACSettingsValidationError{ field: name, @@ -1645,6 +2393,18 @@ func (m *MACState) ValidateFields(paths ...string) error { // no validation rules for LastAdrChangeFCntUp case "recent_mac_command_identifiers": + case "pending_relay_downlink": + + if v, ok := interface{}(m.GetPendingRelayDownlink()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACStateValidationError{ + field: "pending_relay_downlink", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: return MACStateValidationError{ field: name, @@ -5984,6 +6744,18 @@ func (m *MACState_UplinkMessage_RxMetadata) ValidateFields(paths ...string) erro } } + case "relay": + + if v, ok := interface{}(m.GetRelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACState_UplinkMessage_RxMetadataValidationError{ + field: "relay", + reason: "embedded message failed validation", + cause: err, + } + } + } + default: return MACState_UplinkMessage_RxMetadataValidationError{ field: name, @@ -6128,6 +6900,79 @@ var _ interface { ErrorName() string } = MACState_UplinkMessage_RxMetadata_PacketBrokerMetadataValidationError{} +// ValidateFields checks the field values on +// MACState_UplinkMessage_RxMetadata_RelayMetadata with the rules defined in +// the proto definition for this message. If any rules are violated, an error +// is returned. +func (m *MACState_UplinkMessage_RxMetadata_RelayMetadata) ValidateFields(paths ...string) error { + if len(paths) > 0 { + return fmt.Errorf("message MACState_UplinkMessage_RxMetadata_RelayMetadata has no fields, but paths %s were specified", paths) + } + return nil +} + +// MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError is the +// validation error returned by +// MACState_UplinkMessage_RxMetadata_RelayMetadata.ValidateFields if the +// designated constraints aren't met. +type MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) Field() string { + return e.field +} + +// Reason function returns reason value. +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) Reason() string { + return e.reason +} + +// Cause function returns cause value. +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) ErrorName() string { + return "MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError" +} + +// Error satisfies the builtin error interface +func (e MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMACState_UplinkMessage_RxMetadata_RelayMetadata.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MACState_UplinkMessage_RxMetadata_RelayMetadataValidationError{} + // ValidateFields checks the field values on MACState_DownlinkMessage_Message // 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/end_device_flags.pb.go b/pkg/ttnpb/end_device_flags.pb.go index 55531cc5c7..7a6ee92da9 100644 --- a/pkg/ttnpb/end_device_flags.pb.go +++ b/pkg/ttnpb/end_device_flags.pb.go @@ -172,6 +172,543 @@ func (m *BoolValue) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []s return paths, nil } +// AddSelectFlagsForServingRelayForwardingLimits adds flags to select fields in ServingRelayForwardingLimits. +func AddSelectFlagsForServingRelayForwardingLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("reset-behavior", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("reset-behavior", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("join-requests", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("join-requests", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("join-requests", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("notifications", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("notifications", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("notifications", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("uplink-messages", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("uplink-messages", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("uplink-messages", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("overall", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("overall", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("overall", prefix), hidden) +} + +// SelectFromFlags outputs the fieldmask paths forServingRelayForwardingLimits message from select flags. +func PathsFromSelectFlagsForServingRelayForwardingLimits(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("reset_behavior", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("reset_behavior", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("join_requests", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("join_requests", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("join_requests", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("notifications", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("notifications", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("notifications", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("uplink_messages", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("uplink_messages", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("uplink_messages", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("overall", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("overall", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("overall", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + return paths, nil +} + +// AddSetFlagsForServingRelayForwardingLimits adds flags to select fields in ServingRelayForwardingLimits. +func AddSetFlagsForServingRelayForwardingLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("reset-behavior", prefix), flagsplugin.EnumValueDesc(RelayResetLimitCounter_value), flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("join-requests", prefix), hidden) + AddSetFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("notifications", prefix), hidden) + AddSetFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("uplink-messages", prefix), hidden) + AddSetFlagsForRelayForwardLimits(flags, flagsplugin.Prefix("overall", prefix), hidden) +} + +// SetFromFlags sets the ServingRelayForwardingLimits message from flags. +func (m *ServingRelayForwardingLimits) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("reset_behavior", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelayResetLimitCounter_value) + if err != nil { + return nil, err + } + m.ResetBehavior = RelayResetLimitCounter(enumValue) + paths = append(paths, flagsplugin.Prefix("reset_behavior", prefix)) + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("join_requests", prefix)); changed { + if m.JoinRequests == nil { + m.JoinRequests = &RelayForwardLimits{} + } + if setPaths, err := m.JoinRequests.SetFromFlags(flags, flagsplugin.Prefix("join_requests", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("notifications", prefix)); changed { + if m.Notifications == nil { + m.Notifications = &RelayForwardLimits{} + } + if setPaths, err := m.Notifications.SetFromFlags(flags, flagsplugin.Prefix("notifications", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("uplink_messages", prefix)); changed { + if m.UplinkMessages == nil { + m.UplinkMessages = &RelayForwardLimits{} + } + if setPaths, err := m.UplinkMessages.SetFromFlags(flags, flagsplugin.Prefix("uplink_messages", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("overall", prefix)); changed { + if m.Overall == nil { + m.Overall = &RelayForwardLimits{} + } + if setPaths, err := m.Overall.SetFromFlags(flags, flagsplugin.Prefix("overall", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + return paths, nil +} + +// AddSelectFlagsForRelayUplinkForwardingRule adds flags to select fields in RelayUplinkForwardingRule. +func AddSelectFlagsForRelayUplinkForwardingRule(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("limits", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("limits", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("limits", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-w-f-cnt", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-w-f-cnt", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("device-id", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("device-id", 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))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayUplinkForwardingRule message from select flags. +func PathsFromSelectFlagsForRelayUplinkForwardingRule(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("limits", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("last_w_f_cnt", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("last_w_f_cnt", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("device_id", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("device_id", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("session_key_id", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("session_key_id", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayUplinkForwardingRule adds flags to select fields in RelayUplinkForwardingRule. +func AddSetFlagsForRelayUplinkForwardingRule(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("limits", prefix), hidden) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("last-w-f-cnt", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("device-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBytesFlag(flagsplugin.Prefix("session-key-id", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayUplinkForwardingRule message from flags. +func (m *RelayUplinkForwardingRule) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("limits", prefix)); changed { + if m.Limits == nil { + m.Limits = &RelayUplinkForwardLimits{} + } + if setPaths, err := m.Limits.SetFromFlags(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("last_w_f_cnt", prefix)); err != nil { + return nil, err + } else if changed { + m.LastWFCnt = val + paths = append(paths, flagsplugin.Prefix("last_w_f_cnt", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("device_id", prefix)); err != nil { + return nil, err + } else if changed { + m.DeviceId = val + paths = append(paths, flagsplugin.Prefix("device_id", prefix)) + } + if val, changed, err := flagsplugin.GetBytes(flags, flagsplugin.Prefix("session_key_id", prefix)); err != nil { + return nil, err + } else if changed { + m.SessionKeyId = val + paths = append(paths, flagsplugin.Prefix("session_key_id", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForServingRelayParameters adds flags to select fields in ServingRelayParameters. +func AddSelectFlagsForServingRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("second-channel", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("second-channel", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second-channel", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("default-channel-index", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("default-channel-index", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("cad-periodicity", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("cad-periodicity", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("uplink-forwarding-rules", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("uplink-forwarding-rules", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("limits", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("limits", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForServingRelayForwardingLimits(flags, flagsplugin.Prefix("limits", prefix), hidden) +} + +// SelectFromFlags outputs the fieldmask paths forServingRelayParameters message from select flags. +func PathsFromSelectFlagsForServingRelayParameters(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("second_channel", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("default_channel_index", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("default_channel_index", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("cad_periodicity", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("cad_periodicity", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("uplink_forwarding_rules", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("uplink_forwarding_rules", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("limits", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForServingRelayForwardingLimits(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + return paths, nil +} + +// AddSetFlagsForServingRelayParameters adds flags to select fields in ServingRelayParameters. +func AddSetFlagsForServingRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second-channel", prefix), hidden) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("default-channel-index", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("cad-periodicity", prefix), flagsplugin.EnumValueDesc(RelayCADPeriodicity_value), flagsplugin.WithHidden(hidden))) + // FIXME: Skipping UplinkForwardingRules because repeated messages are currently not supported. + AddSetFlagsForServingRelayForwardingLimits(flags, flagsplugin.Prefix("limits", prefix), hidden) +} + +// SetFromFlags sets the ServingRelayParameters message from flags. +func (m *ServingRelayParameters) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("second_channel", prefix)); changed { + if m.SecondChannel == nil { + m.SecondChannel = &RelaySecondChannel{} + } + if setPaths, err := m.SecondChannel.SetFromFlags(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("default_channel_index", prefix)); err != nil { + return nil, err + } else if changed { + m.DefaultChannelIndex = val + paths = append(paths, flagsplugin.Prefix("default_channel_index", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("cad_periodicity", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelayCADPeriodicity_value) + if err != nil { + return nil, err + } + m.CadPeriodicity = RelayCADPeriodicity(enumValue) + paths = append(paths, flagsplugin.Prefix("cad_periodicity", prefix)) + } + // FIXME: Skipping UplinkForwardingRules because it does not seem to implement AddSetFlags. + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("limits", prefix)); changed { + if m.Limits == nil { + m.Limits = &ServingRelayForwardingLimits{} + } + if setPaths, err := m.Limits.SetFromFlags(flags, flagsplugin.Prefix("limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + return paths, nil +} + +// AddSelectFlagsForServedRelayParameters adds flags to select fields in ServedRelayParameters. +func AddSelectFlagsForServedRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.always", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("mode.always", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayEndDeviceAlwaysMode(flags, flagsplugin.Prefix("mode.always", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.dynamic", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("mode.dynamic", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayEndDeviceDynamicMode(flags, flagsplugin.Prefix("mode.dynamic", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.end-device-controlled", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("mode.end-device-controlled", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayEndDeviceControlledMode(flags, flagsplugin.Prefix("mode.end-device-controlled", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("backoff", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("backoff", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("second-channel", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("second-channel", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second-channel", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("serving-device-id", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("serving-device-id", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forServedRelayParameters message from select flags. +func PathsFromSelectFlagsForServedRelayParameters(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("mode.always", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("mode.always", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayEndDeviceAlwaysMode(flags, flagsplugin.Prefix("mode.always", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("mode.dynamic", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("mode.dynamic", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayEndDeviceDynamicMode(flags, flagsplugin.Prefix("mode.dynamic", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("mode.end_device_controlled", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("mode.end_device_controlled", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayEndDeviceControlledMode(flags, flagsplugin.Prefix("mode.end_device_controlled", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("backoff", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("backoff", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("second_channel", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("serving_device_id", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("serving_device_id", prefix)) + } + return paths, nil +} + +// AddSetFlagsForServedRelayParameters adds flags to select fields in ServedRelayParameters. +func AddSetFlagsForServedRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForRelayEndDeviceAlwaysMode(flags, flagsplugin.Prefix("mode.always", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.always", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelayEndDeviceDynamicMode(flags, flagsplugin.Prefix("mode.dynamic", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.dynamic", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelayEndDeviceControlledMode(flags, flagsplugin.Prefix("mode.end-device-controlled", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.end-device-controlled", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("backoff", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelaySecondChannel(flags, flagsplugin.Prefix("second-channel", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("second-channel", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("serving-device-id", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the ServedRelayParameters message from flags. +func (m *ServedRelayParameters) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("mode.always", prefix)); changed { + ov := &ServedRelayParameters_Always{} + if ov.Always == nil { + ov.Always = &RelayEndDeviceAlwaysMode{} + } + if setPaths, err := ov.Always.SetFromFlags(flags, flagsplugin.Prefix("mode.always", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "mode.always") + } else { + paths = append(paths, setPaths...) + } + m.Mode = ov + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("mode.dynamic", prefix)); changed { + ov := &ServedRelayParameters_Dynamic{} + if ov.Dynamic == nil { + ov.Dynamic = &RelayEndDeviceDynamicMode{} + } + if setPaths, err := ov.Dynamic.SetFromFlags(flags, flagsplugin.Prefix("mode.dynamic", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "mode.dynamic") + } else { + paths = append(paths, setPaths...) + } + m.Mode = ov + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("mode.end_device_controlled", prefix)); changed { + ov := &ServedRelayParameters_EndDeviceControlled{} + if ov.EndDeviceControlled == nil { + ov.EndDeviceControlled = &RelayEndDeviceControlledMode{} + } + if setPaths, err := ov.EndDeviceControlled.SetFromFlags(flags, flagsplugin.Prefix("mode.end_device_controlled", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "mode.end_device_controlled") + } else { + paths = append(paths, setPaths...) + } + m.Mode = ov + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("backoff", prefix)); err != nil { + return nil, err + } else if changed { + m.Backoff = val + paths = append(paths, flagsplugin.Prefix("backoff", prefix)) + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("second_channel", prefix)); changed { + if m.SecondChannel == nil { + m.SecondChannel = &RelaySecondChannel{} + } + if setPaths, err := m.SecondChannel.SetFromFlags(flags, flagsplugin.Prefix("second_channel", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "second_channel") + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("serving_device_id", prefix)); err != nil { + return nil, err + } else if changed { + m.ServingDeviceId = val + paths = append(paths, flagsplugin.Prefix("serving_device_id", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayParameters adds flags to select fields in RelayParameters. +func AddSelectFlagsForRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.serving", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("mode.serving", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForServingRelayParameters(flags, flagsplugin.Prefix("mode.serving", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.served", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("mode.served", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForServedRelayParameters(flags, flagsplugin.Prefix("mode.served", prefix), hidden) +} + +// SelectFromFlags outputs the fieldmask paths forRelayParameters message from select flags. +func PathsFromSelectFlagsForRelayParameters(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("mode.serving", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("mode.serving", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForServingRelayParameters(flags, flagsplugin.Prefix("mode.serving", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("mode.served", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("mode.served", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForServedRelayParameters(flags, flagsplugin.Prefix("mode.served", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + return paths, nil +} + +// AddSetFlagsForRelayParameters adds flags to select fields in RelayParameters. +func AddSetFlagsForRelayParameters(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForServingRelayParameters(flags, flagsplugin.Prefix("mode.serving", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.serving", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForServedRelayParameters(flags, flagsplugin.Prefix("mode.served", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("mode.served", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayParameters message from flags. +func (m *RelayParameters) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("mode.serving", prefix)); changed { + ov := &RelayParameters_Serving{} + if ov.Serving == nil { + ov.Serving = &ServingRelayParameters{} + } + if setPaths, err := ov.Serving.SetFromFlags(flags, flagsplugin.Prefix("mode.serving", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "mode.serving") + } else { + paths = append(paths, setPaths...) + } + m.Mode = ov + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("mode.served", prefix)); changed { + ov := &RelayParameters_Served{} + if ov.Served == nil { + ov.Served = &ServedRelayParameters{} + } + if setPaths, err := ov.Served.SetFromFlags(flags, flagsplugin.Prefix("mode.served", prefix)); err != nil { + return nil, err + } else if len(setPaths) == 0 { + paths = append(paths, "mode.served") + } else { + paths = append(paths, setPaths...) + } + m.Mode = ov + } + return paths, nil +} + // AddSelectFlagsForMACParameters_Channel adds flags to select fields in MACParameters_Channel. func AddSelectFlagsForMACParameters_Channel(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("uplink-frequency", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("uplink-frequency", prefix), false), flagsplugin.WithHidden(hidden))) @@ -292,6 +829,8 @@ func AddSelectFlagsForMACParameters(flags *pflag.FlagSet, prefix string, hidden AddSelectFlagsForADRAckDelayExponentValue(flags, flagsplugin.Prefix("adr-ack-delay-exponent", prefix), true) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("ping-slot-data-rate-index-value", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("ping-slot-data-rate-index-value", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForDataRateIndexValue(flags, flagsplugin.Prefix("ping-slot-data-rate-index-value", prefix), true) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("relay", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("relay", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix), hidden) } // SelectFromFlags outputs the fieldmask paths forMACParameters message from select flags. @@ -431,6 +970,16 @@ func PathsFromSelectFlagsForMACParameters(flags *pflag.FlagSet, prefix string) ( } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("relay", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } return paths, nil } @@ -463,6 +1012,7 @@ func AddSetFlagsForMACParameters(flags *pflag.FlagSet, prefix string, hidden boo flagsplugin.AddAlias(flags, flagsplugin.Prefix("adr-ack-delay-exponent.value", prefix), flagsplugin.Prefix("adr-ack-delay-exponent", prefix), flagsplugin.WithHidden(hidden)) AddSetFlagsForDataRateIndexValue(flags, flagsplugin.Prefix("ping-slot-data-rate-index-value", prefix), true) flagsplugin.AddAlias(flags, flagsplugin.Prefix("ping-slot-data-rate-index-value.value", prefix), flagsplugin.Prefix("ping-slot-data-rate-index-value", prefix), flagsplugin.WithHidden(hidden)) + AddSetFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix), hidden) } // SetFromFlags sets the MACParameters message from flags. @@ -646,6 +1196,16 @@ func (m *MACParameters) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths paths = append(paths, setPaths...) } } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("relay", prefix)); changed { + if m.Relay == nil { + m.Relay = &RelayParameters{} + } + if setPaths, err := m.Relay.SetFromFlags(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } return paths, nil } @@ -1157,6 +1717,10 @@ func AddSelectFlagsForMACSettings(flags *pflag.FlagSet, prefix string, hidden bo AddSelectFlagsForADRSettings(flags, flagsplugin.Prefix("adr", prefix), hidden) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("schedule-downlinks", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("schedule-downlinks", prefix), true), flagsplugin.WithHidden(hidden))) AddSelectFlagsForBoolValue(flags, flagsplugin.Prefix("schedule-downlinks", prefix), true) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("relay", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("relay", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("desired-relay", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("desired-relay", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("desired-relay", prefix), hidden) } // SelectFromFlags outputs the fieldmask paths forMACSettings message from select flags. @@ -1466,6 +2030,26 @@ func PathsFromSelectFlagsForMACSettings(flags *pflag.FlagSet, prefix string) (pa } else { paths = append(paths, selectPaths...) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("relay", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("desired_relay", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("desired_relay", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayParameters(flags, flagsplugin.Prefix("desired_relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } return paths, nil } @@ -1531,6 +2115,8 @@ func AddSetFlagsForMACSettings(flags *pflag.FlagSet, prefix string, hidden bool) AddSetFlagsForADRSettings(flags, flagsplugin.Prefix("adr", prefix), hidden) AddSetFlagsForBoolValue(flags, flagsplugin.Prefix("schedule-downlinks", prefix), true) flagsplugin.AddAlias(flags, flagsplugin.Prefix("schedule-downlinks.value", prefix), flagsplugin.Prefix("schedule-downlinks", prefix), flagsplugin.WithHidden(hidden)) + AddSetFlagsForRelayParameters(flags, flagsplugin.Prefix("relay", prefix), hidden) + AddSetFlagsForRelayParameters(flags, flagsplugin.Prefix("desired-relay", prefix), hidden) } // SetFromFlags sets the MACSettings message from flags. @@ -1847,6 +2433,26 @@ func (m *MACSettings) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths [ paths = append(paths, setPaths...) } } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("relay", prefix)); changed { + if m.Relay == nil { + m.Relay = &RelayParameters{} + } + if setPaths, err := m.Relay.SetFromFlags(flags, flagsplugin.Prefix("relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("desired_relay", prefix)); changed { + if m.DesiredRelay == nil { + m.DesiredRelay = &RelayParameters{} + } + if setPaths, err := m.DesiredRelay.SetFromFlags(flags, flagsplugin.Prefix("desired_relay", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } return paths, nil } @@ -2156,6 +2762,8 @@ func AddSelectFlagsForMACState(flags *pflag.FlagSet, prefix string, hidden bool) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("rejected-data-rate-ranges", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("rejected-data-rate-ranges", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("last-adr-change-f-cnt-up", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("last-adr-change-f-cnt-up", prefix), false), flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("recent-mac-command-identifiers", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("recent-mac-command-identifiers", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("pending-relay-downlink", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("pending-relay-downlink", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayForwardDownlinkReq(flags, flagsplugin.Prefix("pending-relay-downlink", prefix), hidden) } // SelectFromFlags outputs the fieldmask paths forMACState message from select flags. @@ -2305,6 +2913,16 @@ func PathsFromSelectFlagsForMACState(flags *pflag.FlagSet, prefix string) (paths } else if selected && val { paths = append(paths, flagsplugin.Prefix("recent_mac_command_identifiers", prefix)) } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("pending_relay_downlink", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("pending_relay_downlink", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayForwardDownlinkReq(flags, flagsplugin.Prefix("pending_relay_downlink", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } return paths, nil } @@ -2334,6 +2952,7 @@ func AddSetFlagsForMACState(flags *pflag.FlagSet, prefix string, hidden bool) { // FIXME: Skipping RejectedDataRateRanges because maps with uint64 key types are currently not supported. flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("last-adr-change-f-cnt-up", prefix), "", flagsplugin.WithHidden(hidden))) flags.AddFlag(flagsplugin.NewStringSliceFlag(flagsplugin.Prefix("recent-mac-command-identifiers", prefix), flagsplugin.EnumValueDesc(MACCommandIdentifier_value), flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelayForwardDownlinkReq(flags, flagsplugin.Prefix("pending-relay-downlink", prefix), hidden) } // SetFromFlags sets the MACState message from flags. @@ -2497,6 +3116,16 @@ func (m *MACState) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []st } paths = append(paths, flagsplugin.Prefix("recent_mac_command_identifiers", prefix)) } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("pending_relay_downlink", prefix)); changed { + if m.PendingRelayDownlink == nil { + m.PendingRelayDownlink = &RelayForwardDownlinkReq{} + } + if setPaths, err := m.PendingRelayDownlink.SetFromFlags(flags, flagsplugin.Prefix("pending_relay_downlink", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } return paths, nil } diff --git a/pkg/ttnpb/end_device_json.pb.go b/pkg/ttnpb/end_device_json.pb.go index 51fdb9c4d7..13c070cba7 100644 --- a/pkg/ttnpb/end_device_json.pb.go +++ b/pkg/ttnpb/end_device_json.pb.go @@ -224,6 +224,446 @@ func (x *BoolValue) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } +// MarshalProtoJSON marshals the ServingRelayForwardingLimits message to JSON. +func (x *ServingRelayForwardingLimits) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.ResetBehavior != 0 || s.HasField("reset_behavior") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("reset_behavior") + x.ResetBehavior.MarshalProtoJSON(s) + } + if x.JoinRequests != nil || s.HasField("join_requests") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("join_requests") + x.JoinRequests.MarshalProtoJSON(s.WithField("join_requests")) + } + if x.Notifications != nil || s.HasField("notifications") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("notifications") + x.Notifications.MarshalProtoJSON(s.WithField("notifications")) + } + if x.UplinkMessages != nil || s.HasField("uplink_messages") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("uplink_messages") + x.UplinkMessages.MarshalProtoJSON(s.WithField("uplink_messages")) + } + if x.Overall != nil || s.HasField("overall") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("overall") + x.Overall.MarshalProtoJSON(s.WithField("overall")) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the ServingRelayForwardingLimits to JSON. +func (x *ServingRelayForwardingLimits) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the ServingRelayForwardingLimits message from JSON. +func (x *ServingRelayForwardingLimits) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "reset_behavior", "resetBehavior": + s.AddField("reset_behavior") + x.ResetBehavior.UnmarshalProtoJSON(s) + case "join_requests", "joinRequests": + if s.ReadNil() { + x.JoinRequests = nil + return + } + x.JoinRequests = &RelayForwardLimits{} + x.JoinRequests.UnmarshalProtoJSON(s.WithField("join_requests", true)) + case "notifications": + if s.ReadNil() { + x.Notifications = nil + return + } + x.Notifications = &RelayForwardLimits{} + x.Notifications.UnmarshalProtoJSON(s.WithField("notifications", true)) + case "uplink_messages", "uplinkMessages": + if s.ReadNil() { + x.UplinkMessages = nil + return + } + x.UplinkMessages = &RelayForwardLimits{} + x.UplinkMessages.UnmarshalProtoJSON(s.WithField("uplink_messages", true)) + case "overall": + if s.ReadNil() { + x.Overall = nil + return + } + x.Overall = &RelayForwardLimits{} + x.Overall.UnmarshalProtoJSON(s.WithField("overall", true)) + } + }) +} + +// UnmarshalJSON unmarshals the ServingRelayForwardingLimits from JSON. +func (x *ServingRelayForwardingLimits) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayUplinkForwardingRule message to JSON. +func (x *RelayUplinkForwardingRule) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Limits != nil || s.HasField("limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("limits") + x.Limits.MarshalProtoJSON(s.WithField("limits")) + } + if x.LastWFCnt != 0 || s.HasField("last_w_f_cnt") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("last_w_f_cnt") + s.WriteUint32(x.LastWFCnt) + } + if x.DeviceId != "" || s.HasField("device_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("device_id") + s.WriteString(x.DeviceId) + } + if len(x.SessionKeyId) > 0 || s.HasField("session_key_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("session_key_id") + s.WriteBytes(x.SessionKeyId) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayUplinkForwardingRule to JSON. +func (x *RelayUplinkForwardingRule) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayUplinkForwardingRule message from JSON. +func (x *RelayUplinkForwardingRule) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "limits": + if s.ReadNil() { + x.Limits = nil + return + } + x.Limits = &RelayUplinkForwardLimits{} + x.Limits.UnmarshalProtoJSON(s.WithField("limits", true)) + case "last_w_f_cnt", "lastWFCnt": + s.AddField("last_w_f_cnt") + x.LastWFCnt = s.ReadUint32() + case "device_id", "deviceId": + s.AddField("device_id") + x.DeviceId = s.ReadString() + case "session_key_id", "sessionKeyId": + s.AddField("session_key_id") + x.SessionKeyId = s.ReadBytes() + } + }) +} + +// UnmarshalJSON unmarshals the RelayUplinkForwardingRule from JSON. +func (x *RelayUplinkForwardingRule) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the ServingRelayParameters message to JSON. +func (x *ServingRelayParameters) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.SecondChannel != nil || s.HasField("second_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("second_channel") + x.SecondChannel.MarshalProtoJSON(s.WithField("second_channel")) + } + if x.DefaultChannelIndex != 0 || s.HasField("default_channel_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("default_channel_index") + s.WriteUint32(x.DefaultChannelIndex) + } + if x.CadPeriodicity != 0 || s.HasField("cad_periodicity") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("cad_periodicity") + x.CadPeriodicity.MarshalProtoJSON(s) + } + if len(x.UplinkForwardingRules) > 0 || s.HasField("uplink_forwarding_rules") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("uplink_forwarding_rules") + s.WriteArrayStart() + var wroteElement bool + for _, element := range x.UplinkForwardingRules { + s.WriteMoreIf(&wroteElement) + element.MarshalProtoJSON(s.WithField("uplink_forwarding_rules")) + } + s.WriteArrayEnd() + } + if x.Limits != nil || s.HasField("limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("limits") + x.Limits.MarshalProtoJSON(s.WithField("limits")) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the ServingRelayParameters to JSON. +func (x *ServingRelayParameters) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the ServingRelayParameters message from JSON. +func (x *ServingRelayParameters) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "second_channel", "secondChannel": + if s.ReadNil() { + x.SecondChannel = nil + return + } + x.SecondChannel = &RelaySecondChannel{} + x.SecondChannel.UnmarshalProtoJSON(s.WithField("second_channel", true)) + case "default_channel_index", "defaultChannelIndex": + s.AddField("default_channel_index") + x.DefaultChannelIndex = s.ReadUint32() + case "cad_periodicity", "cadPeriodicity": + s.AddField("cad_periodicity") + x.CadPeriodicity.UnmarshalProtoJSON(s) + case "uplink_forwarding_rules", "uplinkForwardingRules": + s.AddField("uplink_forwarding_rules") + if s.ReadNil() { + x.UplinkForwardingRules = nil + return + } + s.ReadArray(func() { + if s.ReadNil() { + x.UplinkForwardingRules = append(x.UplinkForwardingRules, nil) + return + } + v := &RelayUplinkForwardingRule{} + v.UnmarshalProtoJSON(s.WithField("uplink_forwarding_rules", false)) + if s.Err() != nil { + return + } + x.UplinkForwardingRules = append(x.UplinkForwardingRules, v) + }) + case "limits": + if s.ReadNil() { + x.Limits = nil + return + } + x.Limits = &ServingRelayForwardingLimits{} + x.Limits.UnmarshalProtoJSON(s.WithField("limits", true)) + } + }) +} + +// UnmarshalJSON unmarshals the ServingRelayParameters from JSON. +func (x *ServingRelayParameters) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the ServedRelayParameters message to JSON. +func (x *ServedRelayParameters) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Mode != nil { + switch ov := x.Mode.(type) { + case *ServedRelayParameters_Always: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("always") + // NOTE: RelayEndDeviceAlwaysMode does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.Always) + case *ServedRelayParameters_Dynamic: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("dynamic") + ov.Dynamic.MarshalProtoJSON(s.WithField("dynamic")) + case *ServedRelayParameters_EndDeviceControlled: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("end_device_controlled") + // NOTE: RelayEndDeviceControlledMode does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.EndDeviceControlled) + } + } + if x.Backoff != 0 || s.HasField("backoff") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("backoff") + s.WriteUint32(x.Backoff) + } + if x.SecondChannel != nil || s.HasField("second_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("second_channel") + x.SecondChannel.MarshalProtoJSON(s.WithField("second_channel")) + } + if x.ServingDeviceId != "" || s.HasField("serving_device_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("serving_device_id") + s.WriteString(x.ServingDeviceId) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the ServedRelayParameters to JSON. +func (x *ServedRelayParameters) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the ServedRelayParameters message from JSON. +func (x *ServedRelayParameters) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "always": + s.AddField("always") + ov := &ServedRelayParameters_Always{} + x.Mode = ov + if s.ReadNil() { + ov.Always = nil + return + } + // NOTE: RelayEndDeviceAlwaysMode does not seem to implement UnmarshalProtoJSON. + var v RelayEndDeviceAlwaysMode + golang.UnmarshalMessage(s, &v) + ov.Always = &v + case "dynamic": + ov := &ServedRelayParameters_Dynamic{} + x.Mode = ov + if s.ReadNil() { + ov.Dynamic = nil + return + } + ov.Dynamic = &RelayEndDeviceDynamicMode{} + ov.Dynamic.UnmarshalProtoJSON(s.WithField("dynamic", true)) + case "end_device_controlled", "endDeviceControlled": + s.AddField("end_device_controlled") + ov := &ServedRelayParameters_EndDeviceControlled{} + x.Mode = ov + if s.ReadNil() { + ov.EndDeviceControlled = nil + return + } + // NOTE: RelayEndDeviceControlledMode does not seem to implement UnmarshalProtoJSON. + var v RelayEndDeviceControlledMode + golang.UnmarshalMessage(s, &v) + ov.EndDeviceControlled = &v + case "backoff": + s.AddField("backoff") + x.Backoff = s.ReadUint32() + case "second_channel", "secondChannel": + if s.ReadNil() { + x.SecondChannel = nil + return + } + x.SecondChannel = &RelaySecondChannel{} + x.SecondChannel.UnmarshalProtoJSON(s.WithField("second_channel", true)) + case "serving_device_id", "servingDeviceId": + s.AddField("serving_device_id") + x.ServingDeviceId = s.ReadString() + } + }) +} + +// UnmarshalJSON unmarshals the ServedRelayParameters from JSON. +func (x *ServedRelayParameters) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayParameters message to JSON. +func (x *RelayParameters) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Mode != nil { + switch ov := x.Mode.(type) { + case *RelayParameters_Serving: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("serving") + ov.Serving.MarshalProtoJSON(s.WithField("serving")) + case *RelayParameters_Served: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("served") + ov.Served.MarshalProtoJSON(s.WithField("served")) + } + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayParameters to JSON. +func (x *RelayParameters) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayParameters message from JSON. +func (x *RelayParameters) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "serving": + ov := &RelayParameters_Serving{} + x.Mode = ov + if s.ReadNil() { + ov.Serving = nil + return + } + ov.Serving = &ServingRelayParameters{} + ov.Serving.UnmarshalProtoJSON(s.WithField("serving", true)) + case "served": + ov := &RelayParameters_Served{} + x.Mode = ov + if s.ReadNil() { + ov.Served = nil + return + } + ov.Served = &ServedRelayParameters{} + ov.Served.UnmarshalProtoJSON(s.WithField("served", true)) + } + }) +} + +// UnmarshalJSON unmarshals the RelayParameters from JSON. +func (x *RelayParameters) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + // MarshalProtoJSON marshals the MACParameters_Channel message to JSON. func (x *MACParameters_Channel) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { @@ -422,6 +862,11 @@ func (x *MACParameters) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteObjectField("ping_slot_data_rate_index_value") x.PingSlotDataRateIndexValue.MarshalProtoJSON(s.WithField("ping_slot_data_rate_index_value")) } + if x.Relay != nil || s.HasField("relay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay") + x.Relay.MarshalProtoJSON(s.WithField("relay")) + } s.WriteObjectEnd() } @@ -545,6 +990,13 @@ func (x *MACParameters) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { } x.PingSlotDataRateIndexValue = &DataRateIndexValue{} x.PingSlotDataRateIndexValue.UnmarshalProtoJSON(s.WithField("ping_slot_data_rate_index_value", false)) + case "relay": + if s.ReadNil() { + x.Relay = nil + return + } + x.Relay = &RelayParameters{} + x.Relay.UnmarshalProtoJSON(s.WithField("relay", true)) } }) } @@ -1229,6 +1681,16 @@ func (x *MACSettings) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteObjectField("schedule_downlinks") x.ScheduleDownlinks.MarshalProtoJSON(s.WithField("schedule_downlinks")) } + if x.Relay != nil || s.HasField("relay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay") + x.Relay.MarshalProtoJSON(s.WithField("relay")) + } + if x.DesiredRelay != nil || s.HasField("desired_relay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("desired_relay") + x.DesiredRelay.MarshalProtoJSON(s.WithField("desired_relay")) + } s.WriteObjectEnd() } @@ -1534,6 +1996,20 @@ func (x *MACSettings) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { } x.ScheduleDownlinks = &BoolValue{} x.ScheduleDownlinks.UnmarshalProtoJSON(s.WithField("schedule_downlinks", false)) + case "relay": + if s.ReadNil() { + x.Relay = nil + return + } + x.Relay = &RelayParameters{} + x.Relay.UnmarshalProtoJSON(s.WithField("relay", true)) + case "desired_relay", "desiredRelay": + if s.ReadNil() { + x.DesiredRelay = nil + return + } + x.DesiredRelay = &RelayParameters{} + x.DesiredRelay.UnmarshalProtoJSON(s.WithField("desired_relay", true)) } }) } @@ -1742,6 +2218,12 @@ func (x *MACState_UplinkMessage_RxMetadata) MarshalProtoJSON(s *jsonplugin.Marsh // NOTE: MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata does not seem to implement MarshalProtoJSON. golang.MarshalMessage(s, x.PacketBroker) } + if x.Relay != nil || s.HasField("relay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay") + // NOTE: MACState_UplinkMessage_RxMetadata_RelayMetadata does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.Relay) + } s.WriteObjectEnd() } @@ -1788,6 +2270,16 @@ func (x *MACState_UplinkMessage_RxMetadata) UnmarshalProtoJSON(s *jsonplugin.Unm var v MACState_UplinkMessage_RxMetadata_PacketBrokerMetadata golang.UnmarshalMessage(s, &v) x.PacketBroker = &v + case "relay": + s.AddField("relay") + if s.ReadNil() { + x.Relay = nil + return + } + // NOTE: MACState_UplinkMessage_RxMetadata_RelayMetadata does not seem to implement UnmarshalProtoJSON. + var v MACState_UplinkMessage_RxMetadata_RelayMetadata + golang.UnmarshalMessage(s, &v) + x.Relay = &v } }) } @@ -2381,6 +2873,12 @@ func (x *MACState) MarshalProtoJSON(s *jsonplugin.MarshalState) { } s.WriteArrayEnd() } + if x.PendingRelayDownlink != nil || s.HasField("pending_relay_downlink") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("pending_relay_downlink") + // NOTE: RelayForwardDownlinkReq does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.PendingRelayDownlink) + } s.WriteObjectEnd() } @@ -2609,6 +3107,16 @@ func (x *MACState) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { v.UnmarshalProtoJSON(s) x.RecentMacCommandIdentifiers = append(x.RecentMacCommandIdentifiers, v) }) + case "pending_relay_downlink", "pendingRelayDownlink": + s.AddField("pending_relay_downlink") + if s.ReadNil() { + x.PendingRelayDownlink = nil + return + } + // NOTE: RelayForwardDownlinkReq does not seem to implement UnmarshalProtoJSON. + var v RelayForwardDownlinkReq + golang.UnmarshalMessage(s, &v) + x.PendingRelayDownlink = &v } }) } diff --git a/pkg/ttnpb/field_mask_validation.go b/pkg/ttnpb/field_mask_validation.go index 7ab678dea1..fa39c8db22 100644 --- a/pkg/ttnpb/field_mask_validation.go +++ b/pkg/ttnpb/field_mask_validation.go @@ -148,6 +148,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_settings.desired_ping_slot_data_rate_index.value", "mac_settings.desired_ping_slot_frequency", "mac_settings.desired_ping_slot_frequency.value", + "mac_settings.desired_relay", + "mac_settings.desired_relay.mode", + "mac_settings.desired_relay.mode.served", + "mac_settings.desired_relay.mode.served.backoff", + "mac_settings.desired_relay.mode.served.mode", + "mac_settings.desired_relay.mode.served.mode.always", + "mac_settings.desired_relay.mode.served.mode.dynamic", + "mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "mac_settings.desired_relay.mode.served.second_channel", + "mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.served.second_channel.frequency", + "mac_settings.desired_relay.mode.served.serving_device_id", + "mac_settings.desired_relay.mode.serving", + "mac_settings.desired_relay.mode.serving.cad_periodicity", + "mac_settings.desired_relay.mode.serving.default_channel_index", + "mac_settings.desired_relay.mode.serving.limits", + "mac_settings.desired_relay.mode.serving.limits.join_requests", + "mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.notifications", + "mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.overall", + "mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.desired_relay.mode.serving.second_channel", + "mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.serving.second_channel.frequency", + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "mac_settings.desired_rx1_data_rate_offset", "mac_settings.desired_rx1_data_rate_offset.value", "mac_settings.desired_rx1_delay", @@ -165,6 +201,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_settings.ping_slot_frequency.value", "mac_settings.ping_slot_periodicity", "mac_settings.ping_slot_periodicity.value", + "mac_settings.relay", + "mac_settings.relay.mode", + "mac_settings.relay.mode.served", + "mac_settings.relay.mode.served.backoff", + "mac_settings.relay.mode.served.mode", + "mac_settings.relay.mode.served.mode.always", + "mac_settings.relay.mode.served.mode.dynamic", + "mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.relay.mode.served.mode.end_device_controlled", + "mac_settings.relay.mode.served.second_channel", + "mac_settings.relay.mode.served.second_channel.ack_offset", + "mac_settings.relay.mode.served.second_channel.data_rate_index", + "mac_settings.relay.mode.served.second_channel.frequency", + "mac_settings.relay.mode.served.serving_device_id", + "mac_settings.relay.mode.serving", + "mac_settings.relay.mode.serving.cad_periodicity", + "mac_settings.relay.mode.serving.default_channel_index", + "mac_settings.relay.mode.serving.limits", + "mac_settings.relay.mode.serving.limits.join_requests", + "mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.relay.mode.serving.limits.notifications", + "mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.relay.mode.serving.limits.overall", + "mac_settings.relay.mode.serving.limits.overall.bucket_size", + "mac_settings.relay.mode.serving.limits.overall.reload_rate", + "mac_settings.relay.mode.serving.limits.reset_behavior", + "mac_settings.relay.mode.serving.limits.uplink_messages", + "mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.relay.mode.serving.second_channel", + "mac_settings.relay.mode.serving.second_channel.ack_offset", + "mac_settings.relay.mode.serving.second_channel.data_rate_index", + "mac_settings.relay.mode.serving.second_channel.frequency", + "mac_settings.relay.mode.serving.uplink_forwarding_rules", "mac_settings.resets_f_cnt", "mac_settings.resets_f_cnt.value", "mac_settings.rx1_data_rate_offset", @@ -207,6 +279,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay", + "mac_state.current_parameters.relay.mode", + "mac_state.current_parameters.relay.mode.served", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -232,6 +340,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay", + "mac_state.desired_parameters.relay.mode", + "mac_state.desired_parameters.relay.mode.served", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -256,6 +400,8 @@ var nsEndDeviceReadFieldPaths = [...]string{ "mac_state.pending_application_downlink.frm_payload", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_relay_downlink", + "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", "mac_state.ping_slot_periodicity", "mac_state.ping_slot_periodicity.value", @@ -291,6 +437,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "pending_mac_state.current_parameters.ping_slot_frequency", "pending_mac_state.current_parameters.rejoin_count_periodicity", "pending_mac_state.current_parameters.rejoin_time_periodicity", + "pending_mac_state.current_parameters.relay", + "pending_mac_state.current_parameters.relay.mode", + "pending_mac_state.current_parameters.relay.mode.served", + "pending_mac_state.current_parameters.relay.mode.served.backoff", + "pending_mac_state.current_parameters.relay.mode.served.mode", + "pending_mac_state.current_parameters.relay.mode.served.mode.always", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.current_parameters.relay.mode.served.second_channel", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.current_parameters.relay.mode.serving", + "pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.limits", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.current_parameters.rx1_data_rate_offset", "pending_mac_state.current_parameters.rx1_delay", "pending_mac_state.current_parameters.rx2_data_rate_index", @@ -316,6 +498,42 @@ var nsEndDeviceReadFieldPaths = [...]string{ "pending_mac_state.desired_parameters.ping_slot_frequency", "pending_mac_state.desired_parameters.rejoin_count_periodicity", "pending_mac_state.desired_parameters.rejoin_time_periodicity", + "pending_mac_state.desired_parameters.relay", + "pending_mac_state.desired_parameters.relay.mode", + "pending_mac_state.desired_parameters.relay.mode.served", + "pending_mac_state.desired_parameters.relay.mode.served.backoff", + "pending_mac_state.desired_parameters.relay.mode.served.mode", + "pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.desired_parameters.relay.mode.serving", + "pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.limits", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.desired_parameters.rx1_data_rate_offset", "pending_mac_state.desired_parameters.rx1_delay", "pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -792,6 +1010,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_settings.desired_ping_slot_data_rate_index.value", "mac_settings.desired_ping_slot_frequency", "mac_settings.desired_ping_slot_frequency.value", + "mac_settings.desired_relay", + "mac_settings.desired_relay.mode", + "mac_settings.desired_relay.mode.served", + "mac_settings.desired_relay.mode.served.backoff", + "mac_settings.desired_relay.mode.served.mode", + "mac_settings.desired_relay.mode.served.mode.always", + "mac_settings.desired_relay.mode.served.mode.dynamic", + "mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "mac_settings.desired_relay.mode.served.second_channel", + "mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.served.second_channel.frequency", + "mac_settings.desired_relay.mode.served.serving_device_id", + "mac_settings.desired_relay.mode.serving", + "mac_settings.desired_relay.mode.serving.cad_periodicity", + "mac_settings.desired_relay.mode.serving.default_channel_index", + "mac_settings.desired_relay.mode.serving.limits", + "mac_settings.desired_relay.mode.serving.limits.join_requests", + "mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.notifications", + "mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.overall", + "mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.desired_relay.mode.serving.second_channel", + "mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "mac_settings.desired_relay.mode.serving.second_channel.frequency", + "mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "mac_settings.desired_rx1_data_rate_offset", "mac_settings.desired_rx1_data_rate_offset.value", "mac_settings.desired_rx1_delay", @@ -809,6 +1063,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_settings.ping_slot_frequency.value", "mac_settings.ping_slot_periodicity", "mac_settings.ping_slot_periodicity.value", + "mac_settings.relay", + "mac_settings.relay.mode", + "mac_settings.relay.mode.served", + "mac_settings.relay.mode.served.backoff", + "mac_settings.relay.mode.served.mode", + "mac_settings.relay.mode.served.mode.always", + "mac_settings.relay.mode.served.mode.dynamic", + "mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_settings.relay.mode.served.mode.end_device_controlled", + "mac_settings.relay.mode.served.second_channel", + "mac_settings.relay.mode.served.second_channel.ack_offset", + "mac_settings.relay.mode.served.second_channel.data_rate_index", + "mac_settings.relay.mode.served.second_channel.frequency", + "mac_settings.relay.mode.served.serving_device_id", + "mac_settings.relay.mode.serving", + "mac_settings.relay.mode.serving.cad_periodicity", + "mac_settings.relay.mode.serving.default_channel_index", + "mac_settings.relay.mode.serving.limits", + "mac_settings.relay.mode.serving.limits.join_requests", + "mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "mac_settings.relay.mode.serving.limits.notifications", + "mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "mac_settings.relay.mode.serving.limits.overall", + "mac_settings.relay.mode.serving.limits.overall.bucket_size", + "mac_settings.relay.mode.serving.limits.overall.reload_rate", + "mac_settings.relay.mode.serving.limits.reset_behavior", + "mac_settings.relay.mode.serving.limits.uplink_messages", + "mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_settings.relay.mode.serving.second_channel", + "mac_settings.relay.mode.serving.second_channel.ack_offset", + "mac_settings.relay.mode.serving.second_channel.data_rate_index", + "mac_settings.relay.mode.serving.second_channel.frequency", + "mac_settings.relay.mode.serving.uplink_forwarding_rules", "mac_settings.resets_f_cnt", "mac_settings.resets_f_cnt.value", "mac_settings.rx1_data_rate_offset", @@ -851,6 +1141,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_state.current_parameters.ping_slot_frequency", "mac_state.current_parameters.rejoin_count_periodicity", "mac_state.current_parameters.rejoin_time_periodicity", + "mac_state.current_parameters.relay", + "mac_state.current_parameters.relay.mode", + "mac_state.current_parameters.relay.mode.served", + "mac_state.current_parameters.relay.mode.served.backoff", + "mac_state.current_parameters.relay.mode.served.mode", + "mac_state.current_parameters.relay.mode.served.mode.always", + "mac_state.current_parameters.relay.mode.served.mode.dynamic", + "mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.current_parameters.relay.mode.served.second_channel", + "mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "mac_state.current_parameters.relay.mode.served.serving_device_id", + "mac_state.current_parameters.relay.mode.serving", + "mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "mac_state.current_parameters.relay.mode.serving.default_channel_index", + "mac_state.current_parameters.relay.mode.serving.limits", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.notifications", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.overall", + "mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.current_parameters.relay.mode.serving.second_channel", + "mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.current_parameters.rx1_data_rate_offset", "mac_state.current_parameters.rx1_delay", "mac_state.current_parameters.rx2_data_rate_index", @@ -876,6 +1202,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_state.desired_parameters.ping_slot_frequency", "mac_state.desired_parameters.rejoin_count_periodicity", "mac_state.desired_parameters.rejoin_time_periodicity", + "mac_state.desired_parameters.relay", + "mac_state.desired_parameters.relay.mode", + "mac_state.desired_parameters.relay.mode.served", + "mac_state.desired_parameters.relay.mode.served.backoff", + "mac_state.desired_parameters.relay.mode.served.mode", + "mac_state.desired_parameters.relay.mode.served.mode.always", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "mac_state.desired_parameters.relay.mode.served.second_channel", + "mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.served.serving_device_id", + "mac_state.desired_parameters.relay.mode.serving", + "mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "mac_state.desired_parameters.relay.mode.serving.limits", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.overall", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "mac_state.desired_parameters.relay.mode.serving.second_channel", + "mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "mac_state.desired_parameters.rx1_data_rate_offset", "mac_state.desired_parameters.rx1_delay", "mac_state.desired_parameters.rx2_data_rate_index", @@ -900,6 +1262,8 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "mac_state.pending_application_downlink.frm_payload", "mac_state.pending_application_downlink.priority", "mac_state.pending_application_downlink.session_key_id", + "mac_state.pending_relay_downlink", + "mac_state.pending_relay_downlink.raw_payload", "mac_state.pending_requests", "mac_state.ping_slot_periodicity", "mac_state.ping_slot_periodicity.value", @@ -935,6 +1299,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "pending_mac_state.current_parameters.ping_slot_frequency", "pending_mac_state.current_parameters.rejoin_count_periodicity", "pending_mac_state.current_parameters.rejoin_time_periodicity", + "pending_mac_state.current_parameters.relay", + "pending_mac_state.current_parameters.relay.mode", + "pending_mac_state.current_parameters.relay.mode.served", + "pending_mac_state.current_parameters.relay.mode.served.backoff", + "pending_mac_state.current_parameters.relay.mode.served.mode", + "pending_mac_state.current_parameters.relay.mode.served.mode.always", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.current_parameters.relay.mode.served.second_channel", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.current_parameters.relay.mode.serving", + "pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.current_parameters.relay.mode.serving.limits", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.current_parameters.rx1_data_rate_offset", "pending_mac_state.current_parameters.rx1_delay", "pending_mac_state.current_parameters.rx2_data_rate_index", @@ -960,6 +1360,42 @@ var RPCFieldMaskPaths = map[string]RPCFieldMaskPathValue{ "pending_mac_state.desired_parameters.ping_slot_frequency", "pending_mac_state.desired_parameters.rejoin_count_periodicity", "pending_mac_state.desired_parameters.rejoin_time_periodicity", + "pending_mac_state.desired_parameters.relay", + "pending_mac_state.desired_parameters.relay.mode", + "pending_mac_state.desired_parameters.relay.mode.served", + "pending_mac_state.desired_parameters.relay.mode.served.backoff", + "pending_mac_state.desired_parameters.relay.mode.served.mode", + "pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "pending_mac_state.desired_parameters.relay.mode.serving", + "pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "pending_mac_state.desired_parameters.relay.mode.serving.limits", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "pending_mac_state.desired_parameters.rx1_data_rate_offset", "pending_mac_state.desired_parameters.rx1_delay", "pending_mac_state.desired_parameters.rx2_data_rate_index", diff --git a/pkg/ttnpb/gateway_services.pb.go b/pkg/ttnpb/gateway_services.pb.go index 18a89af65d..515c777438 100644 --- a/pkg/ttnpb/gateway_services.pb.go +++ b/pkg/ttnpb/gateway_services.pb.go @@ -231,7 +231,7 @@ var file_ttn_lorawan_v3_gateway_services_proto_rawDesc = []byte{ 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x92, 0x01, 0x04, 0x08, 0x01, - 0x10, 0x14, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x73, 0x12, 0x3c, + 0x10, 0x64, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x73, 0x12, 0x3c, 0x0a, 0x08, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x69, 0x67, 0x68, 0x74, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, diff --git a/pkg/ttnpb/gateway_services.pb.validate.go b/pkg/ttnpb/gateway_services.pb.validate.go index 8d21dc3a21..ed9e539bb4 100644 --- a/pkg/ttnpb/gateway_services.pb.validate.go +++ b/pkg/ttnpb/gateway_services.pb.validate.go @@ -155,10 +155,10 @@ func (m *AssertGatewayRightsRequest) ValidateFields(paths ...string) error { switch name { case "gateway_ids": - if l := len(m.GetGatewayIds()); l < 1 || l > 20 { + if l := len(m.GetGatewayIds()); l < 1 || l > 100 { return AssertGatewayRightsRequestValidationError{ field: "gateway_ids", - reason: "value must contain between 1 and 20 items, inclusive", + reason: "value must contain between 1 and 100 items, inclusive", } } diff --git a/pkg/ttnpb/i18n.go b/pkg/ttnpb/i18n.go index a9a67c0f7e..6c2b8d0296 100644 --- a/pkg/ttnpb/i18n.go +++ b/pkg/ttnpb/i18n.go @@ -87,6 +87,14 @@ func init() { defineEnum(MACCommandIdentifier_CID_BEACON_FREQ, "beacon frequency") defineEnum(MACCommandIdentifier_CID_DEVICE_MODE, "device mode") + defineEnum(MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, "end device relay configuration") + defineEnum(MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, "update uplink forwarding rules") + defineEnum(MACCommandIdentifier_CID_RELAY_CONF, "relay configuration") + defineEnum(MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, "manage uplink forwarding rules") + defineEnum(MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE, "new end device under relay") + defineEnum(MACCommandIdentifier_CID_RELAY_FILTER_LIST, "manage join request forwarding rules") + defineEnum(MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, "manage uplink forwarding limits") + defineEnum(LocationSource_SOURCE_UNKNOWN, "unknown location source") defineEnum(LocationSource_SOURCE_GPS, "determined by GPS") defineEnum(LocationSource_SOURCE_REGISTRY, "set in and updated from a registry") diff --git a/pkg/ttnpb/identifiers.pb.go b/pkg/ttnpb/identifiers.pb.go index 50edfa43e1..7d605e5a1e 100644 --- a/pkg/ttnpb/identifiers.pb.go +++ b/pkg/ttnpb/identifiers.pb.go @@ -1198,7 +1198,7 @@ var file_ttn_lorawan_v3_identifiers_proto_rawDesc = []byte{ 0x61, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0x80, 0x02, 0x52, 0x0d, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, - 0x08, 0x01, 0x10, 0x00, 0x22, 0x69, 0x0a, 0x1e, 0x4c, 0x6f, 0x52, 0x61, 0x41, 0x6c, 0x6c, 0x69, + 0x08, 0x01, 0x10, 0x01, 0x22, 0x69, 0x0a, 0x1e, 0x4c, 0x6f, 0x52, 0x61, 0x41, 0x6c, 0x6c, 0x69, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x65, 0x6e, 0x64, 0x6f, diff --git a/pkg/ttnpb/identifiers_flags.pb.go b/pkg/ttnpb/identifiers_flags.pb.go index 7b7580ee87..f2e69fd0aa 100644 --- a/pkg/ttnpb/identifiers_flags.pb.go +++ b/pkg/ttnpb/identifiers_flags.pb.go @@ -481,3 +481,54 @@ func PathsFromSelectFlagsForNetworkIdentifiers(flags *pflag.FlagSet, prefix stri } return paths, nil } + +// AddSetFlagsForNetworkIdentifiers adds flags to select fields in NetworkIdentifiers. +func AddSetFlagsForNetworkIdentifiers(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(customflags.New3BytesFlag(flagsplugin.Prefix("net-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(customflags.New8BytesFlag(flagsplugin.Prefix("ns-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("tenant-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("cluster-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("cluster-address", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("tenant-address", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the NetworkIdentifiers message from flags. +func (m *NetworkIdentifiers) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := customflags.GetExactBytes(flags, flagsplugin.Prefix("net_id", prefix)); err != nil { + return nil, err + } else if changed { + m.NetId = val + paths = append(paths, flagsplugin.Prefix("net_id", prefix)) + } + if val, changed, err := customflags.GetExactBytes(flags, flagsplugin.Prefix("ns_id", prefix)); err != nil { + return nil, err + } else if changed { + m.NsId = val + paths = append(paths, flagsplugin.Prefix("ns_id", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("tenant_id", prefix)); err != nil { + return nil, err + } else if changed { + m.TenantId = val + paths = append(paths, flagsplugin.Prefix("tenant_id", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("cluster_id", prefix)); err != nil { + return nil, err + } else if changed { + m.ClusterId = val + paths = append(paths, flagsplugin.Prefix("cluster_id", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("cluster_address", prefix)); err != nil { + return nil, err + } else if changed { + m.ClusterAddress = val + paths = append(paths, flagsplugin.Prefix("cluster_address", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("tenant_address", prefix)); err != nil { + return nil, err + } else if changed { + m.TenantAddress = val + paths = append(paths, flagsplugin.Prefix("tenant_address", prefix)) + } + return paths, nil +} diff --git a/pkg/ttnpb/lorawan.go b/pkg/ttnpb/lorawan.go index c0f84555aa..2d13b350fc 100644 --- a/pkg/ttnpb/lorawan.go +++ b/pkg/ttnpb/lorawan.go @@ -1197,3 +1197,43 @@ func (m *Message) EndDeviceIdentifiers() *EndDeviceIdentifiers { } return nil } + +// FieldIsZero returns whether path p is zero. +func (v *RelaySecondChannel) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "ack_offset": + return v.AckOffset == 0 + case "data_rate_index": + return v.DataRateIndex == 0 + case "frequency": + return v.Frequency == 0 + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *RelayEndDeviceDynamicMode) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "smart_enable_level": + return v.SmartEnableLevel == 0 + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} + +// FieldIsZero returns whether path p is zero. +func (v *RelayForwardDownlinkReq) FieldIsZero(p string) bool { + if v == nil { + return true + } + switch p { + case "raw_payload": + return v.RawPayload == nil + } + panic(fmt.Sprintf("unknown path '%s'", p)) +} diff --git a/pkg/ttnpb/lorawan.pb.go b/pkg/ttnpb/lorawan.pb.go index ad1fea9de8..04fc47efe9 100644 --- a/pkg/ttnpb/lorawan.pb.go +++ b/pkg/ttnpb/lorawan.pb.go @@ -720,27 +720,34 @@ func (TxSchedulePriority) EnumDescriptor() ([]byte, []int) { type MACCommandIdentifier int32 const ( - MACCommandIdentifier_CID_RFU_0 MACCommandIdentifier = 0 - MACCommandIdentifier_CID_RESET MACCommandIdentifier = 1 - MACCommandIdentifier_CID_LINK_CHECK MACCommandIdentifier = 2 - MACCommandIdentifier_CID_LINK_ADR MACCommandIdentifier = 3 - MACCommandIdentifier_CID_DUTY_CYCLE MACCommandIdentifier = 4 - MACCommandIdentifier_CID_RX_PARAM_SETUP MACCommandIdentifier = 5 - MACCommandIdentifier_CID_DEV_STATUS MACCommandIdentifier = 6 - MACCommandIdentifier_CID_NEW_CHANNEL MACCommandIdentifier = 7 - MACCommandIdentifier_CID_RX_TIMING_SETUP MACCommandIdentifier = 8 - MACCommandIdentifier_CID_TX_PARAM_SETUP MACCommandIdentifier = 9 - MACCommandIdentifier_CID_DL_CHANNEL MACCommandIdentifier = 10 - MACCommandIdentifier_CID_REKEY MACCommandIdentifier = 11 - MACCommandIdentifier_CID_ADR_PARAM_SETUP MACCommandIdentifier = 12 - MACCommandIdentifier_CID_DEVICE_TIME MACCommandIdentifier = 13 - MACCommandIdentifier_CID_FORCE_REJOIN MACCommandIdentifier = 14 - MACCommandIdentifier_CID_REJOIN_PARAM_SETUP MACCommandIdentifier = 15 - MACCommandIdentifier_CID_PING_SLOT_INFO MACCommandIdentifier = 16 - MACCommandIdentifier_CID_PING_SLOT_CHANNEL MACCommandIdentifier = 17 - MACCommandIdentifier_CID_BEACON_TIMING MACCommandIdentifier = 18 // Deprecated - MACCommandIdentifier_CID_BEACON_FREQ MACCommandIdentifier = 19 - MACCommandIdentifier_CID_DEVICE_MODE MACCommandIdentifier = 32 + MACCommandIdentifier_CID_RFU_0 MACCommandIdentifier = 0 + MACCommandIdentifier_CID_RESET MACCommandIdentifier = 1 + MACCommandIdentifier_CID_LINK_CHECK MACCommandIdentifier = 2 + MACCommandIdentifier_CID_LINK_ADR MACCommandIdentifier = 3 + MACCommandIdentifier_CID_DUTY_CYCLE MACCommandIdentifier = 4 + MACCommandIdentifier_CID_RX_PARAM_SETUP MACCommandIdentifier = 5 + MACCommandIdentifier_CID_DEV_STATUS MACCommandIdentifier = 6 + MACCommandIdentifier_CID_NEW_CHANNEL MACCommandIdentifier = 7 + MACCommandIdentifier_CID_RX_TIMING_SETUP MACCommandIdentifier = 8 + MACCommandIdentifier_CID_TX_PARAM_SETUP MACCommandIdentifier = 9 + MACCommandIdentifier_CID_DL_CHANNEL MACCommandIdentifier = 10 + MACCommandIdentifier_CID_REKEY MACCommandIdentifier = 11 + MACCommandIdentifier_CID_ADR_PARAM_SETUP MACCommandIdentifier = 12 + MACCommandIdentifier_CID_DEVICE_TIME MACCommandIdentifier = 13 + MACCommandIdentifier_CID_FORCE_REJOIN MACCommandIdentifier = 14 + MACCommandIdentifier_CID_REJOIN_PARAM_SETUP MACCommandIdentifier = 15 + MACCommandIdentifier_CID_PING_SLOT_INFO MACCommandIdentifier = 16 + MACCommandIdentifier_CID_PING_SLOT_CHANNEL MACCommandIdentifier = 17 + MACCommandIdentifier_CID_BEACON_TIMING MACCommandIdentifier = 18 // Deprecated + MACCommandIdentifier_CID_BEACON_FREQ MACCommandIdentifier = 19 + MACCommandIdentifier_CID_DEVICE_MODE MACCommandIdentifier = 32 + MACCommandIdentifier_CID_RELAY_CONF MACCommandIdentifier = 64 + MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF MACCommandIdentifier = 65 + MACCommandIdentifier_CID_RELAY_FILTER_LIST MACCommandIdentifier = 66 + MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST MACCommandIdentifier = 67 + MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST MACCommandIdentifier = 68 + MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT MACCommandIdentifier = 69 + MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE MACCommandIdentifier = 70 ) // Enum value maps for MACCommandIdentifier. @@ -767,29 +774,43 @@ var ( 18: "CID_BEACON_TIMING", 19: "CID_BEACON_FREQ", 32: "CID_DEVICE_MODE", + 64: "CID_RELAY_CONF", + 65: "CID_RELAY_END_DEVICE_CONF", + 66: "CID_RELAY_FILTER_LIST", + 67: "CID_RELAY_UPDATE_UPLINK_LIST", + 68: "CID_RELAY_CTRL_UPLINK_LIST", + 69: "CID_RELAY_CONFIGURE_FWD_LIMIT", + 70: "CID_RELAY_NOTIFY_NEW_END_DEVICE", } MACCommandIdentifier_value = map[string]int32{ - "CID_RFU_0": 0, - "CID_RESET": 1, - "CID_LINK_CHECK": 2, - "CID_LINK_ADR": 3, - "CID_DUTY_CYCLE": 4, - "CID_RX_PARAM_SETUP": 5, - "CID_DEV_STATUS": 6, - "CID_NEW_CHANNEL": 7, - "CID_RX_TIMING_SETUP": 8, - "CID_TX_PARAM_SETUP": 9, - "CID_DL_CHANNEL": 10, - "CID_REKEY": 11, - "CID_ADR_PARAM_SETUP": 12, - "CID_DEVICE_TIME": 13, - "CID_FORCE_REJOIN": 14, - "CID_REJOIN_PARAM_SETUP": 15, - "CID_PING_SLOT_INFO": 16, - "CID_PING_SLOT_CHANNEL": 17, - "CID_BEACON_TIMING": 18, - "CID_BEACON_FREQ": 19, - "CID_DEVICE_MODE": 32, + "CID_RFU_0": 0, + "CID_RESET": 1, + "CID_LINK_CHECK": 2, + "CID_LINK_ADR": 3, + "CID_DUTY_CYCLE": 4, + "CID_RX_PARAM_SETUP": 5, + "CID_DEV_STATUS": 6, + "CID_NEW_CHANNEL": 7, + "CID_RX_TIMING_SETUP": 8, + "CID_TX_PARAM_SETUP": 9, + "CID_DL_CHANNEL": 10, + "CID_REKEY": 11, + "CID_ADR_PARAM_SETUP": 12, + "CID_DEVICE_TIME": 13, + "CID_FORCE_REJOIN": 14, + "CID_REJOIN_PARAM_SETUP": 15, + "CID_PING_SLOT_INFO": 16, + "CID_PING_SLOT_CHANNEL": 17, + "CID_BEACON_TIMING": 18, + "CID_BEACON_FREQ": 19, + "CID_DEVICE_MODE": 32, + "CID_RELAY_CONF": 64, + "CID_RELAY_END_DEVICE_CONF": 65, + "CID_RELAY_FILTER_LIST": 66, + "CID_RELAY_UPDATE_UPLINK_LIST": 67, + "CID_RELAY_CTRL_UPLINK_LIST": 68, + "CID_RELAY_CONFIGURE_FWD_LIMIT": 69, + "CID_RELAY_NOTIFY_NEW_END_DEVICE": 70, } ) @@ -820,6 +841,370 @@ func (MACCommandIdentifier) EnumDescriptor() ([]byte, []int) { return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{11} } +type RelayCADPeriodicity int32 + +const ( + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND RelayCADPeriodicity = 0 + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_500_MILLISECONDS RelayCADPeriodicity = 1 + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_250_MILLISECONDS RelayCADPeriodicity = 2 + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_100_MILLISECONDS RelayCADPeriodicity = 3 + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_50_MILLISECONDS RelayCADPeriodicity = 4 + RelayCADPeriodicity_RELAY_CAD_PERIODICITY_20_MILLISECONDS RelayCADPeriodicity = 5 // sic +) + +// Enum value maps for RelayCADPeriodicity. +var ( + RelayCADPeriodicity_name = map[int32]string{ + 0: "RELAY_CAD_PERIODICITY_1_SECOND", + 1: "RELAY_CAD_PERIODICITY_500_MILLISECONDS", + 2: "RELAY_CAD_PERIODICITY_250_MILLISECONDS", + 3: "RELAY_CAD_PERIODICITY_100_MILLISECONDS", + 4: "RELAY_CAD_PERIODICITY_50_MILLISECONDS", + 5: "RELAY_CAD_PERIODICITY_20_MILLISECONDS", + } + RelayCADPeriodicity_value = map[string]int32{ + "RELAY_CAD_PERIODICITY_1_SECOND": 0, + "RELAY_CAD_PERIODICITY_500_MILLISECONDS": 1, + "RELAY_CAD_PERIODICITY_250_MILLISECONDS": 2, + "RELAY_CAD_PERIODICITY_100_MILLISECONDS": 3, + "RELAY_CAD_PERIODICITY_50_MILLISECONDS": 4, + "RELAY_CAD_PERIODICITY_20_MILLISECONDS": 5, + } +) + +func (x RelayCADPeriodicity) Enum() *RelayCADPeriodicity { + p := new(RelayCADPeriodicity) + *p = x + return p +} + +func (x RelayCADPeriodicity) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelayCADPeriodicity) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[12].Descriptor() +} + +func (RelayCADPeriodicity) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[12] +} + +func (x RelayCADPeriodicity) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelayCADPeriodicity.Descriptor instead. +func (RelayCADPeriodicity) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{12} +} + +type RelaySecondChAckOffset int32 + +const ( + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_0 RelaySecondChAckOffset = 0 // 0 kHz + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_200 RelaySecondChAckOffset = 1 // 200 kHz + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_400 RelaySecondChAckOffset = 2 // 400 kHz + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_800 RelaySecondChAckOffset = 3 // 800 kHz + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_1600 RelaySecondChAckOffset = 4 // 1.6 MHz + RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_3200 RelaySecondChAckOffset = 5 // 3.2 MHz +) + +// Enum value maps for RelaySecondChAckOffset. +var ( + RelaySecondChAckOffset_name = map[int32]string{ + 0: "RELAY_SECOND_CH_ACK_OFFSET_0", + 1: "RELAY_SECOND_CH_ACK_OFFSET_200", + 2: "RELAY_SECOND_CH_ACK_OFFSET_400", + 3: "RELAY_SECOND_CH_ACK_OFFSET_800", + 4: "RELAY_SECOND_CH_ACK_OFFSET_1600", + 5: "RELAY_SECOND_CH_ACK_OFFSET_3200", + } + RelaySecondChAckOffset_value = map[string]int32{ + "RELAY_SECOND_CH_ACK_OFFSET_0": 0, + "RELAY_SECOND_CH_ACK_OFFSET_200": 1, + "RELAY_SECOND_CH_ACK_OFFSET_400": 2, + "RELAY_SECOND_CH_ACK_OFFSET_800": 3, + "RELAY_SECOND_CH_ACK_OFFSET_1600": 4, + "RELAY_SECOND_CH_ACK_OFFSET_3200": 5, + } +) + +func (x RelaySecondChAckOffset) Enum() *RelaySecondChAckOffset { + p := new(RelaySecondChAckOffset) + *p = x + return p +} + +func (x RelaySecondChAckOffset) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelaySecondChAckOffset) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[13].Descriptor() +} + +func (RelaySecondChAckOffset) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[13] +} + +func (x RelaySecondChAckOffset) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelaySecondChAckOffset.Descriptor instead. +func (RelaySecondChAckOffset) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{13} +} + +type RelayLimitBucketSize int32 + +const ( + RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_1 RelayLimitBucketSize = 0 + RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_2 RelayLimitBucketSize = 1 + RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_4 RelayLimitBucketSize = 2 + RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_12 RelayLimitBucketSize = 3 // sic +) + +// Enum value maps for RelayLimitBucketSize. +var ( + RelayLimitBucketSize_name = map[int32]string{ + 0: "RELAY_LIMIT_BUCKET_SIZE_1", + 1: "RELAY_LIMIT_BUCKET_SIZE_2", + 2: "RELAY_LIMIT_BUCKET_SIZE_4", + 3: "RELAY_LIMIT_BUCKET_SIZE_12", + } + RelayLimitBucketSize_value = map[string]int32{ + "RELAY_LIMIT_BUCKET_SIZE_1": 0, + "RELAY_LIMIT_BUCKET_SIZE_2": 1, + "RELAY_LIMIT_BUCKET_SIZE_4": 2, + "RELAY_LIMIT_BUCKET_SIZE_12": 3, + } +) + +func (x RelayLimitBucketSize) Enum() *RelayLimitBucketSize { + p := new(RelayLimitBucketSize) + *p = x + return p +} + +func (x RelayLimitBucketSize) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelayLimitBucketSize) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[14].Descriptor() +} + +func (RelayLimitBucketSize) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[14] +} + +func (x RelayLimitBucketSize) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelayLimitBucketSize.Descriptor instead. +func (RelayLimitBucketSize) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{14} +} + +type RelaySmartEnableLevel int32 + +const ( + RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_8 RelaySmartEnableLevel = 0 + RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_16 RelaySmartEnableLevel = 1 + RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_32 RelaySmartEnableLevel = 2 + RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_64 RelaySmartEnableLevel = 3 +) + +// Enum value maps for RelaySmartEnableLevel. +var ( + RelaySmartEnableLevel_name = map[int32]string{ + 0: "RELAY_SMART_ENABLE_LEVEL_8", + 1: "RELAY_SMART_ENABLE_LEVEL_16", + 2: "RELAY_SMART_ENABLE_LEVEL_32", + 3: "RELAY_SMART_ENABLE_LEVEL_64", + } + RelaySmartEnableLevel_value = map[string]int32{ + "RELAY_SMART_ENABLE_LEVEL_8": 0, + "RELAY_SMART_ENABLE_LEVEL_16": 1, + "RELAY_SMART_ENABLE_LEVEL_32": 2, + "RELAY_SMART_ENABLE_LEVEL_64": 3, + } +) + +func (x RelaySmartEnableLevel) Enum() *RelaySmartEnableLevel { + p := new(RelaySmartEnableLevel) + *p = x + return p +} + +func (x RelaySmartEnableLevel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelaySmartEnableLevel) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[15].Descriptor() +} + +func (RelaySmartEnableLevel) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[15] +} + +func (x RelaySmartEnableLevel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelaySmartEnableLevel.Descriptor instead. +func (RelaySmartEnableLevel) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{15} +} + +type RelayWORChannel int32 + +const ( + RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT RelayWORChannel = 0 + RelayWORChannel_RELAY_WOR_CHANNEL_SECONDARY RelayWORChannel = 1 +) + +// Enum value maps for RelayWORChannel. +var ( + RelayWORChannel_name = map[int32]string{ + 0: "RELAY_WOR_CHANNEL_DEFAULT", + 1: "RELAY_WOR_CHANNEL_SECONDARY", + } + RelayWORChannel_value = map[string]int32{ + "RELAY_WOR_CHANNEL_DEFAULT": 0, + "RELAY_WOR_CHANNEL_SECONDARY": 1, + } +) + +func (x RelayWORChannel) Enum() *RelayWORChannel { + p := new(RelayWORChannel) + *p = x + return p +} + +func (x RelayWORChannel) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelayWORChannel) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[16].Descriptor() +} + +func (RelayWORChannel) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[16] +} + +func (x RelayWORChannel) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelayWORChannel.Descriptor instead. +func (RelayWORChannel) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{16} +} + +type RelayResetLimitCounter int32 + +const ( + RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_ZERO RelayResetLimitCounter = 0 + RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE RelayResetLimitCounter = 1 + RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_MAX_VALUE RelayResetLimitCounter = 2 + RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_NO_RESET RelayResetLimitCounter = 3 +) + +// Enum value maps for RelayResetLimitCounter. +var ( + RelayResetLimitCounter_name = map[int32]string{ + 0: "RELAY_RESET_LIMIT_COUNTER_ZERO", + 1: "RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE", + 2: "RELAY_RESET_LIMIT_COUNTER_MAX_VALUE", + 3: "RELAY_RESET_LIMIT_COUNTER_NO_RESET", + } + RelayResetLimitCounter_value = map[string]int32{ + "RELAY_RESET_LIMIT_COUNTER_ZERO": 0, + "RELAY_RESET_LIMIT_COUNTER_RELOAD_RATE": 1, + "RELAY_RESET_LIMIT_COUNTER_MAX_VALUE": 2, + "RELAY_RESET_LIMIT_COUNTER_NO_RESET": 3, + } +) + +func (x RelayResetLimitCounter) Enum() *RelayResetLimitCounter { + p := new(RelayResetLimitCounter) + *p = x + return p +} + +func (x RelayResetLimitCounter) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelayResetLimitCounter) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[17].Descriptor() +} + +func (RelayResetLimitCounter) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[17] +} + +func (x RelayResetLimitCounter) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelayResetLimitCounter.Descriptor instead. +func (RelayResetLimitCounter) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{17} +} + +type RelayCtrlUplinkListAction int32 + +const ( + RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT RelayCtrlUplinkListAction = 0 + RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE RelayCtrlUplinkListAction = 1 +) + +// Enum value maps for RelayCtrlUplinkListAction. +var ( + RelayCtrlUplinkListAction_name = map[int32]string{ + 0: "RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT", + 1: "RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE", + } + RelayCtrlUplinkListAction_value = map[string]int32{ + "RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT": 0, + "RELAY_CTRL_UPLINK_LIST_ACTION_REMOVE_TRUSTED_END_DEVICE": 1, + } +) + +func (x RelayCtrlUplinkListAction) Enum() *RelayCtrlUplinkListAction { + p := new(RelayCtrlUplinkListAction) + *p = x + return p +} + +func (x RelayCtrlUplinkListAction) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RelayCtrlUplinkListAction) Descriptor() protoreflect.EnumDescriptor { + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[18].Descriptor() +} + +func (RelayCtrlUplinkListAction) Type() protoreflect.EnumType { + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[18] +} + +func (x RelayCtrlUplinkListAction) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RelayCtrlUplinkListAction.Descriptor instead. +func (RelayCtrlUplinkListAction) EnumDescriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{18} +} + type AggregatedDutyCycle int32 const ( @@ -892,11 +1277,11 @@ func (x AggregatedDutyCycle) String() string { } func (AggregatedDutyCycle) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[12].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[19].Descriptor() } func (AggregatedDutyCycle) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[12] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[19] } func (x AggregatedDutyCycle) Number() protoreflect.EnumNumber { @@ -905,7 +1290,7 @@ func (x AggregatedDutyCycle) Number() protoreflect.EnumNumber { // Deprecated: Use AggregatedDutyCycle.Descriptor instead. func (AggregatedDutyCycle) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{12} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{19} } type PingSlotPeriod int32 @@ -956,11 +1341,11 @@ func (x PingSlotPeriod) String() string { } func (PingSlotPeriod) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[13].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[20].Descriptor() } func (PingSlotPeriod) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[13] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[20] } func (x PingSlotPeriod) Number() protoreflect.EnumNumber { @@ -969,7 +1354,7 @@ func (x PingSlotPeriod) Number() protoreflect.EnumNumber { // Deprecated: Use PingSlotPeriod.Descriptor instead. func (PingSlotPeriod) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{13} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20} } type RejoinCountExponent int32 @@ -1044,11 +1429,11 @@ func (x RejoinCountExponent) String() string { } func (RejoinCountExponent) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[14].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[21].Descriptor() } func (RejoinCountExponent) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[14] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[21] } func (x RejoinCountExponent) Number() protoreflect.EnumNumber { @@ -1057,7 +1442,7 @@ func (x RejoinCountExponent) Number() protoreflect.EnumNumber { // Deprecated: Use RejoinCountExponent.Descriptor instead. func (RejoinCountExponent) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{14} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{21} } type RejoinTimeExponent int32 @@ -1132,11 +1517,11 @@ func (x RejoinTimeExponent) String() string { } func (RejoinTimeExponent) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[15].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[22].Descriptor() } func (RejoinTimeExponent) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[15] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[22] } func (x RejoinTimeExponent) Number() protoreflect.EnumNumber { @@ -1145,7 +1530,7 @@ func (x RejoinTimeExponent) Number() protoreflect.EnumNumber { // Deprecated: Use RejoinTimeExponent.Descriptor instead. func (RejoinTimeExponent) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{15} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{22} } type RejoinPeriodExponent int32 @@ -1196,11 +1581,11 @@ func (x RejoinPeriodExponent) String() string { } func (RejoinPeriodExponent) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[16].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[23].Descriptor() } func (RejoinPeriodExponent) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[16] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[23] } func (x RejoinPeriodExponent) Number() protoreflect.EnumNumber { @@ -1209,7 +1594,7 @@ func (x RejoinPeriodExponent) Number() protoreflect.EnumNumber { // Deprecated: Use RejoinPeriodExponent.Descriptor instead. func (RejoinPeriodExponent) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{16} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{23} } type DeviceEIRP int32 @@ -1284,11 +1669,11 @@ func (x DeviceEIRP) String() string { } func (DeviceEIRP) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[17].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[24].Descriptor() } func (DeviceEIRP) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[17] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[24] } func (x DeviceEIRP) Number() protoreflect.EnumNumber { @@ -1297,7 +1682,7 @@ func (x DeviceEIRP) Number() protoreflect.EnumNumber { // Deprecated: Use DeviceEIRP.Descriptor instead. func (DeviceEIRP) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{17} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{24} } type ADRAckLimitExponent int32 @@ -1372,11 +1757,11 @@ func (x ADRAckLimitExponent) String() string { } func (ADRAckLimitExponent) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[18].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[25].Descriptor() } func (ADRAckLimitExponent) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[18] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[25] } func (x ADRAckLimitExponent) Number() protoreflect.EnumNumber { @@ -1385,7 +1770,7 @@ func (x ADRAckLimitExponent) Number() protoreflect.EnumNumber { // Deprecated: Use ADRAckLimitExponent.Descriptor instead. func (ADRAckLimitExponent) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{18} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{25} } type ADRAckDelayExponent int32 @@ -1460,11 +1845,11 @@ func (x ADRAckDelayExponent) String() string { } func (ADRAckDelayExponent) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[19].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[26].Descriptor() } func (ADRAckDelayExponent) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[19] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[26] } func (x ADRAckDelayExponent) Number() protoreflect.EnumNumber { @@ -1473,7 +1858,7 @@ func (x ADRAckDelayExponent) Number() protoreflect.EnumNumber { // Deprecated: Use ADRAckDelayExponent.Descriptor instead. func (ADRAckDelayExponent) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{19} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26} } type RxDelay int32 @@ -1548,11 +1933,11 @@ func (x RxDelay) String() string { } func (RxDelay) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[20].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[27].Descriptor() } func (RxDelay) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[20] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[27] } func (x RxDelay) Number() protoreflect.EnumNumber { @@ -1561,7 +1946,7 @@ func (x RxDelay) Number() protoreflect.EnumNumber { // Deprecated: Use RxDelay.Descriptor instead. func (RxDelay) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{27} } type Minor int32 @@ -1636,11 +2021,11 @@ func (x Minor) String() string { } func (Minor) Descriptor() protoreflect.EnumDescriptor { - return file_ttn_lorawan_v3_lorawan_proto_enumTypes[21].Descriptor() + return file_ttn_lorawan_v3_lorawan_proto_enumTypes[28].Descriptor() } func (Minor) Type() protoreflect.EnumType { - return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[21] + return &file_ttn_lorawan_v3_lorawan_proto_enumTypes[28] } func (x Minor) Number() protoreflect.EnumNumber { @@ -1649,7 +2034,7 @@ func (x Minor) Number() protoreflect.EnumNumber { // Deprecated: Use Minor.Descriptor instead. func (Minor) EnumDescriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{21} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{28} } // Message represents a LoRaWAN message @@ -3250,29 +3635,336 @@ func (x *TxRequest) GetAdvanced() *structpb.Struct { return nil } -type MACCommand struct { +type RelaySecondChannel struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Cid MACCommandIdentifier `protobuf:"varint,1,opt,name=cid,proto3,enum=ttn.lorawan.v3.MACCommandIdentifier" json:"cid,omitempty"` - // Types that are assignable to Payload: - // *MACCommand_RawPayload - // *MACCommand_ResetInd_ - // *MACCommand_ResetConf_ - // *MACCommand_LinkCheckAns_ - // *MACCommand_LinkAdrReq - // *MACCommand_LinkAdrAns - // *MACCommand_DutyCycleReq_ - // *MACCommand_RxParamSetupReq_ - // *MACCommand_RxParamSetupAns_ - // *MACCommand_DevStatusAns_ - // *MACCommand_NewChannelReq_ - // *MACCommand_NewChannelAns_ - // *MACCommand_DlChannelReq - // *MACCommand_DlChannelAns - // *MACCommand_RxTimingSetupReq_ - // *MACCommand_TxParamSetupReq_ + // The frequency (Hz) offset used for the WOR acknowledgement. + AckOffset RelaySecondChAckOffset `protobuf:"varint,1,opt,name=ack_offset,json=ackOffset,proto3,enum=ttn.lorawan.v3.RelaySecondChAckOffset" json:"ack_offset,omitempty"` + // The data rate index used by the WOR and WOR acknowledgement. + DataRateIndex DataRateIndex `protobuf:"varint,2,opt,name=data_rate_index,json=dataRateIndex,proto3,enum=ttn.lorawan.v3.DataRateIndex" json:"data_rate_index,omitempty"` + // The frequency (Hz) used by the wake on radio message. + Frequency uint64 `protobuf:"varint,3,opt,name=frequency,proto3" json:"frequency,omitempty"` +} + +func (x *RelaySecondChannel) Reset() { + *x = RelaySecondChannel{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelaySecondChannel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelaySecondChannel) ProtoMessage() {} + +func (x *RelaySecondChannel) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelaySecondChannel.ProtoReflect.Descriptor instead. +func (*RelaySecondChannel) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20} +} + +func (x *RelaySecondChannel) GetAckOffset() RelaySecondChAckOffset { + if x != nil { + return x.AckOffset + } + return RelaySecondChAckOffset_RELAY_SECOND_CH_ACK_OFFSET_0 +} + +func (x *RelaySecondChannel) GetDataRateIndex() DataRateIndex { + if x != nil { + return x.DataRateIndex + } + return DataRateIndex_DATA_RATE_0 +} + +func (x *RelaySecondChannel) GetFrequency() uint64 { + if x != nil { + return x.Frequency + } + return 0 +} + +type RelayUplinkForwardLimits struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The multiplier used to compute the total bucket size for the limits. + // The multiplier is multiplied by the reload rate in order to compute the total bucket size. + BucketSize RelayLimitBucketSize `protobuf:"varint,1,opt,name=bucket_size,json=bucketSize,proto3,enum=ttn.lorawan.v3.RelayLimitBucketSize" json:"bucket_size,omitempty"` + // The number of tokens which are replenished in the bucket every hour. + ReloadRate uint32 `protobuf:"varint,2,opt,name=reload_rate,json=reloadRate,proto3" json:"reload_rate,omitempty"` +} + +func (x *RelayUplinkForwardLimits) Reset() { + *x = RelayUplinkForwardLimits{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayUplinkForwardLimits) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayUplinkForwardLimits) ProtoMessage() {} + +func (x *RelayUplinkForwardLimits) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayUplinkForwardLimits.ProtoReflect.Descriptor instead. +func (*RelayUplinkForwardLimits) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{21} +} + +func (x *RelayUplinkForwardLimits) GetBucketSize() RelayLimitBucketSize { + if x != nil { + return x.BucketSize + } + return RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_1 +} + +func (x *RelayUplinkForwardLimits) GetReloadRate() uint32 { + if x != nil { + return x.ReloadRate + } + return 0 +} + +type RelayForwardLimits struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The multiplier used to compute the total bucket size for the limits. + // The multiplier is multiplied by the reload rate in order to compute the total bucket size. + BucketSize RelayLimitBucketSize `protobuf:"varint,1,opt,name=bucket_size,json=bucketSize,proto3,enum=ttn.lorawan.v3.RelayLimitBucketSize" json:"bucket_size,omitempty"` + // The number of tokens which are replenished in the bucket every hour. + ReloadRate uint32 `protobuf:"varint,2,opt,name=reload_rate,json=reloadRate,proto3" json:"reload_rate,omitempty"` +} + +func (x *RelayForwardLimits) Reset() { + *x = RelayForwardLimits{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayForwardLimits) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayForwardLimits) ProtoMessage() {} + +func (x *RelayForwardLimits) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayForwardLimits.ProtoReflect.Descriptor instead. +func (*RelayForwardLimits) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{22} +} + +func (x *RelayForwardLimits) GetBucketSize() RelayLimitBucketSize { + if x != nil { + return x.BucketSize + } + return RelayLimitBucketSize_RELAY_LIMIT_BUCKET_SIZE_1 +} + +func (x *RelayForwardLimits) GetReloadRate() uint32 { + if x != nil { + return x.ReloadRate + } + return 0 +} + +type RelayEndDeviceAlwaysMode struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RelayEndDeviceAlwaysMode) Reset() { + *x = RelayEndDeviceAlwaysMode{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayEndDeviceAlwaysMode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayEndDeviceAlwaysMode) ProtoMessage() {} + +func (x *RelayEndDeviceAlwaysMode) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayEndDeviceAlwaysMode.ProtoReflect.Descriptor instead. +func (*RelayEndDeviceAlwaysMode) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{23} +} + +type RelayEndDeviceDynamicMode struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The number of consecutive uplinks without a valid downlink before the end device attempts + // to use the relay mode to transmit messages. + SmartEnableLevel RelaySmartEnableLevel `protobuf:"varint,1,opt,name=smart_enable_level,json=smartEnableLevel,proto3,enum=ttn.lorawan.v3.RelaySmartEnableLevel" json:"smart_enable_level,omitempty"` +} + +func (x *RelayEndDeviceDynamicMode) Reset() { + *x = RelayEndDeviceDynamicMode{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayEndDeviceDynamicMode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayEndDeviceDynamicMode) ProtoMessage() {} + +func (x *RelayEndDeviceDynamicMode) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayEndDeviceDynamicMode.ProtoReflect.Descriptor instead. +func (*RelayEndDeviceDynamicMode) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{24} +} + +func (x *RelayEndDeviceDynamicMode) GetSmartEnableLevel() RelaySmartEnableLevel { + if x != nil { + return x.SmartEnableLevel + } + return RelaySmartEnableLevel_RELAY_SMART_ENABLE_LEVEL_8 +} + +type RelayEndDeviceControlledMode struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RelayEndDeviceControlledMode) Reset() { + *x = RelayEndDeviceControlledMode{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayEndDeviceControlledMode) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayEndDeviceControlledMode) ProtoMessage() {} + +func (x *RelayEndDeviceControlledMode) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayEndDeviceControlledMode.ProtoReflect.Descriptor instead. +func (*RelayEndDeviceControlledMode) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{25} +} + +type MACCommand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cid MACCommandIdentifier `protobuf:"varint,1,opt,name=cid,proto3,enum=ttn.lorawan.v3.MACCommandIdentifier" json:"cid,omitempty"` + // Types that are assignable to Payload: + // *MACCommand_RawPayload + // *MACCommand_ResetInd_ + // *MACCommand_ResetConf_ + // *MACCommand_LinkCheckAns_ + // *MACCommand_LinkAdrReq + // *MACCommand_LinkAdrAns + // *MACCommand_DutyCycleReq_ + // *MACCommand_RxParamSetupReq_ + // *MACCommand_RxParamSetupAns_ + // *MACCommand_DevStatusAns_ + // *MACCommand_NewChannelReq_ + // *MACCommand_NewChannelAns_ + // *MACCommand_DlChannelReq + // *MACCommand_DlChannelAns + // *MACCommand_RxTimingSetupReq_ + // *MACCommand_TxParamSetupReq_ // *MACCommand_RekeyInd_ // *MACCommand_RekeyConf_ // *MACCommand_AdrParamSetupReq @@ -3288,13 +3980,24 @@ type MACCommand struct { // *MACCommand_BeaconFreqAns_ // *MACCommand_DeviceModeInd_ // *MACCommand_DeviceModeConf_ + // *MACCommand_RelayConfReq_ + // *MACCommand_RelayConfAns_ + // *MACCommand_RelayEndDeviceConfReq_ + // *MACCommand_RelayEndDeviceConfAns_ + // *MACCommand_RelayUpdateUplinkListReq_ + // *MACCommand_RelayUpdateUplinkListAns_ + // *MACCommand_RelayCtrlUplinkListReq_ + // *MACCommand_RelayCtrlUplinkListAns_ + // *MACCommand_RelayConfigureFwdLimitReq_ + // *MACCommand_RelayConfigureFwdLimitAns_ + // *MACCommand_RelayNotifyNewEndDeviceReq_ Payload isMACCommand_Payload `protobuf_oneof:"payload"` } func (x *MACCommand) Reset() { *x = MACCommand{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3307,7 +4010,7 @@ func (x *MACCommand) String() string { func (*MACCommand) ProtoMessage() {} func (x *MACCommand) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[20] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3320,7 +4023,7 @@ func (x *MACCommand) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand.ProtoReflect.Descriptor instead. func (*MACCommand) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26} } func (x *MACCommand) GetCid() MACCommandIdentifier { @@ -3554,12 +4257,89 @@ func (x *MACCommand) GetDeviceModeConf() *MACCommand_DeviceModeConf { return nil } -type isMACCommand_Payload interface { - isMACCommand_Payload() +func (x *MACCommand) GetRelayConfReq() *MACCommand_RelayConfReq { + if x, ok := x.GetPayload().(*MACCommand_RelayConfReq_); ok { + return x.RelayConfReq + } + return nil } -type MACCommand_RawPayload struct { - RawPayload []byte `protobuf:"bytes,2,opt,name=raw_payload,json=rawPayload,proto3,oneof"` +func (x *MACCommand) GetRelayConfAns() *MACCommand_RelayConfAns { + if x, ok := x.GetPayload().(*MACCommand_RelayConfAns_); ok { + return x.RelayConfAns + } + return nil +} + +func (x *MACCommand) GetRelayEndDeviceConfReq() *MACCommand_RelayEndDeviceConfReq { + if x, ok := x.GetPayload().(*MACCommand_RelayEndDeviceConfReq_); ok { + return x.RelayEndDeviceConfReq + } + return nil +} + +func (x *MACCommand) GetRelayEndDeviceConfAns() *MACCommand_RelayEndDeviceConfAns { + if x, ok := x.GetPayload().(*MACCommand_RelayEndDeviceConfAns_); ok { + return x.RelayEndDeviceConfAns + } + return nil +} + +func (x *MACCommand) GetRelayUpdateUplinkListReq() *MACCommand_RelayUpdateUplinkListReq { + if x, ok := x.GetPayload().(*MACCommand_RelayUpdateUplinkListReq_); ok { + return x.RelayUpdateUplinkListReq + } + return nil +} + +func (x *MACCommand) GetRelayUpdateUplinkListAns() *MACCommand_RelayUpdateUplinkListAns { + if x, ok := x.GetPayload().(*MACCommand_RelayUpdateUplinkListAns_); ok { + return x.RelayUpdateUplinkListAns + } + return nil +} + +func (x *MACCommand) GetRelayCtrlUplinkListReq() *MACCommand_RelayCtrlUplinkListReq { + if x, ok := x.GetPayload().(*MACCommand_RelayCtrlUplinkListReq_); ok { + return x.RelayCtrlUplinkListReq + } + return nil +} + +func (x *MACCommand) GetRelayCtrlUplinkListAns() *MACCommand_RelayCtrlUplinkListAns { + if x, ok := x.GetPayload().(*MACCommand_RelayCtrlUplinkListAns_); ok { + return x.RelayCtrlUplinkListAns + } + return nil +} + +func (x *MACCommand) GetRelayConfigureFwdLimitReq() *MACCommand_RelayConfigureFwdLimitReq { + if x, ok := x.GetPayload().(*MACCommand_RelayConfigureFwdLimitReq_); ok { + return x.RelayConfigureFwdLimitReq + } + return nil +} + +func (x *MACCommand) GetRelayConfigureFwdLimitAns() *MACCommand_RelayConfigureFwdLimitAns { + if x, ok := x.GetPayload().(*MACCommand_RelayConfigureFwdLimitAns_); ok { + return x.RelayConfigureFwdLimitAns + } + return nil +} + +func (x *MACCommand) GetRelayNotifyNewEndDeviceReq() *MACCommand_RelayNotifyNewEndDeviceReq { + if x, ok := x.GetPayload().(*MACCommand_RelayNotifyNewEndDeviceReq_); ok { + return x.RelayNotifyNewEndDeviceReq + } + return nil +} + +type isMACCommand_Payload interface { + isMACCommand_Payload() +} + +type MACCommand_RawPayload struct { + RawPayload []byte `protobuf:"bytes,2,opt,name=raw_payload,json=rawPayload,proto3,oneof"` } type MACCommand_ResetInd_ struct { @@ -3682,6 +4462,50 @@ type MACCommand_DeviceModeConf_ struct { DeviceModeConf *MACCommand_DeviceModeConf `protobuf:"bytes,32,opt,name=device_mode_conf,json=deviceModeConf,proto3,oneof"` } +type MACCommand_RelayConfReq_ struct { + RelayConfReq *MACCommand_RelayConfReq `protobuf:"bytes,33,opt,name=relay_conf_req,json=relayConfReq,proto3,oneof"` +} + +type MACCommand_RelayConfAns_ struct { + RelayConfAns *MACCommand_RelayConfAns `protobuf:"bytes,34,opt,name=relay_conf_ans,json=relayConfAns,proto3,oneof"` +} + +type MACCommand_RelayEndDeviceConfReq_ struct { + RelayEndDeviceConfReq *MACCommand_RelayEndDeviceConfReq `protobuf:"bytes,35,opt,name=relay_end_device_conf_req,json=relayEndDeviceConfReq,proto3,oneof"` +} + +type MACCommand_RelayEndDeviceConfAns_ struct { + RelayEndDeviceConfAns *MACCommand_RelayEndDeviceConfAns `protobuf:"bytes,36,opt,name=relay_end_device_conf_ans,json=relayEndDeviceConfAns,proto3,oneof"` +} + +type MACCommand_RelayUpdateUplinkListReq_ struct { + RelayUpdateUplinkListReq *MACCommand_RelayUpdateUplinkListReq `protobuf:"bytes,39,opt,name=relay_update_uplink_list_req,json=relayUpdateUplinkListReq,proto3,oneof"` +} + +type MACCommand_RelayUpdateUplinkListAns_ struct { + RelayUpdateUplinkListAns *MACCommand_RelayUpdateUplinkListAns `protobuf:"bytes,40,opt,name=relay_update_uplink_list_ans,json=relayUpdateUplinkListAns,proto3,oneof"` +} + +type MACCommand_RelayCtrlUplinkListReq_ struct { + RelayCtrlUplinkListReq *MACCommand_RelayCtrlUplinkListReq `protobuf:"bytes,41,opt,name=relay_ctrl_uplink_list_req,json=relayCtrlUplinkListReq,proto3,oneof"` +} + +type MACCommand_RelayCtrlUplinkListAns_ struct { + RelayCtrlUplinkListAns *MACCommand_RelayCtrlUplinkListAns `protobuf:"bytes,42,opt,name=relay_ctrl_uplink_list_ans,json=relayCtrlUplinkListAns,proto3,oneof"` +} + +type MACCommand_RelayConfigureFwdLimitReq_ struct { + RelayConfigureFwdLimitReq *MACCommand_RelayConfigureFwdLimitReq `protobuf:"bytes,43,opt,name=relay_configure_fwd_limit_req,json=relayConfigureFwdLimitReq,proto3,oneof"` +} + +type MACCommand_RelayConfigureFwdLimitAns_ struct { + RelayConfigureFwdLimitAns *MACCommand_RelayConfigureFwdLimitAns `protobuf:"bytes,44,opt,name=relay_configure_fwd_limit_ans,json=relayConfigureFwdLimitAns,proto3,oneof"` +} + +type MACCommand_RelayNotifyNewEndDeviceReq_ struct { + RelayNotifyNewEndDeviceReq *MACCommand_RelayNotifyNewEndDeviceReq `protobuf:"bytes,45,opt,name=relay_notify_new_end_device_req,json=relayNotifyNewEndDeviceReq,proto3,oneof"` +} + func (*MACCommand_RawPayload) isMACCommand_Payload() {} func (*MACCommand_ResetInd_) isMACCommand_Payload() {} @@ -3744,6 +4568,28 @@ func (*MACCommand_DeviceModeInd_) isMACCommand_Payload() {} func (*MACCommand_DeviceModeConf_) isMACCommand_Payload() {} +func (*MACCommand_RelayConfReq_) isMACCommand_Payload() {} + +func (*MACCommand_RelayConfAns_) isMACCommand_Payload() {} + +func (*MACCommand_RelayEndDeviceConfReq_) isMACCommand_Payload() {} + +func (*MACCommand_RelayEndDeviceConfAns_) isMACCommand_Payload() {} + +func (*MACCommand_RelayUpdateUplinkListReq_) isMACCommand_Payload() {} + +func (*MACCommand_RelayUpdateUplinkListAns_) isMACCommand_Payload() {} + +func (*MACCommand_RelayCtrlUplinkListReq_) isMACCommand_Payload() {} + +func (*MACCommand_RelayCtrlUplinkListAns_) isMACCommand_Payload() {} + +func (*MACCommand_RelayConfigureFwdLimitReq_) isMACCommand_Payload() {} + +func (*MACCommand_RelayConfigureFwdLimitAns_) isMACCommand_Payload() {} + +func (*MACCommand_RelayNotifyNewEndDeviceReq_) isMACCommand_Payload() {} + type MACCommands struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3755,7 +4601,7 @@ type MACCommands struct { func (x *MACCommands) Reset() { *x = MACCommands{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3768,7 +4614,7 @@ func (x *MACCommands) String() string { func (*MACCommands) ProtoMessage() {} func (x *MACCommands) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[21] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3781,7 +4627,7 @@ func (x *MACCommands) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommands.ProtoReflect.Descriptor instead. func (*MACCommands) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{21} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{27} } func (x *MACCommands) GetCommands() []*MACCommand { @@ -3802,7 +4648,7 @@ type FrequencyValue struct { func (x *FrequencyValue) Reset() { *x = FrequencyValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3815,7 +4661,7 @@ func (x *FrequencyValue) String() string { func (*FrequencyValue) ProtoMessage() {} func (x *FrequencyValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[22] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3828,7 +4674,7 @@ func (x *FrequencyValue) ProtoReflect() protoreflect.Message { // Deprecated: Use FrequencyValue.ProtoReflect.Descriptor instead. func (*FrequencyValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{22} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{28} } func (x *FrequencyValue) GetValue() uint64 { @@ -3849,7 +4695,7 @@ type ZeroableFrequencyValue struct { func (x *ZeroableFrequencyValue) Reset() { *x = ZeroableFrequencyValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3862,7 +4708,7 @@ func (x *ZeroableFrequencyValue) String() string { func (*ZeroableFrequencyValue) ProtoMessage() {} func (x *ZeroableFrequencyValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[23] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3875,7 +4721,7 @@ func (x *ZeroableFrequencyValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ZeroableFrequencyValue.ProtoReflect.Descriptor instead. func (*ZeroableFrequencyValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{23} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{29} } func (x *ZeroableFrequencyValue) GetValue() uint64 { @@ -3896,7 +4742,7 @@ type DataRateOffsetValue struct { func (x *DataRateOffsetValue) Reset() { *x = DataRateOffsetValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3909,7 +4755,7 @@ func (x *DataRateOffsetValue) String() string { func (*DataRateOffsetValue) ProtoMessage() {} func (x *DataRateOffsetValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[24] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3922,7 +4768,7 @@ func (x *DataRateOffsetValue) ProtoReflect() protoreflect.Message { // Deprecated: Use DataRateOffsetValue.ProtoReflect.Descriptor instead. func (*DataRateOffsetValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{24} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{30} } func (x *DataRateOffsetValue) GetValue() DataRateOffset { @@ -3943,7 +4789,7 @@ type DataRateIndexValue struct { func (x *DataRateIndexValue) Reset() { *x = DataRateIndexValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[25] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3956,7 +4802,7 @@ func (x *DataRateIndexValue) String() string { func (*DataRateIndexValue) ProtoMessage() {} func (x *DataRateIndexValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[25] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3969,7 +4815,7 @@ func (x *DataRateIndexValue) ProtoReflect() protoreflect.Message { // Deprecated: Use DataRateIndexValue.ProtoReflect.Descriptor instead. func (*DataRateIndexValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{25} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{31} } func (x *DataRateIndexValue) GetValue() DataRateIndex { @@ -3990,7 +4836,7 @@ type PingSlotPeriodValue struct { func (x *PingSlotPeriodValue) Reset() { *x = PingSlotPeriodValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[26] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4003,7 +4849,7 @@ func (x *PingSlotPeriodValue) String() string { func (*PingSlotPeriodValue) ProtoMessage() {} func (x *PingSlotPeriodValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[26] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4016,7 +4862,7 @@ func (x *PingSlotPeriodValue) ProtoReflect() protoreflect.Message { // Deprecated: Use PingSlotPeriodValue.ProtoReflect.Descriptor instead. func (*PingSlotPeriodValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{32} } func (x *PingSlotPeriodValue) GetValue() PingSlotPeriod { @@ -4037,7 +4883,7 @@ type AggregatedDutyCycleValue struct { func (x *AggregatedDutyCycleValue) Reset() { *x = AggregatedDutyCycleValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[27] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4050,7 +4896,7 @@ func (x *AggregatedDutyCycleValue) String() string { func (*AggregatedDutyCycleValue) ProtoMessage() {} func (x *AggregatedDutyCycleValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[27] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4063,7 +4909,7 @@ func (x *AggregatedDutyCycleValue) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatedDutyCycleValue.ProtoReflect.Descriptor instead. func (*AggregatedDutyCycleValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{27} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{33} } func (x *AggregatedDutyCycleValue) GetValue() AggregatedDutyCycle { @@ -4084,7 +4930,7 @@ type RxDelayValue struct { func (x *RxDelayValue) Reset() { *x = RxDelayValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[28] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4097,7 +4943,7 @@ func (x *RxDelayValue) String() string { func (*RxDelayValue) ProtoMessage() {} func (x *RxDelayValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[28] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4110,7 +4956,7 @@ func (x *RxDelayValue) ProtoReflect() protoreflect.Message { // Deprecated: Use RxDelayValue.ProtoReflect.Descriptor instead. func (*RxDelayValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{28} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{34} } func (x *RxDelayValue) GetValue() RxDelay { @@ -4131,7 +4977,7 @@ type ADRAckLimitExponentValue struct { func (x *ADRAckLimitExponentValue) Reset() { *x = ADRAckLimitExponentValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[29] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4144,7 +4990,7 @@ func (x *ADRAckLimitExponentValue) String() string { func (*ADRAckLimitExponentValue) ProtoMessage() {} func (x *ADRAckLimitExponentValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[29] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4157,7 +5003,7 @@ func (x *ADRAckLimitExponentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRAckLimitExponentValue.ProtoReflect.Descriptor instead. func (*ADRAckLimitExponentValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{29} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{35} } func (x *ADRAckLimitExponentValue) GetValue() ADRAckLimitExponent { @@ -4178,7 +5024,7 @@ type ADRAckDelayExponentValue struct { func (x *ADRAckDelayExponentValue) Reset() { *x = ADRAckDelayExponentValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[30] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4191,7 +5037,7 @@ func (x *ADRAckDelayExponentValue) String() string { func (*ADRAckDelayExponentValue) ProtoMessage() {} func (x *ADRAckDelayExponentValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[30] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4204,7 +5050,7 @@ func (x *ADRAckDelayExponentValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ADRAckDelayExponentValue.ProtoReflect.Descriptor instead. func (*ADRAckDelayExponentValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{30} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{36} } func (x *ADRAckDelayExponentValue) GetValue() ADRAckDelayExponent { @@ -4225,7 +5071,7 @@ type DeviceEIRPValue struct { func (x *DeviceEIRPValue) Reset() { *x = DeviceEIRPValue{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[31] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4238,7 +5084,7 @@ func (x *DeviceEIRPValue) String() string { func (*DeviceEIRPValue) ProtoMessage() {} func (x *DeviceEIRPValue) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[31] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4251,7 +5097,7 @@ func (x *DeviceEIRPValue) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceEIRPValue.ProtoReflect.Descriptor instead. func (*DeviceEIRPValue) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{31} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{37} } func (x *DeviceEIRPValue) GetValue() DeviceEIRP { @@ -4261,37 +5107,36 @@ func (x *DeviceEIRPValue) GetValue() DeviceEIRP { return DeviceEIRP_DEVICE_EIRP_8 } -// Transmission settings for downlink. -type TxSettings_Downlink struct { +type RelayForwardUplinkReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Index of the antenna on which the uplink was received and/or downlink must be sent. - AntennaIndex uint32 `protobuf:"varint,1,opt,name=antenna_index,json=antennaIndex,proto3" json:"antenna_index,omitempty"` - // Transmission power (dBm). Only on downlink. - TxPower float32 `protobuf:"fixed32,2,opt,name=tx_power,json=txPower,proto3" json:"tx_power,omitempty"` - // Invert LoRa polarization; false for LoRaWAN uplink, true for downlink. - InvertPolarization bool `protobuf:"varint,3,opt,name=invert_polarization,json=invertPolarization,proto3" json:"invert_polarization,omitempty"` + DataRate *DataRate `protobuf:"bytes,1,opt,name=data_rate,json=dataRate,proto3" json:"data_rate,omitempty"` + Snr int32 `protobuf:"varint,2,opt,name=snr,proto3" json:"snr,omitempty"` + Rssi int32 `protobuf:"varint,3,opt,name=rssi,proto3" json:"rssi,omitempty"` + WorChannel RelayWORChannel `protobuf:"varint,4,opt,name=wor_channel,json=worChannel,proto3,enum=ttn.lorawan.v3.RelayWORChannel" json:"wor_channel,omitempty"` + Frequency uint64 `protobuf:"varint,5,opt,name=frequency,proto3" json:"frequency,omitempty"` // Uplink channel frequency (Hz). + RawPayload []byte `protobuf:"bytes,6,opt,name=raw_payload,json=rawPayload,proto3" json:"raw_payload,omitempty"` } -func (x *TxSettings_Downlink) Reset() { - *x = TxSettings_Downlink{} +func (x *RelayForwardUplinkReq) Reset() { + *x = RelayForwardUplinkReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[32] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *TxSettings_Downlink) String() string { +func (x *RelayForwardUplinkReq) String() string { return protoimpl.X.MessageStringOf(x) } -func (*TxSettings_Downlink) ProtoMessage() {} +func (*RelayForwardUplinkReq) ProtoMessage() {} -func (x *TxSettings_Downlink) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[32] +func (x *RelayForwardUplinkReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4302,57 +5147,78 @@ func (x *TxSettings_Downlink) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use TxSettings_Downlink.ProtoReflect.Descriptor instead. -func (*TxSettings_Downlink) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{14, 0} +// Deprecated: Use RelayForwardUplinkReq.ProtoReflect.Descriptor instead. +func (*RelayForwardUplinkReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{38} } -func (x *TxSettings_Downlink) GetAntennaIndex() uint32 { +func (x *RelayForwardUplinkReq) GetDataRate() *DataRate { if x != nil { - return x.AntennaIndex + return x.DataRate + } + return nil +} + +func (x *RelayForwardUplinkReq) GetSnr() int32 { + if x != nil { + return x.Snr } return 0 } -func (x *TxSettings_Downlink) GetTxPower() float32 { +func (x *RelayForwardUplinkReq) GetRssi() int32 { if x != nil { - return x.TxPower + return x.Rssi } return 0 } -func (x *TxSettings_Downlink) GetInvertPolarization() bool { +func (x *RelayForwardUplinkReq) GetWorChannel() RelayWORChannel { if x != nil { - return x.InvertPolarization + return x.WorChannel } - return false + return RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT } -type MACCommand_ResetInd struct { +func (x *RelayForwardUplinkReq) GetFrequency() uint64 { + if x != nil { + return x.Frequency + } + return 0 +} + +func (x *RelayForwardUplinkReq) GetRawPayload() []byte { + if x != nil { + return x.RawPayload + } + return nil +} + +type RelayForwardDownlinkReq struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MinorVersion Minor `protobuf:"varint,1,opt,name=minor_version,json=minorVersion,proto3,enum=ttn.lorawan.v3.Minor" json:"minor_version,omitempty"` + RawPayload []byte `protobuf:"bytes,1,opt,name=raw_payload,json=rawPayload,proto3" json:"raw_payload,omitempty"` } -func (x *MACCommand_ResetInd) Reset() { - *x = MACCommand_ResetInd{} +func (x *RelayForwardDownlinkReq) Reset() { + *x = RelayForwardDownlinkReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[33] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *MACCommand_ResetInd) String() string { +func (x *RelayForwardDownlinkReq) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MACCommand_ResetInd) ProtoMessage() {} +func (*RelayForwardDownlinkReq) ProtoMessage() {} -func (x *MACCommand_ResetInd) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[33] +func (x *RelayForwardDownlinkReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4363,43 +5229,45 @@ func (x *MACCommand_ResetInd) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MACCommand_ResetInd.ProtoReflect.Descriptor instead. -func (*MACCommand_ResetInd) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 0} +// Deprecated: Use RelayForwardDownlinkReq.ProtoReflect.Descriptor instead. +func (*RelayForwardDownlinkReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{39} } -func (x *MACCommand_ResetInd) GetMinorVersion() Minor { +func (x *RelayForwardDownlinkReq) GetRawPayload() []byte { if x != nil { - return x.MinorVersion + return x.RawPayload } - return Minor_MINOR_RFU_0 + return nil } -type MACCommand_ResetConf struct { +type RelayUplinkToken struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MinorVersion Minor `protobuf:"varint,1,opt,name=minor_version,json=minorVersion,proto3,enum=ttn.lorawan.v3.Minor" json:"minor_version,omitempty"` + Ids *EndDeviceIdentifiers `protobuf:"bytes,1,opt,name=ids,proto3" json:"ids,omitempty"` + SessionKeyId []byte `protobuf:"bytes,2,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"` + FullFCnt uint32 `protobuf:"varint,3,opt,name=full_f_cnt,json=fullFCnt,proto3" json:"full_f_cnt,omitempty"` } -func (x *MACCommand_ResetConf) Reset() { - *x = MACCommand_ResetConf{} +func (x *RelayUplinkToken) Reset() { + *x = RelayUplinkToken{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[34] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *MACCommand_ResetConf) String() string { +func (x *RelayUplinkToken) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MACCommand_ResetConf) ProtoMessage() {} +func (*RelayUplinkToken) ProtoMessage() {} -func (x *MACCommand_ResetConf) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[34] +func (x *RelayUplinkToken) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4410,45 +5278,63 @@ func (x *MACCommand_ResetConf) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MACCommand_ResetConf.ProtoReflect.Descriptor instead. -func (*MACCommand_ResetConf) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 1} +// Deprecated: Use RelayUplinkToken.ProtoReflect.Descriptor instead. +func (*RelayUplinkToken) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{40} } -func (x *MACCommand_ResetConf) GetMinorVersion() Minor { +func (x *RelayUplinkToken) GetIds() *EndDeviceIdentifiers { if x != nil { - return x.MinorVersion + return x.Ids } - return Minor_MINOR_RFU_0 + return nil } -type MACCommand_LinkCheckAns struct { +func (x *RelayUplinkToken) GetSessionKeyId() []byte { + if x != nil { + return x.SessionKeyId + } + return nil +} + +func (x *RelayUplinkToken) GetFullFCnt() uint32 { + if x != nil { + return x.FullFCnt + } + return 0 +} + +// Transmission settings for downlink. +type TxSettings_Downlink struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // Indicates the link margin in dB of the received LinkCheckReq, relative to the demodulation floor. - Margin uint32 `protobuf:"varint,1,opt,name=margin,proto3" json:"margin,omitempty"` - GatewayCount uint32 `protobuf:"varint,2,opt,name=gateway_count,json=gatewayCount,proto3" json:"gateway_count,omitempty"` + // Index of the antenna on which the uplink was received and/or downlink must be sent. + AntennaIndex uint32 `protobuf:"varint,1,opt,name=antenna_index,json=antennaIndex,proto3" json:"antenna_index,omitempty"` + // Transmission power (dBm). Only on downlink. + TxPower float32 `protobuf:"fixed32,2,opt,name=tx_power,json=txPower,proto3" json:"tx_power,omitempty"` + // Invert LoRa polarization; false for LoRaWAN uplink, true for downlink. + InvertPolarization bool `protobuf:"varint,3,opt,name=invert_polarization,json=invertPolarization,proto3" json:"invert_polarization,omitempty"` } -func (x *MACCommand_LinkCheckAns) Reset() { - *x = MACCommand_LinkCheckAns{} +func (x *TxSettings_Downlink) Reset() { + *x = TxSettings_Downlink{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[35] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *MACCommand_LinkCheckAns) String() string { +func (x *TxSettings_Downlink) String() string { return protoimpl.X.MessageStringOf(x) } -func (*MACCommand_LinkCheckAns) ProtoMessage() {} +func (*TxSettings_Downlink) ProtoMessage() {} -func (x *MACCommand_LinkCheckAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[35] +func (x *TxSettings_Downlink) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4459,9 +5345,166 @@ func (x *MACCommand_LinkCheckAns) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use MACCommand_LinkCheckAns.ProtoReflect.Descriptor instead. +// Deprecated: Use TxSettings_Downlink.ProtoReflect.Descriptor instead. +func (*TxSettings_Downlink) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{14, 0} +} + +func (x *TxSettings_Downlink) GetAntennaIndex() uint32 { + if x != nil { + return x.AntennaIndex + } + return 0 +} + +func (x *TxSettings_Downlink) GetTxPower() float32 { + if x != nil { + return x.TxPower + } + return 0 +} + +func (x *TxSettings_Downlink) GetInvertPolarization() bool { + if x != nil { + return x.InvertPolarization + } + return false +} + +type MACCommand_ResetInd struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MinorVersion Minor `protobuf:"varint,1,opt,name=minor_version,json=minorVersion,proto3,enum=ttn.lorawan.v3.Minor" json:"minor_version,omitempty"` +} + +func (x *MACCommand_ResetInd) Reset() { + *x = MACCommand_ResetInd{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_ResetInd) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_ResetInd) ProtoMessage() {} + +func (x *MACCommand_ResetInd) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_ResetInd.ProtoReflect.Descriptor instead. +func (*MACCommand_ResetInd) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 0} +} + +func (x *MACCommand_ResetInd) GetMinorVersion() Minor { + if x != nil { + return x.MinorVersion + } + return Minor_MINOR_RFU_0 +} + +type MACCommand_ResetConf struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MinorVersion Minor `protobuf:"varint,1,opt,name=minor_version,json=minorVersion,proto3,enum=ttn.lorawan.v3.Minor" json:"minor_version,omitempty"` +} + +func (x *MACCommand_ResetConf) Reset() { + *x = MACCommand_ResetConf{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_ResetConf) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_ResetConf) ProtoMessage() {} + +func (x *MACCommand_ResetConf) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_ResetConf.ProtoReflect.Descriptor instead. +func (*MACCommand_ResetConf) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 1} +} + +func (x *MACCommand_ResetConf) GetMinorVersion() Minor { + if x != nil { + return x.MinorVersion + } + return Minor_MINOR_RFU_0 +} + +type MACCommand_LinkCheckAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Indicates the link margin in dB of the received LinkCheckReq, relative to the demodulation floor. + Margin uint32 `protobuf:"varint,1,opt,name=margin,proto3" json:"margin,omitempty"` + GatewayCount uint32 `protobuf:"varint,2,opt,name=gateway_count,json=gatewayCount,proto3" json:"gateway_count,omitempty"` +} + +func (x *MACCommand_LinkCheckAns) Reset() { + *x = MACCommand_LinkCheckAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_LinkCheckAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_LinkCheckAns) ProtoMessage() {} + +func (x *MACCommand_LinkCheckAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_LinkCheckAns.ProtoReflect.Descriptor instead. func (*MACCommand_LinkCheckAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 2} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 2} } func (x *MACCommand_LinkCheckAns) GetMargin() uint32 { @@ -4493,7 +5536,7 @@ type MACCommand_LinkADRReq struct { func (x *MACCommand_LinkADRReq) Reset() { *x = MACCommand_LinkADRReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[36] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4506,7 +5549,7 @@ func (x *MACCommand_LinkADRReq) String() string { func (*MACCommand_LinkADRReq) ProtoMessage() {} func (x *MACCommand_LinkADRReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[36] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[45] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4519,7 +5562,7 @@ func (x *MACCommand_LinkADRReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_LinkADRReq.ProtoReflect.Descriptor instead. func (*MACCommand_LinkADRReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 3} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 3} } func (x *MACCommand_LinkADRReq) GetDataRateIndex() DataRateIndex { @@ -4570,7 +5613,7 @@ type MACCommand_LinkADRAns struct { func (x *MACCommand_LinkADRAns) Reset() { *x = MACCommand_LinkADRAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[37] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4583,7 +5626,7 @@ func (x *MACCommand_LinkADRAns) String() string { func (*MACCommand_LinkADRAns) ProtoMessage() {} func (x *MACCommand_LinkADRAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[37] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[46] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4596,7 +5639,7 @@ func (x *MACCommand_LinkADRAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_LinkADRAns.ProtoReflect.Descriptor instead. func (*MACCommand_LinkADRAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 4} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 4} } func (x *MACCommand_LinkADRAns) GetChannelMaskAck() bool { @@ -4631,7 +5674,7 @@ type MACCommand_DutyCycleReq struct { func (x *MACCommand_DutyCycleReq) Reset() { *x = MACCommand_DutyCycleReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[38] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4644,7 +5687,7 @@ func (x *MACCommand_DutyCycleReq) String() string { func (*MACCommand_DutyCycleReq) ProtoMessage() {} func (x *MACCommand_DutyCycleReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[38] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[47] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4657,7 +5700,7 @@ func (x *MACCommand_DutyCycleReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DutyCycleReq.ProtoReflect.Descriptor instead. func (*MACCommand_DutyCycleReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 5} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 5} } func (x *MACCommand_DutyCycleReq) GetMaxDutyCycle() AggregatedDutyCycle { @@ -4680,7 +5723,7 @@ type MACCommand_RxParamSetupReq struct { func (x *MACCommand_RxParamSetupReq) Reset() { *x = MACCommand_RxParamSetupReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[39] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4693,7 +5736,7 @@ func (x *MACCommand_RxParamSetupReq) String() string { func (*MACCommand_RxParamSetupReq) ProtoMessage() {} func (x *MACCommand_RxParamSetupReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[39] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[48] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4706,7 +5749,7 @@ func (x *MACCommand_RxParamSetupReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RxParamSetupReq.ProtoReflect.Descriptor instead. func (*MACCommand_RxParamSetupReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 6} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 6} } func (x *MACCommand_RxParamSetupReq) GetRx2DataRateIndex() DataRateIndex { @@ -4743,7 +5786,7 @@ type MACCommand_RxParamSetupAns struct { func (x *MACCommand_RxParamSetupAns) Reset() { *x = MACCommand_RxParamSetupAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[40] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4756,7 +5799,7 @@ func (x *MACCommand_RxParamSetupAns) String() string { func (*MACCommand_RxParamSetupAns) ProtoMessage() {} func (x *MACCommand_RxParamSetupAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[40] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[49] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4769,7 +5812,7 @@ func (x *MACCommand_RxParamSetupAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RxParamSetupAns.ProtoReflect.Descriptor instead. func (*MACCommand_RxParamSetupAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 7} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 7} } func (x *MACCommand_RxParamSetupAns) GetRx2DataRateIndexAck() bool { @@ -4810,7 +5853,7 @@ type MACCommand_DevStatusAns struct { func (x *MACCommand_DevStatusAns) Reset() { *x = MACCommand_DevStatusAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[41] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4823,7 +5866,7 @@ func (x *MACCommand_DevStatusAns) String() string { func (*MACCommand_DevStatusAns) ProtoMessage() {} func (x *MACCommand_DevStatusAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[41] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[50] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4836,7 +5879,7 @@ func (x *MACCommand_DevStatusAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DevStatusAns.ProtoReflect.Descriptor instead. func (*MACCommand_DevStatusAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 8} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 8} } func (x *MACCommand_DevStatusAns) GetBattery() uint32 { @@ -4867,7 +5910,7 @@ type MACCommand_NewChannelReq struct { func (x *MACCommand_NewChannelReq) Reset() { *x = MACCommand_NewChannelReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[42] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4880,7 +5923,7 @@ func (x *MACCommand_NewChannelReq) String() string { func (*MACCommand_NewChannelReq) ProtoMessage() {} func (x *MACCommand_NewChannelReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[42] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[51] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4893,7 +5936,7 @@ func (x *MACCommand_NewChannelReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_NewChannelReq.ProtoReflect.Descriptor instead. func (*MACCommand_NewChannelReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 9} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 9} } func (x *MACCommand_NewChannelReq) GetChannelIndex() uint32 { @@ -4936,7 +5979,7 @@ type MACCommand_NewChannelAns struct { func (x *MACCommand_NewChannelAns) Reset() { *x = MACCommand_NewChannelAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[43] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4949,7 +5992,7 @@ func (x *MACCommand_NewChannelAns) String() string { func (*MACCommand_NewChannelAns) ProtoMessage() {} func (x *MACCommand_NewChannelAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[43] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[52] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4962,7 +6005,7 @@ func (x *MACCommand_NewChannelAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_NewChannelAns.ProtoReflect.Descriptor instead. func (*MACCommand_NewChannelAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 10} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 10} } func (x *MACCommand_NewChannelAns) GetFrequencyAck() bool { @@ -4991,7 +6034,7 @@ type MACCommand_DLChannelReq struct { func (x *MACCommand_DLChannelReq) Reset() { *x = MACCommand_DLChannelReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[44] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5004,7 +6047,7 @@ func (x *MACCommand_DLChannelReq) String() string { func (*MACCommand_DLChannelReq) ProtoMessage() {} func (x *MACCommand_DLChannelReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[44] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[53] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5017,7 +6060,7 @@ func (x *MACCommand_DLChannelReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DLChannelReq.ProtoReflect.Descriptor instead. func (*MACCommand_DLChannelReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 11} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 11} } func (x *MACCommand_DLChannelReq) GetChannelIndex() uint32 { @@ -5046,7 +6089,7 @@ type MACCommand_DLChannelAns struct { func (x *MACCommand_DLChannelAns) Reset() { *x = MACCommand_DLChannelAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[45] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5059,7 +6102,7 @@ func (x *MACCommand_DLChannelAns) String() string { func (*MACCommand_DLChannelAns) ProtoMessage() {} func (x *MACCommand_DLChannelAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[45] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[54] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5072,7 +6115,7 @@ func (x *MACCommand_DLChannelAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DLChannelAns.ProtoReflect.Descriptor instead. func (*MACCommand_DLChannelAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 12} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 12} } func (x *MACCommand_DLChannelAns) GetChannelIndexAck() bool { @@ -5100,7 +6143,7 @@ type MACCommand_RxTimingSetupReq struct { func (x *MACCommand_RxTimingSetupReq) Reset() { *x = MACCommand_RxTimingSetupReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[46] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5113,7 +6156,7 @@ func (x *MACCommand_RxTimingSetupReq) String() string { func (*MACCommand_RxTimingSetupReq) ProtoMessage() {} func (x *MACCommand_RxTimingSetupReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[46] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[55] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5126,7 +6169,7 @@ func (x *MACCommand_RxTimingSetupReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RxTimingSetupReq.ProtoReflect.Descriptor instead. func (*MACCommand_RxTimingSetupReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 13} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 13} } func (x *MACCommand_RxTimingSetupReq) GetDelay() RxDelay { @@ -5151,7 +6194,7 @@ type MACCommand_TxParamSetupReq struct { func (x *MACCommand_TxParamSetupReq) Reset() { *x = MACCommand_TxParamSetupReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[47] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5164,7 +6207,7 @@ func (x *MACCommand_TxParamSetupReq) String() string { func (*MACCommand_TxParamSetupReq) ProtoMessage() {} func (x *MACCommand_TxParamSetupReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[47] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[56] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5177,7 +6220,7 @@ func (x *MACCommand_TxParamSetupReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_TxParamSetupReq.ProtoReflect.Descriptor instead. func (*MACCommand_TxParamSetupReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 14} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 14} } func (x *MACCommand_TxParamSetupReq) GetMaxEirpIndex() DeviceEIRP { @@ -5212,7 +6255,7 @@ type MACCommand_RekeyInd struct { func (x *MACCommand_RekeyInd) Reset() { *x = MACCommand_RekeyInd{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[48] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5225,7 +6268,7 @@ func (x *MACCommand_RekeyInd) String() string { func (*MACCommand_RekeyInd) ProtoMessage() {} func (x *MACCommand_RekeyInd) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[48] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[57] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5238,7 +6281,7 @@ func (x *MACCommand_RekeyInd) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RekeyInd.ProtoReflect.Descriptor instead. func (*MACCommand_RekeyInd) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 15} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 15} } func (x *MACCommand_RekeyInd) GetMinorVersion() Minor { @@ -5259,7 +6302,7 @@ type MACCommand_RekeyConf struct { func (x *MACCommand_RekeyConf) Reset() { *x = MACCommand_RekeyConf{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[49] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5272,7 +6315,7 @@ func (x *MACCommand_RekeyConf) String() string { func (*MACCommand_RekeyConf) ProtoMessage() {} func (x *MACCommand_RekeyConf) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[49] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[58] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5285,7 +6328,7 @@ func (x *MACCommand_RekeyConf) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RekeyConf.ProtoReflect.Descriptor instead. func (*MACCommand_RekeyConf) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 16} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 16} } func (x *MACCommand_RekeyConf) GetMinorVersion() Minor { @@ -5309,7 +6352,7 @@ type MACCommand_ADRParamSetupReq struct { func (x *MACCommand_ADRParamSetupReq) Reset() { *x = MACCommand_ADRParamSetupReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[50] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5322,7 +6365,7 @@ func (x *MACCommand_ADRParamSetupReq) String() string { func (*MACCommand_ADRParamSetupReq) ProtoMessage() {} func (x *MACCommand_ADRParamSetupReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[50] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[59] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5335,7 +6378,7 @@ func (x *MACCommand_ADRParamSetupReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_ADRParamSetupReq.ProtoReflect.Descriptor instead. func (*MACCommand_ADRParamSetupReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 17} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 17} } func (x *MACCommand_ADRParamSetupReq) GetAdrAckLimitExponent() ADRAckLimitExponent { @@ -5363,7 +6406,7 @@ type MACCommand_DeviceTimeAns struct { func (x *MACCommand_DeviceTimeAns) Reset() { *x = MACCommand_DeviceTimeAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[51] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5376,7 +6419,7 @@ func (x *MACCommand_DeviceTimeAns) String() string { func (*MACCommand_DeviceTimeAns) ProtoMessage() {} func (x *MACCommand_DeviceTimeAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[51] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[60] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5389,7 +6432,7 @@ func (x *MACCommand_DeviceTimeAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DeviceTimeAns.ProtoReflect.Descriptor instead. func (*MACCommand_DeviceTimeAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 18} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 18} } func (x *MACCommand_DeviceTimeAns) GetTime() *timestamppb.Timestamp { @@ -5414,7 +6457,7 @@ type MACCommand_ForceRejoinReq struct { func (x *MACCommand_ForceRejoinReq) Reset() { *x = MACCommand_ForceRejoinReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[52] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5427,7 +6470,7 @@ func (x *MACCommand_ForceRejoinReq) String() string { func (*MACCommand_ForceRejoinReq) ProtoMessage() {} func (x *MACCommand_ForceRejoinReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[52] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[61] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5440,7 +6483,7 @@ func (x *MACCommand_ForceRejoinReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_ForceRejoinReq.ProtoReflect.Descriptor instead. func (*MACCommand_ForceRejoinReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 19} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 19} } func (x *MACCommand_ForceRejoinReq) GetRejoinType() RejoinRequestType { @@ -5485,7 +6528,7 @@ type MACCommand_RejoinParamSetupReq struct { func (x *MACCommand_RejoinParamSetupReq) Reset() { *x = MACCommand_RejoinParamSetupReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[53] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5498,7 +6541,7 @@ func (x *MACCommand_RejoinParamSetupReq) String() string { func (*MACCommand_RejoinParamSetupReq) ProtoMessage() {} func (x *MACCommand_RejoinParamSetupReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[53] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[62] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5511,7 +6554,7 @@ func (x *MACCommand_RejoinParamSetupReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RejoinParamSetupReq.ProtoReflect.Descriptor instead. func (*MACCommand_RejoinParamSetupReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 20} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 20} } func (x *MACCommand_RejoinParamSetupReq) GetMaxCountExponent() RejoinCountExponent { @@ -5539,7 +6582,7 @@ type MACCommand_RejoinParamSetupAns struct { func (x *MACCommand_RejoinParamSetupAns) Reset() { *x = MACCommand_RejoinParamSetupAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[54] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5552,7 +6595,7 @@ func (x *MACCommand_RejoinParamSetupAns) String() string { func (*MACCommand_RejoinParamSetupAns) ProtoMessage() {} func (x *MACCommand_RejoinParamSetupAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[54] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[63] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5565,7 +6608,7 @@ func (x *MACCommand_RejoinParamSetupAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_RejoinParamSetupAns.ProtoReflect.Descriptor instead. func (*MACCommand_RejoinParamSetupAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 21} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 21} } func (x *MACCommand_RejoinParamSetupAns) GetMaxTimeExponentAck() bool { @@ -5586,7 +6629,7 @@ type MACCommand_PingSlotInfoReq struct { func (x *MACCommand_PingSlotInfoReq) Reset() { *x = MACCommand_PingSlotInfoReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[55] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5599,7 +6642,7 @@ func (x *MACCommand_PingSlotInfoReq) String() string { func (*MACCommand_PingSlotInfoReq) ProtoMessage() {} func (x *MACCommand_PingSlotInfoReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[55] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[64] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5612,7 +6655,7 @@ func (x *MACCommand_PingSlotInfoReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_PingSlotInfoReq.ProtoReflect.Descriptor instead. func (*MACCommand_PingSlotInfoReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 22} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 22} } func (x *MACCommand_PingSlotInfoReq) GetPeriod() PingSlotPeriod { @@ -5634,7 +6677,7 @@ type MACCommand_PingSlotChannelReq struct { func (x *MACCommand_PingSlotChannelReq) Reset() { *x = MACCommand_PingSlotChannelReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[56] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5647,7 +6690,7 @@ func (x *MACCommand_PingSlotChannelReq) String() string { func (*MACCommand_PingSlotChannelReq) ProtoMessage() {} func (x *MACCommand_PingSlotChannelReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[56] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[65] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5660,7 +6703,7 @@ func (x *MACCommand_PingSlotChannelReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_PingSlotChannelReq.ProtoReflect.Descriptor instead. func (*MACCommand_PingSlotChannelReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 23} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 23} } func (x *MACCommand_PingSlotChannelReq) GetFrequency() uint64 { @@ -5689,7 +6732,7 @@ type MACCommand_PingSlotChannelAns struct { func (x *MACCommand_PingSlotChannelAns) Reset() { *x = MACCommand_PingSlotChannelAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[57] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5702,7 +6745,7 @@ func (x *MACCommand_PingSlotChannelAns) String() string { func (*MACCommand_PingSlotChannelAns) ProtoMessage() {} func (x *MACCommand_PingSlotChannelAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[57] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[66] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5715,7 +6758,7 @@ func (x *MACCommand_PingSlotChannelAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_PingSlotChannelAns.ProtoReflect.Descriptor instead. func (*MACCommand_PingSlotChannelAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 24} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 24} } func (x *MACCommand_PingSlotChannelAns) GetFrequencyAck() bool { @@ -5744,7 +6787,7 @@ type MACCommand_BeaconTimingAns struct { func (x *MACCommand_BeaconTimingAns) Reset() { *x = MACCommand_BeaconTimingAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[58] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5757,7 +6800,7 @@ func (x *MACCommand_BeaconTimingAns) String() string { func (*MACCommand_BeaconTimingAns) ProtoMessage() {} func (x *MACCommand_BeaconTimingAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[58] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[67] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5770,7 +6813,7 @@ func (x *MACCommand_BeaconTimingAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_BeaconTimingAns.ProtoReflect.Descriptor instead. func (*MACCommand_BeaconTimingAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 25} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 25} } func (x *MACCommand_BeaconTimingAns) GetDelay() uint32 { @@ -5798,7 +6841,7 @@ type MACCommand_BeaconFreqReq struct { func (x *MACCommand_BeaconFreqReq) Reset() { *x = MACCommand_BeaconFreqReq{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[59] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5811,7 +6854,7 @@ func (x *MACCommand_BeaconFreqReq) String() string { func (*MACCommand_BeaconFreqReq) ProtoMessage() {} func (x *MACCommand_BeaconFreqReq) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[59] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[68] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5824,7 +6867,7 @@ func (x *MACCommand_BeaconFreqReq) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_BeaconFreqReq.ProtoReflect.Descriptor instead. func (*MACCommand_BeaconFreqReq) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 26} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 26} } func (x *MACCommand_BeaconFreqReq) GetFrequency() uint64 { @@ -5845,7 +6888,7 @@ type MACCommand_BeaconFreqAns struct { func (x *MACCommand_BeaconFreqAns) Reset() { *x = MACCommand_BeaconFreqAns{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[60] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5858,7 +6901,7 @@ func (x *MACCommand_BeaconFreqAns) String() string { func (*MACCommand_BeaconFreqAns) ProtoMessage() {} func (x *MACCommand_BeaconFreqAns) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[60] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[69] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5871,7 +6914,7 @@ func (x *MACCommand_BeaconFreqAns) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_BeaconFreqAns.ProtoReflect.Descriptor instead. func (*MACCommand_BeaconFreqAns) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 27} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 27} } func (x *MACCommand_BeaconFreqAns) GetFrequencyAck() bool { @@ -5892,7 +6935,7 @@ type MACCommand_DeviceModeInd struct { func (x *MACCommand_DeviceModeInd) Reset() { *x = MACCommand_DeviceModeInd{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[61] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5905,7 +6948,7 @@ func (x *MACCommand_DeviceModeInd) String() string { func (*MACCommand_DeviceModeInd) ProtoMessage() {} func (x *MACCommand_DeviceModeInd) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[61] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[70] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5918,7 +6961,7 @@ func (x *MACCommand_DeviceModeInd) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DeviceModeInd.ProtoReflect.Descriptor instead. func (*MACCommand_DeviceModeInd) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 28} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 28} } func (x *MACCommand_DeviceModeInd) GetClass() Class { @@ -5939,7 +6982,7 @@ type MACCommand_DeviceModeConf struct { func (x *MACCommand_DeviceModeConf) Reset() { *x = MACCommand_DeviceModeConf{} if protoimpl.UnsafeEnabled { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[62] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5952,7 +6995,7 @@ func (x *MACCommand_DeviceModeConf) String() string { func (*MACCommand_DeviceModeConf) ProtoMessage() {} func (x *MACCommand_DeviceModeConf) ProtoReflect() protoreflect.Message { - mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[62] + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[71] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5965,7 +7008,7 @@ func (x *MACCommand_DeviceModeConf) ProtoReflect() protoreflect.Message { // Deprecated: Use MACCommand_DeviceModeConf.ProtoReflect.Descriptor instead. func (*MACCommand_DeviceModeConf) Descriptor() ([]byte, []int) { - return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{20, 29} + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 29} } func (x *MACCommand_DeviceModeConf) GetClass() Class { @@ -5975,14 +7018,873 @@ func (x *MACCommand_DeviceModeConf) GetClass() Class { return Class_CLASS_A } -var File_ttn_lorawan_v3_lorawan_proto protoreflect.FileDescriptor +type MACCommand_RelayConfReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ - 0x0a, 0x1c, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, - 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x1a, 0x1c, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, - 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, + Configuration *MACCommand_RelayConfReq_Configuration `protobuf:"bytes,1,opt,name=configuration,proto3" json:"configuration,omitempty"` +} + +func (x *MACCommand_RelayConfReq) Reset() { + *x = MACCommand_RelayConfReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[72] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayConfReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayConfReq) ProtoMessage() {} + +func (x *MACCommand_RelayConfReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[72] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayConfReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayConfReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 30} +} + +func (x *MACCommand_RelayConfReq) GetConfiguration() *MACCommand_RelayConfReq_Configuration { + if x != nil { + return x.Configuration + } + return nil +} + +type MACCommand_RelayConfAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SecondChannelFrequencyAck bool `protobuf:"varint,1,opt,name=second_channel_frequency_ack,json=secondChannelFrequencyAck,proto3" json:"second_channel_frequency_ack,omitempty"` + SecondChannelAckOffsetAck bool `protobuf:"varint,2,opt,name=second_channel_ack_offset_ack,json=secondChannelAckOffsetAck,proto3" json:"second_channel_ack_offset_ack,omitempty"` + SecondChannelDataRateIndexAck bool `protobuf:"varint,3,opt,name=second_channel_data_rate_index_ack,json=secondChannelDataRateIndexAck,proto3" json:"second_channel_data_rate_index_ack,omitempty"` + SecondChannelIndexAck bool `protobuf:"varint,4,opt,name=second_channel_index_ack,json=secondChannelIndexAck,proto3" json:"second_channel_index_ack,omitempty"` + DefaultChannelIndexAck bool `protobuf:"varint,5,opt,name=default_channel_index_ack,json=defaultChannelIndexAck,proto3" json:"default_channel_index_ack,omitempty"` + CadPeriodicityAck bool `protobuf:"varint,6,opt,name=cad_periodicity_ack,json=cadPeriodicityAck,proto3" json:"cad_periodicity_ack,omitempty"` +} + +func (x *MACCommand_RelayConfAns) Reset() { + *x = MACCommand_RelayConfAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[73] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayConfAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayConfAns) ProtoMessage() {} + +func (x *MACCommand_RelayConfAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[73] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayConfAns.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayConfAns) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 31} +} + +func (x *MACCommand_RelayConfAns) GetSecondChannelFrequencyAck() bool { + if x != nil { + return x.SecondChannelFrequencyAck + } + return false +} + +func (x *MACCommand_RelayConfAns) GetSecondChannelAckOffsetAck() bool { + if x != nil { + return x.SecondChannelAckOffsetAck + } + return false +} + +func (x *MACCommand_RelayConfAns) GetSecondChannelDataRateIndexAck() bool { + if x != nil { + return x.SecondChannelDataRateIndexAck + } + return false +} + +func (x *MACCommand_RelayConfAns) GetSecondChannelIndexAck() bool { + if x != nil { + return x.SecondChannelIndexAck + } + return false +} + +func (x *MACCommand_RelayConfAns) GetDefaultChannelIndexAck() bool { + if x != nil { + return x.DefaultChannelIndexAck + } + return false +} + +func (x *MACCommand_RelayConfAns) GetCadPeriodicityAck() bool { + if x != nil { + return x.CadPeriodicityAck + } + return false +} + +type MACCommand_RelayEndDeviceConfReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Configuration *MACCommand_RelayEndDeviceConfReq_Configuration `protobuf:"bytes,1,opt,name=configuration,proto3" json:"configuration,omitempty"` +} + +func (x *MACCommand_RelayEndDeviceConfReq) Reset() { + *x = MACCommand_RelayEndDeviceConfReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[74] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayEndDeviceConfReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayEndDeviceConfReq) ProtoMessage() {} + +func (x *MACCommand_RelayEndDeviceConfReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[74] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayEndDeviceConfReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayEndDeviceConfReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 32} +} + +func (x *MACCommand_RelayEndDeviceConfReq) GetConfiguration() *MACCommand_RelayEndDeviceConfReq_Configuration { + if x != nil { + return x.Configuration + } + return nil +} + +type MACCommand_RelayEndDeviceConfAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SecondChannelFrequencyAck bool `protobuf:"varint,1,opt,name=second_channel_frequency_ack,json=secondChannelFrequencyAck,proto3" json:"second_channel_frequency_ack,omitempty"` + SecondChannelDataRateIndexAck bool `protobuf:"varint,3,opt,name=second_channel_data_rate_index_ack,json=secondChannelDataRateIndexAck,proto3" json:"second_channel_data_rate_index_ack,omitempty"` + SecondChannelIndexAck bool `protobuf:"varint,4,opt,name=second_channel_index_ack,json=secondChannelIndexAck,proto3" json:"second_channel_index_ack,omitempty"` + BackoffAck bool `protobuf:"varint,5,opt,name=backoff_ack,json=backoffAck,proto3" json:"backoff_ack,omitempty"` +} + +func (x *MACCommand_RelayEndDeviceConfAns) Reset() { + *x = MACCommand_RelayEndDeviceConfAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[75] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayEndDeviceConfAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayEndDeviceConfAns) ProtoMessage() {} + +func (x *MACCommand_RelayEndDeviceConfAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[75] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayEndDeviceConfAns.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayEndDeviceConfAns) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 33} +} + +func (x *MACCommand_RelayEndDeviceConfAns) GetSecondChannelFrequencyAck() bool { + if x != nil { + return x.SecondChannelFrequencyAck + } + return false +} + +func (x *MACCommand_RelayEndDeviceConfAns) GetSecondChannelDataRateIndexAck() bool { + if x != nil { + return x.SecondChannelDataRateIndexAck + } + return false +} + +func (x *MACCommand_RelayEndDeviceConfAns) GetSecondChannelIndexAck() bool { + if x != nil { + return x.SecondChannelIndexAck + } + return false +} + +func (x *MACCommand_RelayEndDeviceConfAns) GetBackoffAck() bool { + if x != nil { + return x.BackoffAck + } + return false +} + +type MACCommand_RelayUpdateUplinkListReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RuleIndex uint32 `protobuf:"varint,1,opt,name=rule_index,json=ruleIndex,proto3" json:"rule_index,omitempty"` + ForwardLimits *RelayUplinkForwardLimits `protobuf:"bytes,2,opt,name=forward_limits,json=forwardLimits,proto3" json:"forward_limits,omitempty"` + DevAddr []byte `protobuf:"bytes,3,opt,name=dev_addr,json=devAddr,proto3" json:"dev_addr,omitempty"` + WFCnt uint32 `protobuf:"varint,4,opt,name=w_f_cnt,json=wFCnt,proto3" json:"w_f_cnt,omitempty"` + RootWorSKey []byte `protobuf:"bytes,5,opt,name=root_wor_s_key,json=rootWorSKey,proto3" json:"root_wor_s_key,omitempty"` + DeviceId string `protobuf:"bytes,6,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + SessionKeyId []byte `protobuf:"bytes,7,opt,name=session_key_id,json=sessionKeyId,proto3" json:"session_key_id,omitempty"` +} + +func (x *MACCommand_RelayUpdateUplinkListReq) Reset() { + *x = MACCommand_RelayUpdateUplinkListReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[76] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayUpdateUplinkListReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayUpdateUplinkListReq) ProtoMessage() {} + +func (x *MACCommand_RelayUpdateUplinkListReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[76] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayUpdateUplinkListReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayUpdateUplinkListReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 34} +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetRuleIndex() uint32 { + if x != nil { + return x.RuleIndex + } + return 0 +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetForwardLimits() *RelayUplinkForwardLimits { + if x != nil { + return x.ForwardLimits + } + return nil +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetDevAddr() []byte { + if x != nil { + return x.DevAddr + } + return nil +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetWFCnt() uint32 { + if x != nil { + return x.WFCnt + } + return 0 +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetRootWorSKey() []byte { + if x != nil { + return x.RootWorSKey + } + return nil +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *MACCommand_RelayUpdateUplinkListReq) GetSessionKeyId() []byte { + if x != nil { + return x.SessionKeyId + } + return nil +} + +type MACCommand_RelayUpdateUplinkListAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MACCommand_RelayUpdateUplinkListAns) Reset() { + *x = MACCommand_RelayUpdateUplinkListAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[77] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayUpdateUplinkListAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayUpdateUplinkListAns) ProtoMessage() {} + +func (x *MACCommand_RelayUpdateUplinkListAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[77] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayUpdateUplinkListAns.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayUpdateUplinkListAns) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 35} +} + +type MACCommand_RelayCtrlUplinkListReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RuleIndex uint32 `protobuf:"varint,1,opt,name=rule_index,json=ruleIndex,proto3" json:"rule_index,omitempty"` + Action RelayCtrlUplinkListAction `protobuf:"varint,2,opt,name=action,proto3,enum=ttn.lorawan.v3.RelayCtrlUplinkListAction" json:"action,omitempty"` +} + +func (x *MACCommand_RelayCtrlUplinkListReq) Reset() { + *x = MACCommand_RelayCtrlUplinkListReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[78] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayCtrlUplinkListReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayCtrlUplinkListReq) ProtoMessage() {} + +func (x *MACCommand_RelayCtrlUplinkListReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[78] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayCtrlUplinkListReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayCtrlUplinkListReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 36} +} + +func (x *MACCommand_RelayCtrlUplinkListReq) GetRuleIndex() uint32 { + if x != nil { + return x.RuleIndex + } + return 0 +} + +func (x *MACCommand_RelayCtrlUplinkListReq) GetAction() RelayCtrlUplinkListAction { + if x != nil { + return x.Action + } + return RelayCtrlUplinkListAction_RELAY_CTRL_UPLINK_LIST_ACTION_READ_W_F_CNT +} + +type MACCommand_RelayCtrlUplinkListAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RuleIndexAck bool `protobuf:"varint,1,opt,name=rule_index_ack,json=ruleIndexAck,proto3" json:"rule_index_ack,omitempty"` + WFCnt uint32 `protobuf:"varint,2,opt,name=w_f_cnt,json=wFCnt,proto3" json:"w_f_cnt,omitempty"` +} + +func (x *MACCommand_RelayCtrlUplinkListAns) Reset() { + *x = MACCommand_RelayCtrlUplinkListAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[79] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayCtrlUplinkListAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayCtrlUplinkListAns) ProtoMessage() {} + +func (x *MACCommand_RelayCtrlUplinkListAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[79] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayCtrlUplinkListAns.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayCtrlUplinkListAns) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 37} +} + +func (x *MACCommand_RelayCtrlUplinkListAns) GetRuleIndexAck() bool { + if x != nil { + return x.RuleIndexAck + } + return false +} + +func (x *MACCommand_RelayCtrlUplinkListAns) GetWFCnt() uint32 { + if x != nil { + return x.WFCnt + } + return 0 +} + +type MACCommand_RelayConfigureFwdLimitReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResetLimitCounter RelayResetLimitCounter `protobuf:"varint,1,opt,name=reset_limit_counter,json=resetLimitCounter,proto3,enum=ttn.lorawan.v3.RelayResetLimitCounter" json:"reset_limit_counter,omitempty"` + JoinRequestLimits *RelayForwardLimits `protobuf:"bytes,2,opt,name=join_request_limits,json=joinRequestLimits,proto3" json:"join_request_limits,omitempty"` + NotifyLimits *RelayForwardLimits `protobuf:"bytes,3,opt,name=notify_limits,json=notifyLimits,proto3" json:"notify_limits,omitempty"` + GlobalUplinkLimits *RelayForwardLimits `protobuf:"bytes,4,opt,name=global_uplink_limits,json=globalUplinkLimits,proto3" json:"global_uplink_limits,omitempty"` + OverallLimits *RelayForwardLimits `protobuf:"bytes,5,opt,name=overall_limits,json=overallLimits,proto3" json:"overall_limits,omitempty"` +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) Reset() { + *x = MACCommand_RelayConfigureFwdLimitReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[80] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayConfigureFwdLimitReq) ProtoMessage() {} + +func (x *MACCommand_RelayConfigureFwdLimitReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[80] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayConfigureFwdLimitReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayConfigureFwdLimitReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 38} +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) GetResetLimitCounter() RelayResetLimitCounter { + if x != nil { + return x.ResetLimitCounter + } + return RelayResetLimitCounter_RELAY_RESET_LIMIT_COUNTER_ZERO +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) GetJoinRequestLimits() *RelayForwardLimits { + if x != nil { + return x.JoinRequestLimits + } + return nil +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) GetNotifyLimits() *RelayForwardLimits { + if x != nil { + return x.NotifyLimits + } + return nil +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) GetGlobalUplinkLimits() *RelayForwardLimits { + if x != nil { + return x.GlobalUplinkLimits + } + return nil +} + +func (x *MACCommand_RelayConfigureFwdLimitReq) GetOverallLimits() *RelayForwardLimits { + if x != nil { + return x.OverallLimits + } + return nil +} + +type MACCommand_RelayConfigureFwdLimitAns struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MACCommand_RelayConfigureFwdLimitAns) Reset() { + *x = MACCommand_RelayConfigureFwdLimitAns{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[81] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayConfigureFwdLimitAns) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayConfigureFwdLimitAns) ProtoMessage() {} + +func (x *MACCommand_RelayConfigureFwdLimitAns) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[81] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayConfigureFwdLimitAns.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayConfigureFwdLimitAns) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 39} +} + +type MACCommand_RelayNotifyNewEndDeviceReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DevAddr []byte `protobuf:"bytes,1,opt,name=dev_addr,json=devAddr,proto3" json:"dev_addr,omitempty"` + Snr int32 `protobuf:"varint,2,opt,name=snr,proto3" json:"snr,omitempty"` + Rssi int32 `protobuf:"varint,3,opt,name=rssi,proto3" json:"rssi,omitempty"` +} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) Reset() { + *x = MACCommand_RelayNotifyNewEndDeviceReq{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[82] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayNotifyNewEndDeviceReq) ProtoMessage() {} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[82] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayNotifyNewEndDeviceReq.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayNotifyNewEndDeviceReq) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 40} +} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) GetDevAddr() []byte { + if x != nil { + return x.DevAddr + } + return nil +} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) GetSnr() int32 { + if x != nil { + return x.Snr + } + return 0 +} + +func (x *MACCommand_RelayNotifyNewEndDeviceReq) GetRssi() int32 { + if x != nil { + return x.Rssi + } + return 0 +} + +type MACCommand_RelayConfReq_Configuration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SecondChannel *RelaySecondChannel `protobuf:"bytes,1,opt,name=second_channel,json=secondChannel,proto3" json:"second_channel,omitempty"` + DefaultChannelIndex uint32 `protobuf:"varint,2,opt,name=default_channel_index,json=defaultChannelIndex,proto3" json:"default_channel_index,omitempty"` + CadPeriodicity RelayCADPeriodicity `protobuf:"varint,3,opt,name=cad_periodicity,json=cadPeriodicity,proto3,enum=ttn.lorawan.v3.RelayCADPeriodicity" json:"cad_periodicity,omitempty"` +} + +func (x *MACCommand_RelayConfReq_Configuration) Reset() { + *x = MACCommand_RelayConfReq_Configuration{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[83] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayConfReq_Configuration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayConfReq_Configuration) ProtoMessage() {} + +func (x *MACCommand_RelayConfReq_Configuration) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[83] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayConfReq_Configuration.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayConfReq_Configuration) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 30, 0} +} + +func (x *MACCommand_RelayConfReq_Configuration) GetSecondChannel() *RelaySecondChannel { + if x != nil { + return x.SecondChannel + } + return nil +} + +func (x *MACCommand_RelayConfReq_Configuration) GetDefaultChannelIndex() uint32 { + if x != nil { + return x.DefaultChannelIndex + } + return 0 +} + +func (x *MACCommand_RelayConfReq_Configuration) GetCadPeriodicity() RelayCADPeriodicity { + if x != nil { + return x.CadPeriodicity + } + return RelayCADPeriodicity_RELAY_CAD_PERIODICITY_1_SECOND +} + +type MACCommand_RelayEndDeviceConfReq_Configuration struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Mode: + // *MACCommand_RelayEndDeviceConfReq_Configuration_Always + // *MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic + // *MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled + Mode isMACCommand_RelayEndDeviceConfReq_Configuration_Mode `protobuf_oneof:"mode"` + Backoff uint32 `protobuf:"varint,4,opt,name=backoff,proto3" json:"backoff,omitempty"` + SecondChannel *RelaySecondChannel `protobuf:"bytes,5,opt,name=second_channel,json=secondChannel,proto3" json:"second_channel,omitempty"` + ServingDeviceId string `protobuf:"bytes,6,opt,name=serving_device_id,json=servingDeviceId,proto3" json:"serving_device_id,omitempty"` +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) Reset() { + *x = MACCommand_RelayEndDeviceConfReq_Configuration{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[84] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MACCommand_RelayEndDeviceConfReq_Configuration) ProtoMessage() {} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_lorawan_proto_msgTypes[84] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MACCommand_RelayEndDeviceConfReq_Configuration.ProtoReflect.Descriptor instead. +func (*MACCommand_RelayEndDeviceConfReq_Configuration) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP(), []int{26, 32, 0} +} + +func (m *MACCommand_RelayEndDeviceConfReq_Configuration) GetMode() isMACCommand_RelayEndDeviceConfReq_Configuration_Mode { + if m != nil { + return m.Mode + } + return nil +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetAlways() *RelayEndDeviceAlwaysMode { + if x, ok := x.GetMode().(*MACCommand_RelayEndDeviceConfReq_Configuration_Always); ok { + return x.Always + } + return nil +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetDynamic() *RelayEndDeviceDynamicMode { + if x, ok := x.GetMode().(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic); ok { + return x.Dynamic + } + return nil +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetEndDeviceControlled() *RelayEndDeviceControlledMode { + if x, ok := x.GetMode().(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled); ok { + return x.EndDeviceControlled + } + return nil +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetBackoff() uint32 { + if x != nil { + return x.Backoff + } + return 0 +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetSecondChannel() *RelaySecondChannel { + if x != nil { + return x.SecondChannel + } + return nil +} + +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) GetServingDeviceId() string { + if x != nil { + return x.ServingDeviceId + } + return "" +} + +type isMACCommand_RelayEndDeviceConfReq_Configuration_Mode interface { + isMACCommand_RelayEndDeviceConfReq_Configuration_Mode() +} + +type MACCommand_RelayEndDeviceConfReq_Configuration_Always struct { + Always *RelayEndDeviceAlwaysMode `protobuf:"bytes,1,opt,name=always,proto3,oneof"` +} + +type MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic struct { + Dynamic *RelayEndDeviceDynamicMode `protobuf:"bytes,2,opt,name=dynamic,proto3,oneof"` +} + +type MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled struct { + EndDeviceControlled *RelayEndDeviceControlledMode `protobuf:"bytes,3,opt,name=end_device_controlled,json=endDeviceControlled,proto3,oneof"` +} + +func (*MACCommand_RelayEndDeviceConfReq_Configuration_Always) isMACCommand_RelayEndDeviceConfReq_Configuration_Mode() { +} + +func (*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic) isMACCommand_RelayEndDeviceConfReq_Configuration_Mode() { +} + +func (*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled) isMACCommand_RelayEndDeviceConfReq_Configuration_Mode() { +} + +var File_ttn_lorawan_v3_lorawan_proto protoreflect.FileDescriptor + +var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ + 0x0a, 0x1c, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, + 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x1a, 0x1c, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, @@ -6345,10 +8247,10 @@ var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ 0x61, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x3a, 0x08, 0xf2, 0xaa, - 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x32, 0x0a, 0x0b, 0x46, 0x53, 0x4b, 0x44, 0x61, 0x74, + 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x32, 0x0a, 0x0b, 0x46, 0x53, 0x4b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x62, 0x69, 0x74, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x62, 0x69, 0x74, 0x52, 0x61, 0x74, 0x65, - 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x4c, + 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x4c, 0x52, 0x46, 0x48, 0x53, 0x53, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x61, 0x74, 0x69, @@ -6358,7 +8260,7 @@ var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ 0x6e, 0x67, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x57, 0x69, 0x64, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x61, 0x74, 0x65, 0x3a, - 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x22, 0xc6, 0x01, 0x0a, 0x08, 0x44, 0x61, + 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xc6, 0x01, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x6c, 0x6f, 0x72, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x52, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, @@ -6369,7 +8271,7 @@ var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ 0x72, 0x66, 0x68, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x52, 0x46, 0x48, 0x53, 0x53, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x6c, - 0x72, 0x66, 0x68, 0x73, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x42, + 0x72, 0x66, 0x68, 0x73, 0x73, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x42, 0x11, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x03, 0xf8, 0x42, 0x01, 0x22, 0xf9, 0x03, 0x0a, 0x0a, 0x54, 0x78, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3f, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, @@ -6401,8 +8303,8 @@ var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ 0x13, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x5f, 0x70, 0x6f, 0x6c, 0x61, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x50, 0x6f, 0x6c, 0x61, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x08, - 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x00, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, - 0x10, 0x00, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x8f, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, + 0x10, 0x01, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x8f, 0x01, 0x0a, 0x19, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x41, 0x6e, 0x74, 0x65, 0x6e, 0x6e, 0x61, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x4d, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, @@ -6490,879 +8392,1390 @@ var file_ttn_lorawan_v3_lorawan_proto_rawDesc = []byte{ 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, 0x08, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, - 0x08, 0x0b, 0x10, 0x0c, 0x22, 0xc2, 0x33, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x12, 0x42, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x10, 0x01, - 0x20, 0x00, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x72, 0x61, 0x77, 0x5f, 0x70, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, - 0x72, 0x61, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x42, 0x0a, 0x09, 0x72, 0x65, - 0x73, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, - 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x49, - 0x6e, 0x64, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x12, 0x45, - 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, - 0x65, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x4f, 0x0a, 0x0e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, 0x68, - 0x65, 0x63, 0x6b, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, + 0x08, 0x0b, 0x10, 0x0c, 0x22, 0xe9, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x4f, 0x0a, 0x0a, 0x61, + 0x63, 0x6b, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x41, 0x63, + 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x09, 0x61, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x4f, 0x0a, 0x0f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, + 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, + 0x22, 0x9f, 0x01, 0x0a, 0x18, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x4f, 0x0a, + 0x0b, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x75, + 0x63, 0x6b, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x28, + 0x0a, 0x0b, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x3e, 0x52, 0x0a, 0x72, 0x65, + 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x61, 0x74, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, + 0x10, 0x01, 0x22, 0x99, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x4f, 0x0a, 0x0b, 0x62, 0x75, 0x63, + 0x6b, 0x65, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x53, 0x69, 0x7a, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x28, 0x0a, 0x0b, 0x72, 0x65, + 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, + 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x7e, 0x52, 0x0a, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, + 0x52, 0x61, 0x74, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x24, + 0x0a, 0x18, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, + 0x08, 0x01, 0x10, 0x01, 0x22, 0x84, 0x01, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x4d, 0x6f, + 0x64, 0x65, 0x12, 0x5d, 0x0a, 0x12, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x5f, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x6d, 0x61, 0x72, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x10, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x28, 0x0a, 0x1c, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, + 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xe5, 0x5b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x42, 0x0a, 0x03, 0x63, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x10, + 0x01, 0x20, 0x00, 0x52, 0x03, 0x63, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0b, 0x72, 0x61, 0x77, 0x5f, + 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, + 0x0a, 0x72, 0x61, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x42, 0x0a, 0x09, 0x72, + 0x65, 0x73, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, + 0x49, 0x6e, 0x64, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x73, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x12, + 0x45, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, + 0x52, 0x65, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x09, 0x72, 0x65, 0x73, + 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x4f, 0x0a, 0x0e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x41, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, + 0x61, 0x64, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, - 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x41, 0x6e, 0x73, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, - 0x64, 0x72, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, + 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, + 0x52, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x64, 0x72, 0x52, + 0x65, 0x71, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x61, + 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, 0x41, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x64, 0x72, 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, + 0x0e, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x2e, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, + 0x52, 0x0c, 0x64, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x59, + 0x0a, 0x12, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, + 0x5f, 0x72, 0x65, 0x71, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, + 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x78, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x59, 0x0a, 0x12, 0x72, 0x78, 0x5f, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x61, 0x6e, 0x73, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x2e, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, + 0x73, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, + 0x70, 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, - 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x64, 0x72, 0x52, 0x65, - 0x71, 0x12, 0x49, 0x0a, 0x0c, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x6e, - 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, 0x41, 0x6e, 0x73, 0x48, 0x00, - 0x52, 0x0a, 0x6c, 0x69, 0x6e, 0x6b, 0x41, 0x64, 0x72, 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x0e, - 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x2e, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, - 0x0c, 0x64, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x59, 0x0a, - 0x12, 0x72, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, - 0x72, 0x65, 0x71, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x41, 0x6e, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x52, 0x0a, 0x0f, 0x6e, 0x65, 0x77, + 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4e, + 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0d, + 0x6e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, + 0x0e, 0x64, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x2e, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x48, 0x00, + 0x52, 0x0c, 0x64, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x4f, + 0x0a, 0x0e, 0x64, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x6e, 0x73, + 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x2e, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x0c, 0x64, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, + 0x5c, 0x0a, 0x13, 0x72, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, + 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, + 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x78, 0x54, 0x69, 0x6d, 0x69, 0x6e, + 0x67, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x10, 0x72, 0x78, 0x54, + 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x59, 0x0a, + 0x12, 0x74, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, + 0x72, 0x65, 0x71, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0f, 0x72, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x59, 0x0a, 0x12, 0x72, 0x78, 0x5f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x2e, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, 0x73, - 0x48, 0x00, 0x52, 0x0f, 0x72, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, - 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, + 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x42, 0x0a, 0x09, 0x72, 0x65, 0x6b, 0x65, + 0x79, 0x5f, 0x69, 0x6e, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x41, 0x6e, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x6e, 0x65, 0x77, 0x5f, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, - 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x6e, 0x65, 0x77, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x52, 0x0a, 0x0f, 0x6e, 0x65, 0x77, 0x5f, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x4e, 0x65, - 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x6e, - 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x4f, 0x0a, 0x0e, - 0x64, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, + 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, 0x12, 0x45, 0x0a, 0x0a, + 0x72, 0x65, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6b, + 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x09, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x43, + 0x6f, 0x6e, 0x66, 0x12, 0x5c, 0x0a, 0x13, 0x61, 0x64, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, + 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x44, 0x52, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, + 0x10, 0x61, 0x64, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d, + 0x65, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, + 0x6d, 0x65, 0x41, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x72, + 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x46, 0x6f, 0x72, 0x63, + 0x65, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x6f, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x65, 0x0a, 0x16, + 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, + 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, + 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x13, + 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x12, 0x65, 0x0a, 0x16, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x18, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, + 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, + 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, 0x73, 0x12, 0x59, 0x0a, 0x12, 0x70, 0x69, + 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x72, 0x65, 0x71, + 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x65, 0x71, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, + 0x6f, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x1a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, - 0x2e, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, - 0x0c, 0x64, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x4f, 0x0a, - 0x0e, 0x64, 0x6c, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x6e, 0x73, 0x18, - 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x2e, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, 0x00, - 0x52, 0x0c, 0x64, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x5c, - 0x0a, 0x13, 0x72, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x65, 0x74, 0x75, - 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x78, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, - 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x10, 0x72, 0x78, 0x54, 0x69, - 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x59, 0x0a, 0x12, - 0x74, 0x78, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x72, - 0x65, 0x71, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x12, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x15, 0x70, 0x69, 0x6e, + 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, + 0x6e, 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, - 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x54, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, - 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0f, 0x74, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, - 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x42, 0x0a, 0x09, 0x72, 0x65, 0x6b, 0x65, 0x79, - 0x5f, 0x69, 0x6e, 0x64, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, 0x48, - 0x00, 0x52, 0x08, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, 0x12, 0x45, 0x0a, 0x0a, 0x72, - 0x65, 0x6b, 0x65, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6b, 0x65, - 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x09, 0x72, 0x65, 0x6b, 0x65, 0x79, 0x43, 0x6f, - 0x6e, 0x66, 0x12, 0x5c, 0x0a, 0x13, 0x61, 0x64, 0x72, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, - 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x2b, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x41, 0x44, 0x52, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x10, - 0x61, 0x64, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, - 0x12, 0x52, 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x61, 0x6e, 0x73, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d, - 0x65, 0x41, 0x6e, 0x73, 0x12, 0x55, 0x0a, 0x10, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, - 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x12, 0x70, 0x69, 0x6e, 0x67, 0x53, + 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x58, 0x0a, + 0x11, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x61, + 0x6e, 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x69, 0x6e, + 0x67, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, + 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x65, + 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x12, 0x52, 0x0a, 0x0f, 0x62, + 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x1e, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x48, 0x00, + 0x52, 0x0d, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x12, + 0x52, 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, + 0x6e, 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, + 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x49, + 0x6e, 0x64, 0x48, 0x00, 0x52, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, + 0x49, 0x6e, 0x64, 0x12, 0x55, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x6f, + 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, + 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x4f, 0x0a, 0x0e, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x21, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0c, 0x72, + 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x12, 0x4f, 0x0a, 0x0e, 0x72, + 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x22, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, + 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0c, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, 0x73, 0x12, 0x6c, 0x0a, 0x19, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x30, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, + 0x71, 0x48, 0x00, 0x52, 0x15, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x12, 0x6c, 0x0a, 0x19, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, + 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, + 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x15, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, 0x73, 0x12, 0x75, 0x0a, 0x1c, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, + 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x27, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x46, 0x6f, 0x72, 0x63, 0x65, - 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0e, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x65, 0x0a, 0x16, 0x72, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, - 0x70, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x18, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, + 0x75, 0x0a, 0x1c, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, + 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x6e, 0x73, 0x18, + 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x6c, + 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x18, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6e, 0x73, 0x12, 0x6f, 0x0a, 0x1a, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, + 0x63, 0x74, 0x72, 0x6c, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x5f, 0x72, 0x65, 0x71, 0x18, 0x29, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, 0x6c, + 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, + 0x16, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, 0x6f, 0x0a, 0x1a, 0x72, 0x65, 0x6c, 0x61, 0x79, + 0x5f, 0x63, 0x74, 0x72, 0x6c, 0x5f, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x2a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, - 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x13, 0x72, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, - 0x65, 0x71, 0x12, 0x65, 0x0a, 0x16, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x5f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x18, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, - 0x6e, 0x73, 0x48, 0x00, 0x52, 0x13, 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, 0x73, 0x12, 0x59, 0x0a, 0x12, 0x70, 0x69, 0x6e, - 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x72, 0x65, 0x71, 0x18, - 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, + 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6e, 0x73, 0x48, 0x00, + 0x52, 0x16, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, + 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6e, 0x73, 0x12, 0x78, 0x0a, 0x1d, 0x72, 0x65, 0x6c, 0x61, + 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x77, 0x64, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x2b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x34, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x19, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, + 0x65, 0x71, 0x12, 0x78, 0x0a, 0x1d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x5f, 0x66, 0x77, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, + 0x61, 0x6e, 0x73, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x73, 0x48, + 0x00, 0x52, 0x19, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, 0x6e, 0x73, 0x12, 0x7c, 0x0a, 0x1f, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x6e, 0x65, 0x77, + 0x5f, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x71, 0x18, + 0x2d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, - 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, - 0x71, 0x48, 0x00, 0x52, 0x0f, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, - 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x1a, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, - 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x65, 0x71, 0x48, 0x00, 0x52, 0x12, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x15, 0x70, 0x69, 0x6e, 0x67, - 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x6e, - 0x73, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x12, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x6c, - 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x58, 0x0a, 0x11, - 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x5f, 0x61, 0x6e, - 0x73, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, - 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, - 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x54, 0x69, 0x6d, - 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x73, 0x12, 0x52, 0x0a, 0x0f, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, - 0x5f, 0x66, 0x72, 0x65, 0x71, 0x5f, 0x72, 0x65, 0x71, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x65, 0x61, - 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x12, 0x52, 0x0a, 0x0f, 0x62, 0x65, - 0x61, 0x63, 0x6f, 0x6e, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x5f, 0x61, 0x6e, 0x73, 0x18, 0x1e, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, - 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x48, 0x00, 0x52, - 0x0d, 0x62, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x12, 0x52, - 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, - 0x64, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4e, 0x65, 0x77, + 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x48, 0x00, 0x52, 0x1a, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4e, 0x65, 0x77, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x52, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x49, 0x6e, 0x64, 0x12, 0x46, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, + 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x10, 0x01, 0x18, 0x01, + 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x53, + 0x0a, 0x09, 0x52, 0x65, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x46, 0x0a, 0x0d, 0x6d, + 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, + 0x04, 0x10, 0x01, 0x18, 0x01, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x1a, 0x5f, 0x0a, 0x0c, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x41, 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xfe, 0x01, 0x52, 0x06, 0x6d, + 0x61, 0x72, 0x67, 0x69, 0x6e, 0x12, 0x2d, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x1a, 0x9e, 0x02, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, + 0x52, 0x65, 0x71, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, + 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0c, 0x74, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, + 0x64, 0x65, 0x78, 0x12, 0x2b, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, + 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, 0x08, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, + 0x02, 0x10, 0x10, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x61, 0x73, 0x6b, + 0x12, 0x39, 0x0a, 0x14, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, 0x61, 0x73, 0x6b, + 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, + 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x07, 0x52, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x4d, 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x22, 0x0a, 0x08, 0x6e, + 0x62, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, + 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x07, 0x6e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4a, + 0x04, 0x08, 0x04, 0x10, 0x05, 0x1a, 0x92, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, + 0x52, 0x41, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, + 0x6d, 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x61, 0x73, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x2d, + 0x0a, 0x13, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x2b, 0x0a, + 0x12, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, + 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x74, 0x78, 0x50, 0x6f, 0x77, + 0x65, 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x1a, 0x63, 0x0a, 0x0c, 0x44, 0x75, + 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x53, 0x0a, 0x0e, 0x6d, 0x61, + 0x78, 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, + 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x1a, + 0xf4, 0x01, 0x0a, 0x0f, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, + 0x52, 0x65, 0x71, 0x12, 0x56, 0x0a, 0x13, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, + 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x59, 0x0a, 0x14, 0x72, + 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, + 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x11, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, + 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x0d, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, + 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x1a, 0xab, 0x01, 0x0a, 0x0f, 0x52, 0x78, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x17, 0x72, 0x78, + 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x72, 0x78, 0x32, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, + 0x12, 0x36, 0x0a, 0x18, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x14, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x78, 0x32, 0x5f, + 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x41, 0x63, 0x6b, 0x1a, 0x5e, 0x0a, 0x0c, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x41, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x07, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, + 0x07, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, 0x2a, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, + 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x12, 0xfa, 0x42, 0x0f, 0x1a, 0x0d, 0x18, + 0x1f, 0x28, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x52, 0x06, 0x6d, 0x61, + 0x72, 0x67, 0x69, 0x6e, 0x1a, 0x99, 0x02, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x2d, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, + 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, + 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, + 0x6d, 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x1a, 0x58, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, + 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, + 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, + 0x61, 0x74, 0x65, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x41, 0x63, 0x6b, 0x1a, 0x66, 0x0a, 0x0c, 0x44, 0x4c, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x2d, 0x0a, 0x0d, 0x63, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x09, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, + 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x1a, 0x5f, 0x0a, 0x0c, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, + 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x23, + 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x41, 0x63, 0x6b, 0x1a, 0x4b, 0x0a, 0x10, 0x52, 0x78, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, + 0x65, 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x37, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, + 0x1a, 0xb9, 0x01, 0x0a, 0x0f, 0x54, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x12, 0x4a, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, + 0x10, 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x12, 0x2a, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x6c, + 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, + 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, + 0x69, 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x50, 0x0a, 0x08, + 0x52, 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, 0x12, 0x44, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, + 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x51, + 0x0a, 0x09, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x44, 0x0a, 0x0d, 0x6d, + 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, + 0x02, 0x10, 0x01, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x1a, 0xda, 0x01, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, + 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, + 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x62, 0x0a, 0x16, 0x61, 0x64, + 0x72, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, + 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, + 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0x49, + 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x41, 0x6e, 0x73, 0x12, + 0x38, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 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, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0xb2, 0x02, 0x0a, 0x0e, 0x46, 0x6f, + 0x72, 0x63, 0x65, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x4c, 0x0a, 0x0b, + 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, + 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, + 0x72, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x28, 0x0a, 0x0b, 0x6d, + 0x61, 0x78, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x07, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x52, 0x65, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x0f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, + 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, + 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0xcc, + 0x01, 0x0a, 0x13, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, + 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x5b, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, + 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, + 0x01, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, + 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6d, 0x61, + 0x78, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0x48, 0x0a, + 0x13, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, + 0x70, 0x41, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x12, 0x6d, 0x61, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x1a, 0x53, 0x0a, 0x0f, 0x50, 0x69, 0x6e, 0x67, 0x53, + 0x6c, 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x40, 0x0a, 0x06, 0x70, 0x65, + 0x72, 0x69, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, + 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x1a, 0x90, 0x01, 0x0a, + 0x12, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x52, 0x65, 0x71, 0x12, 0x29, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, + 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x4f, + 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, + 0x68, 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x2d, 0x0a, 0x13, 0x64, 0x61, + 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x61, 0x63, + 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x1a, 0x61, 0x0a, 0x0f, 0x42, 0x65, 0x61, + 0x63, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x05, + 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06, + 0x2a, 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2d, 0x0a, + 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x3a, 0x0a, 0x0d, + 0x42, 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x12, 0x29, 0x0a, + 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x1a, 0x34, 0x0a, 0x0d, 0x42, 0x65, 0x61, 0x63, + 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x1a, 0x46, + 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x64, 0x12, + 0x35, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, + 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x1a, 0x47, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x1a, + 0xde, 0x02, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, + 0x12, 0x5b, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, - 0x64, 0x48, 0x00, 0x52, 0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x49, - 0x6e, 0x64, 0x12, 0x55, 0x0a, 0x10, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x6f, 0x64, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, - 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, - 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x1a, 0x52, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x65, 0x74, 0x49, 0x6e, 0x64, 0x12, 0x46, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x69, - 0x6e, 0x6f, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, 0x10, 0x01, 0x18, 0x01, 0x52, - 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x53, 0x0a, - 0x09, 0x52, 0x65, 0x73, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x46, 0x0a, 0x0d, 0x6d, 0x69, - 0x6e, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x82, 0x01, 0x04, - 0x10, 0x01, 0x18, 0x01, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x1a, 0x5f, 0x0a, 0x0c, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x41, - 0x6e, 0x73, 0x12, 0x20, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xfe, 0x01, 0x52, 0x06, 0x6d, 0x61, - 0x72, 0x67, 0x69, 0x6e, 0x12, 0x2d, 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x1a, 0x9e, 0x02, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, 0x52, - 0x65, 0x71, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x12, 0x2d, 0x0a, 0x0e, 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, - 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x0c, 0x74, 0x78, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x2b, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, 0x61, - 0x73, 0x6b, 0x18, 0x03, 0x20, 0x03, 0x28, 0x08, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x92, 0x01, 0x02, - 0x10, 0x10, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x61, 0x73, 0x6b, 0x12, - 0x39, 0x0a, 0x14, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x5f, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x2a, 0x02, 0x18, 0x07, 0x52, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, - 0x61, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x12, 0x22, 0x0a, 0x08, 0x6e, 0x62, - 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x07, 0x6e, 0x62, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x4a, 0x04, - 0x08, 0x04, 0x10, 0x05, 0x1a, 0x92, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x44, 0x52, - 0x41, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x6d, - 0x61, 0x73, 0x6b, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4d, 0x61, 0x73, 0x6b, 0x41, 0x63, 0x6b, 0x12, 0x2d, 0x0a, - 0x13, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x61, 0x74, 0x61, - 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x2b, 0x0a, 0x12, - 0x74, 0x78, 0x5f, 0x70, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x61, - 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x74, 0x78, 0x50, 0x6f, 0x77, 0x65, - 0x72, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x1a, 0x63, 0x0a, 0x0c, 0x44, 0x75, 0x74, - 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x12, 0x53, 0x0a, 0x0e, 0x6d, 0x61, 0x78, - 0x5f, 0x64, 0x75, 0x74, 0x79, 0x5f, 0x63, 0x79, 0x63, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x61, 0x6e, 0x64, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, + 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xf0, 0x01, + 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x49, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x0d, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x3c, 0x0a, 0x15, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, + 0x18, 0xff, 0x01, 0x52, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x0f, 0x63, 0x61, 0x64, 0x5f, + 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, - 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x1a, 0xf4, - 0x01, 0x0a, 0x0f, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x52, - 0x65, 0x71, 0x12, 0x56, 0x0a, 0x13, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, - 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x72, 0x78, 0x32, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x59, 0x0a, 0x14, 0x72, 0x78, - 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, - 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, - 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x11, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, - 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x0d, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, - 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x0c, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x79, 0x1a, 0xab, 0x01, 0x0a, 0x0f, 0x52, 0x78, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, 0x41, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x17, 0x72, 0x78, 0x32, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x72, 0x78, 0x32, 0x44, + 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x41, 0x44, 0x50, 0x65, 0x72, 0x69, 0x6f, + 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0x52, 0x0e, 0x63, 0x61, 0x64, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, + 0x1a, 0x80, 0x03, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, + 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, + 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, + 0x63, 0x6b, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, + 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, + 0x74, 0x41, 0x63, 0x6b, 0x12, 0x49, 0x0a, 0x22, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x1d, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, - 0x36, 0x0a, 0x18, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, - 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x14, 0x72, 0x78, 0x31, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x78, 0x32, 0x5f, 0x66, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0f, 0x72, 0x78, 0x32, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, - 0x41, 0x63, 0x6b, 0x1a, 0x5e, 0x0a, 0x0c, 0x44, 0x65, 0x76, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x41, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x07, 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x07, - 0x62, 0x61, 0x74, 0x74, 0x65, 0x72, 0x79, 0x12, 0x2a, 0x0a, 0x06, 0x6d, 0x61, 0x72, 0x67, 0x69, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x12, 0xfa, 0x42, 0x0f, 0x1a, 0x0d, 0x18, 0x1f, - 0x28, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x52, 0x06, 0x6d, 0x61, 0x72, - 0x67, 0x69, 0x6e, 0x1a, 0x99, 0x02, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x2d, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, - 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, - 0x56, 0x0a, 0x13, 0x6d, 0x69, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, - 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, - 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, - 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x56, 0x0a, 0x13, 0x6d, 0x61, 0x78, 0x5f, 0x64, - 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, - 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x10, 0x6d, - 0x61, 0x78, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, - 0x58, 0x0a, 0x0d, 0x4e, 0x65, 0x77, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, 0x73, - 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, - 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, - 0x63, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, - 0x74, 0x65, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x64, 0x61, - 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x41, 0x63, 0x6b, 0x1a, 0x66, 0x0a, 0x0c, 0x44, 0x4c, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x2d, 0x0a, 0x0d, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x27, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, - 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x1a, 0x5f, 0x0a, 0x0c, 0x44, 0x4c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x41, 0x6e, - 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, - 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x63, 0x68, - 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x23, 0x0a, - 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, - 0x63, 0x6b, 0x1a, 0x4b, 0x0a, 0x10, 0x52, 0x78, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x53, 0x65, - 0x74, 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x37, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x1a, - 0xb9, 0x01, 0x0a, 0x0f, 0x54, 0x78, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, - 0x52, 0x65, 0x71, 0x12, 0x4a, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x65, 0x69, 0x72, 0x70, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, - 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x45, 0x69, 0x72, 0x70, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, - 0x2a, 0x0a, 0x11, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x75, 0x70, 0x6c, 0x69, - 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x64, - 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x64, 0x77, 0x65, 0x6c, 0x6c, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, - 0x6e, 0x6b, 0x44, 0x77, 0x65, 0x6c, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x50, 0x0a, 0x08, 0x52, - 0x65, 0x6b, 0x65, 0x79, 0x49, 0x6e, 0x64, 0x12, 0x44, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x6f, 0x72, - 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, + 0x37, 0x0a, 0x18, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x15, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x39, 0x0a, 0x19, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x41, 0x63, 0x6b, 0x12, 0x2e, 0x0a, 0x13, 0x63, 0x61, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, + 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x11, 0x63, 0x61, 0x64, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, + 0x41, 0x63, 0x6b, 0x1a, 0xce, 0x04, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x12, 0x64, 0x0a, + 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x71, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x1a, 0xce, 0x03, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x42, 0x0a, 0x06, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, + 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x48, + 0x00, 0x52, 0x06, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x64, 0x79, 0x6e, + 0x61, 0x6d, 0x69, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, + 0x63, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, 0x07, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, + 0x12, 0x62, 0x0a, 0x15, 0x65, 0x6e, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2c, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x48, 0x00, 0x52, + 0x13, 0x65, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, + 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x07, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x3f, 0x52, 0x07, + 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x49, 0x0a, 0x0e, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, + 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x52, 0x0d, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x12, 0x53, 0x0a, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xfa, + 0x42, 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, 0x52, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x42, 0x0b, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, + 0x03, 0xf8, 0x42, 0x01, 0x1a, 0xa2, 0x02, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x6e, + 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x41, 0x6e, 0x73, 0x12, 0x3f, + 0x0a, 0x1c, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x19, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x12, + 0x49, 0x0a, 0x22, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x73, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, + 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x37, 0x0a, 0x18, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x73, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x41, 0x63, 0x6b, 0x12, 0x1f, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x5f, 0x61, + 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, + 0x66, 0x41, 0x63, 0x6b, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x1d, 0x73, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x63, 0x6b, 0x1a, 0x9b, 0x08, 0x0a, 0x18, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0a, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, + 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, + 0x02, 0x18, 0x0f, 0x52, 0x09, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x4f, + 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x6c, + 0x69, 0x6e, 0x6b, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, + 0x52, 0x0d, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, + 0xed, 0x02, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x42, 0xd1, 0x02, 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, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, 0x63, 0x6d, + 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x34, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, 0x63, 0x6d, + 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, + 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, 0x72, 0x12, + 0x16, 0x0a, 0x07, 0x77, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x05, 0x77, 0x46, 0x43, 0x6e, 0x74, 0x12, 0x91, 0x03, 0x0a, 0x0e, 0x72, 0x6f, 0x6f, 0x74, + 0x5f, 0x77, 0x6f, 0x72, 0x5f, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, + 0x42, 0xeb, 0x02, 0x92, 0x41, 0x31, 0x4a, 0x22, 0x22, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, + 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x10, 0x70, 0x01, + 0xea, 0xaa, 0x19, 0x83, 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, 0x40, 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, 0x31, 0x36, 0x42, 0x79, 0x74, 0x65, 0x73, 0xf2, 0xaa, 0x19, 0xa1, 0x01, 0x1a, 0x4f, 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, + 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, + 0x4e, 0x65, 0x77, 0x31, 0x36, 0x42, 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, + 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, 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, + 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, + 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0b, + 0x72, 0x6f, 0x6f, 0x74, 0x57, 0x6f, 0x72, 0x53, 0x4b, 0x65, 0x79, 0x12, 0x44, 0x0a, 0x09, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, + 0xfa, 0x42, 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, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, + 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, + 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x1a, 0x1a, 0x0a, 0x18, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x6e, 0x73, 0x1a, 0x83, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, + 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x12, 0x26, + 0x0a, 0x0a, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0d, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x0f, 0x52, 0x09, 0x72, 0x75, 0x6c, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x41, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, + 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x56, 0x0a, 0x16, 0x52, 0x65, 0x6c, + 0x61, 0x79, 0x43, 0x74, 0x72, 0x6c, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, + 0x78, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x75, 0x6c, + 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x07, 0x77, 0x5f, 0x66, + 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x77, 0x46, 0x43, 0x6e, + 0x74, 0x1a, 0xb1, 0x03, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x12, + 0x56, 0x0a, 0x13, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, + 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x52, 0x11, 0x72, 0x65, 0x73, 0x65, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x52, 0x0a, 0x13, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, + 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x11, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x47, 0x0a, 0x0d, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x73, 0x12, 0x54, 0x0a, 0x14, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x75, + 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x12, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x55, 0x70, + 0x6c, 0x69, 0x6e, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x49, 0x0a, 0x0e, 0x6f, 0x76, + 0x65, 0x72, 0x61, 0x6c, 0x6c, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 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, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x0d, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x6c, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x73, 0x1a, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x46, 0x77, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x41, + 0x6e, 0x73, 0x1a, 0xe3, 0x03, 0x0a, 0x1a, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x4e, 0x65, 0x77, 0x45, 0x6e, 0x64, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x12, 0xed, 0x02, 0x0a, 0x08, 0x64, 0x65, 0x76, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x42, 0xd1, 0x02, 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, 0xf2, 0xaa, 0x19, 0xa0, 0x01, 0x1a, 0x4e, 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, + 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x4e, 0x65, 0x77, 0x34, 0x42, + 0x79, 0x74, 0x65, 0x73, 0x46, 0x6c, 0x61, 0x67, 0x22, 0x4e, 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, + 0x63, 0x6d, 0x64, 0x2f, 0x74, 0x74, 0x6e, 0x2d, 0x6c, 0x77, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, + 0x61, 0x63, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x76, 0x41, 0x64, 0x64, + 0x72, 0x12, 0x24, 0x0a, 0x03, 0x73, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x12, + 0xfa, 0x42, 0x0f, 0x1a, 0x0d, 0x18, 0x0b, 0x28, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x73, 0x73, 0x69, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x1a, 0x16, 0x18, 0xf1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x28, 0xf2, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x52, 0x04, 0x72, 0x73, 0x73, 0x69, 0x42, 0x09, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x4a, 0x04, 0x08, 0x25, 0x10, 0x26, 0x4a, 0x04, 0x08, 0x26, 0x10, 0x27, 0x52, + 0x15, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6c, 0x69, + 0x73, 0x74, 0x5f, 0x72, 0x65, 0x71, 0x52, 0x15, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x66, 0x69, + 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x61, 0x6e, 0x73, 0x22, 0x45, 0x0a, + 0x0b, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x36, 0x0a, 0x08, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x51, 0x0a, - 0x09, 0x52, 0x65, 0x6b, 0x65, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x44, 0x0a, 0x0d, 0x6d, 0x69, - 0x6e, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x1a, 0xda, 0x01, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x62, 0x0a, 0x16, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x63, 0x6b, - 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, - 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, - 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x62, 0x0a, 0x16, 0x61, 0x64, 0x72, - 0x5f, 0x61, 0x63, 0x6b, 0x5f, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, - 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, - 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x13, 0x61, 0x64, 0x72, 0x41, 0x63, 0x6b, - 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0x49, 0x0a, - 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x41, 0x6e, 0x73, 0x12, 0x38, - 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x07, 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, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x1a, 0xb2, 0x02, 0x0a, 0x0e, 0x46, 0x6f, 0x72, - 0x63, 0x65, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x12, 0x4c, 0x0a, 0x0b, 0x72, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x21, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, - 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, - 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x72, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x4f, 0x0a, 0x0f, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0d, 0x64, 0x61, 0x74, - 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x28, 0x0a, 0x0b, 0x6d, 0x61, - 0x78, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x42, - 0x07, 0xfa, 0x42, 0x04, 0x2a, 0x02, 0x18, 0x07, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x52, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x12, 0x57, 0x0a, 0x0f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x5f, 0x65, - 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0e, 0x70, - 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0xcc, 0x01, - 0x0a, 0x13, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, - 0x75, 0x70, 0x52, 0x65, 0x71, 0x12, 0x5b, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x5f, 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, - 0x76, 0x33, 0x2e, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, - 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, - 0x52, 0x10, 0x6d, 0x61, 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x12, 0x58, 0x0a, 0x11, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x65, - 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, - 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0f, 0x6d, 0x61, 0x78, - 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x1a, 0x48, 0x0a, 0x13, - 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x53, 0x65, 0x74, 0x75, 0x70, - 0x41, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, - 0x65, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x12, 0x6d, 0x61, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x1a, 0x53, 0x0a, 0x0f, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, - 0x6f, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x12, 0x40, 0x0a, 0x06, 0x70, 0x65, 0x72, - 0x69, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x53, - 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, - 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x1a, 0x90, 0x01, 0x0a, 0x12, - 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, - 0x65, 0x71, 0x12, 0x29, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, - 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x4f, 0x0a, - 0x0f, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x73, 0x22, 0x43, 0x0a, 0x0e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, + 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x4d, 0x0a, 0x16, 0x5a, 0x65, 0x72, + 0x6f, 0x61, 0x62, 0x6c, 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, + 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x67, 0x0a, 0x13, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, + 0x01, 0x22, 0x65, 0x0a, 0x12, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, - 0x0d, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x68, - 0x0a, 0x12, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x41, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x12, 0x2d, 0x0a, 0x13, 0x64, 0x61, 0x74, - 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x61, 0x63, 0x6b, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x41, 0x63, 0x6b, 0x1a, 0x61, 0x0a, 0x0f, 0x42, 0x65, 0x61, 0x63, - 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x05, 0x64, - 0x65, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x2a, - 0x04, 0x18, 0xff, 0xff, 0x03, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x2d, 0x0a, 0x0d, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x1a, 0x3a, 0x0a, 0x0d, 0x42, - 0x65, 0x61, 0x63, 0x6f, 0x6e, 0x46, 0x72, 0x65, 0x71, 0x52, 0x65, 0x71, 0x12, 0x29, 0x0a, 0x09, - 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, - 0x0b, 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x1a, 0x34, 0x0a, 0x0d, 0x42, 0x65, 0x61, 0x63, 0x6f, - 0x6e, 0x46, 0x72, 0x65, 0x71, 0x41, 0x6e, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x65, 0x71, - 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x63, 0x6b, 0x1a, 0x46, 0x0a, - 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x64, 0x12, 0x35, - 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, - 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, - 0x6c, 0x61, 0x73, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, - 0x63, 0x6c, 0x61, 0x73, 0x73, 0x1a, 0x47, 0x0a, 0x0e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4d, - 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x12, 0x35, 0x0a, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x09, - 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x45, 0x0a, 0x0b, 0x4d, 0x41, 0x43, - 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x36, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, - 0x61, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4d, 0x41, 0x43, 0x43, - 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, - 0x22, 0x43, 0x0a, 0x0e, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, - 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x4d, 0x0a, 0x16, 0x5a, 0x65, 0x72, 0x6f, 0x61, 0x62, 0x6c, - 0x65, 0x46, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x0b, - 0xfa, 0x42, 0x08, 0x32, 0x06, 0x18, 0x00, 0x28, 0xa0, 0x8d, 0x06, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, - 0x10, 0x01, 0x18, 0x01, 0x22, 0x67, 0x0a, 0x13, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, - 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, - 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x65, 0x0a, - 0x12, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x3d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, - 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, - 0x10, 0x01, 0x18, 0x01, 0x22, 0x67, 0x0a, 0x13, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, - 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3e, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x69, 0x6e, 0x67, - 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, - 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, - 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x71, 0x0a, - 0x18, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, - 0x79, 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, - 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x42, 0x08, 0xfa, - 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, - 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, - 0x22, 0x59, 0x0a, 0x0c, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, - 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, - 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x71, 0x0a, 0x18, 0x41, - 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, - 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, - 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, - 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, - 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, - 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x71, - 0x0a, 0x18, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, - 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, 0x2e, - 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, 0x63, - 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, + 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x67, 0x0a, 0x13, 0x50, 0x69, 0x6e, 0x67, + 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, + 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, + 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, - 0x01, 0x22, 0x5f, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, 0x49, 0x52, 0x50, 0x42, + 0x01, 0x22, 0x71, 0x0a, 0x18, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, + 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, + 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, + 0x10, 0x01, 0x18, 0x01, 0x22, 0x59, 0x0a, 0x0c, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, + 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, + 0x71, 0x0a, 0x18, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x74, 0x74, 0x6e, + 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, 0x44, 0x52, 0x41, + 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, 0x01, 0x10, 0x01, - 0x18, 0x01, 0x2a, 0xa7, 0x01, 0x0a, 0x05, 0x4d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, - 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0f, - 0x0a, 0x0b, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, - 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x55, - 0x50, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, - 0x45, 0x44, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x4f, 0x4e, - 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x55, 0x50, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x43, - 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x05, 0x12, - 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, - 0x54, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x50, 0x52, 0x49, 0x45, 0x54, 0x41, - 0x52, 0x59, 0x10, 0x07, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x28, 0x0a, 0x05, - 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, - 0x5f, 0x52, 0x31, 0x10, 0x00, 0x1a, 0x0f, 0xea, 0xaa, 0x19, 0x0b, 0x18, 0x01, 0x2a, 0x07, 0x4c, - 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x2a, 0xb9, 0x02, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x56, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0b, 0x4d, 0x41, 0x43, 0x5f, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x12, 0x07, 0x75, 0x6e, - 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x1e, 0x0a, 0x08, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, - 0x30, 0x10, 0x01, 0x1a, 0x10, 0xea, 0xaa, 0x19, 0x0c, 0x12, 0x03, 0x31, 0x2e, 0x30, 0x12, 0x05, - 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x12, 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, - 0x30, 0x5f, 0x31, 0x10, 0x02, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, - 0x2e, 0x31, 0x12, 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, - 0x10, 0x03, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x12, - 0x1e, 0x0a, 0x08, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x10, 0x04, 0x1a, 0x10, 0xea, - 0xaa, 0x19, 0x0c, 0x12, 0x03, 0x31, 0x2e, 0x31, 0x12, 0x05, 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x12, - 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x05, 0x1a, - 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x33, 0x12, 0x1b, 0x0a, 0x0a, - 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x34, 0x10, 0x06, 0x1a, 0x0b, 0xea, 0xaa, - 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x34, 0x1a, 0x57, 0xea, 0xaa, 0x19, 0x07, 0x18, - 0x01, 0x2a, 0x03, 0x4d, 0x41, 0x43, 0xf2, 0xaa, 0x19, 0x48, 0x0a, 0x46, 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, 0x2e, 0x4d, 0x41, 0x43, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x2a, 0xcb, 0x05, 0x0a, 0x0a, 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x1e, 0x0a, 0x0b, 0x50, 0x48, 0x59, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x00, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x12, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, - 0x6e, 0x12, 0x24, 0x0a, 0x08, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x1a, - 0x16, 0xea, 0xaa, 0x19, 0x12, 0x12, 0x03, 0x31, 0x2e, 0x30, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, - 0x30, 0x12, 0x04, 0x56, 0x31, 0x5f, 0x30, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x53, 0x30, 0x30, 0x31, - 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x0a, 0x50, 0x48, 0x59, 0x5f, 0x56, - 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x02, 0x1a, 0x13, 0xea, 0xaa, 0x19, 0x0f, 0x12, 0x05, 0x31, - 0x2e, 0x30, 0x2e, 0x31, 0x12, 0x06, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x12, 0x10, 0x0a, 0x0c, - 0x54, 0x53, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x02, 0x12, 0x40, - 0x0a, 0x10, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, - 0x5f, 0x41, 0x10, 0x03, 0x1a, 0x2a, 0xea, 0xaa, 0x19, 0x26, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, - 0x32, 0x12, 0x07, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x2d, 0x61, 0x12, 0x06, 0x56, 0x31, 0x5f, 0x30, - 0x5f, 0x32, 0x12, 0x0c, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, - 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, - 0x10, 0x03, 0x12, 0x31, 0x0a, 0x10, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, - 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x10, 0x04, 0x1a, 0x1b, 0xea, 0xaa, 0x19, 0x17, 0x12, 0x07, - 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x2d, 0x62, 0x12, 0x0c, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, - 0x52, 0x45, 0x56, 0x5f, 0x42, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, - 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x10, 0x04, 0x12, 0x34, 0x0a, - 0x0e, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, - 0x05, 0x1a, 0x20, 0xea, 0xaa, 0x19, 0x1c, 0x12, 0x05, 0x31, 0x2e, 0x31, 0x2d, 0x61, 0x12, 0x07, - 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x2d, 0x61, 0x12, 0x0a, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, - 0x56, 0x5f, 0x41, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, - 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x05, 0x12, 0x34, 0x0a, 0x0e, 0x50, 0x48, 0x59, - 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x10, 0x06, 0x1a, 0x20, 0xea, - 0xaa, 0x19, 0x1c, 0x12, 0x05, 0x31, 0x2e, 0x31, 0x2d, 0x62, 0x12, 0x07, 0x31, 0x2e, 0x31, 0x2e, - 0x30, 0x2d, 0x62, 0x12, 0x0a, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x12, - 0x14, 0x0a, 0x10, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, - 0x56, 0x5f, 0x42, 0x10, 0x06, 0x12, 0x31, 0x0a, 0x10, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, - 0x30, 0x5f, 0x33, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x07, 0x1a, 0x1b, 0xea, 0xaa, 0x19, - 0x17, 0x12, 0x07, 0x31, 0x2e, 0x30, 0x2e, 0x33, 0x2d, 0x61, 0x12, 0x0c, 0x56, 0x31, 0x5f, 0x30, - 0x5f, 0x33, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x50, 0x30, 0x30, - 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x07, - 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, - 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, - 0x5f, 0x31, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, - 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, - 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, - 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x34, 0x10, 0x0c, 0x1a, 0x54, 0xea, 0xaa, 0x19, 0x02, - 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x48, 0x0a, 0x46, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, + 0x18, 0x01, 0x22, 0x71, 0x0a, 0x18, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, + 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x41, + 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, 0x08, + 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0x5f, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, + 0x49, 0x52, 0x50, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, + 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x45, + 0x49, 0x52, 0x50, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x10, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x06, + 0x08, 0x01, 0x10, 0x01, 0x18, 0x01, 0x22, 0xcf, 0x02, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x61, 0x79, + 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, + 0x12, 0x3f, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, + 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, + 0x65, 0x12, 0x24, 0x0a, 0x03, 0x73, 0x6e, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x12, + 0xfa, 0x42, 0x0f, 0x1a, 0x0d, 0x18, 0x0b, 0x28, 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x2f, 0x0a, 0x04, 0x72, 0x73, 0x73, 0x69, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x1a, 0x16, 0x18, 0xf1, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x28, 0xf2, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x01, 0x52, 0x04, 0x72, 0x73, 0x73, 0x69, 0x12, 0x4a, 0x0a, 0x0b, 0x77, 0x6f, 0x72, 0x5f, + 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1f, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x52, + 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x27, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, + 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x32, 0x04, 0x28, 0xa0, + 0x8d, 0x06, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x0a, + 0x0b, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x77, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x44, 0x0a, 0x17, 0x52, 0x65, 0x6c, 0x61, + 0x79, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, + 0x52, 0x65, 0x71, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x61, 0x77, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x72, 0x61, 0x77, 0x50, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x08, 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0x98, + 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x55, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x12, 0x40, 0x0a, 0x03, 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, 0x03, 0x69, 0x64, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x66, + 0x75, 0x6c, 0x6c, 0x5f, 0x66, 0x5f, 0x63, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x66, 0x75, 0x6c, 0x6c, 0x46, 0x43, 0x6e, 0x74, 0x2a, 0xa7, 0x01, 0x0a, 0x05, 0x4d, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x52, 0x45, 0x51, 0x55, + 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x41, 0x43, + 0x43, 0x45, 0x50, 0x54, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x46, + 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x55, 0x50, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x4e, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x03, + 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, 0x55, 0x50, + 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x5f, + 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, + 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, + 0x4f, 0x50, 0x52, 0x49, 0x45, 0x54, 0x41, 0x52, 0x59, 0x10, 0x07, 0x1a, 0x06, 0xea, 0xaa, 0x19, + 0x02, 0x18, 0x01, 0x2a, 0x28, 0x0a, 0x05, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x12, 0x0e, 0x0a, 0x0a, + 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x5f, 0x52, 0x31, 0x10, 0x00, 0x1a, 0x0f, 0xea, 0xaa, + 0x19, 0x0b, 0x18, 0x01, 0x2a, 0x07, 0x4c, 0x4f, 0x52, 0x41, 0x57, 0x41, 0x4e, 0x2a, 0xb9, 0x02, + 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0b, + 0x4d, 0x41, 0x43, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x1a, 0x0d, 0xea, + 0xaa, 0x19, 0x09, 0x12, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x1e, 0x0a, 0x08, + 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x1a, 0x10, 0xea, 0xaa, 0x19, 0x0c, + 0x12, 0x03, 0x31, 0x2e, 0x30, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x12, 0x1b, 0x0a, 0x0a, + 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x02, 0x1a, 0x0b, 0xea, 0xaa, + 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x31, 0x12, 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, + 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x03, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, + 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x12, 0x1e, 0x0a, 0x08, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, + 0x5f, 0x31, 0x10, 0x04, 0x1a, 0x10, 0xea, 0xaa, 0x19, 0x0c, 0x12, 0x03, 0x31, 0x2e, 0x31, 0x12, + 0x05, 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x12, 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, + 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x05, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, + 0x30, 0x2e, 0x33, 0x12, 0x1b, 0x0a, 0x0a, 0x4d, 0x41, 0x43, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, + 0x34, 0x10, 0x06, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x34, + 0x1a, 0x57, 0xea, 0xaa, 0x19, 0x07, 0x18, 0x01, 0x2a, 0x03, 0x4d, 0x41, 0x43, 0xf2, 0xaa, 0x19, + 0x48, 0x0a, 0x46, 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, 0x2e, 0x4d, 0x41, 0x43, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0xcb, 0x05, 0x0a, 0x0a, 0x50, 0x48, + 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0b, 0x50, 0x48, 0x59, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x12, + 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x24, 0x0a, 0x08, 0x50, 0x48, 0x59, 0x5f, + 0x56, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x1a, 0x16, 0xea, 0xaa, 0x19, 0x12, 0x12, 0x03, 0x31, 0x2e, + 0x30, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x12, 0x04, 0x56, 0x31, 0x5f, 0x30, 0x12, 0x0e, + 0x0a, 0x0a, 0x54, 0x53, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x10, 0x01, 0x12, 0x23, + 0x0a, 0x0a, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x02, 0x1a, 0x13, + 0xea, 0xaa, 0x19, 0x0f, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x31, 0x12, 0x06, 0x56, 0x31, 0x5f, + 0x30, 0x5f, 0x31, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x53, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, + 0x30, 0x5f, 0x31, 0x10, 0x02, 0x12, 0x40, 0x0a, 0x10, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, + 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x03, 0x1a, 0x2a, 0xea, 0xaa, 0x19, + 0x26, 0x12, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x12, 0x07, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x2d, + 0x61, 0x12, 0x06, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x12, 0x0c, 0x56, 0x31, 0x5f, 0x30, 0x5f, + 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x31, + 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x03, 0x12, 0x31, 0x0a, 0x10, 0x50, 0x48, 0x59, + 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x10, 0x04, 0x1a, + 0x1b, 0xea, 0xaa, 0x19, 0x17, 0x12, 0x07, 0x31, 0x2e, 0x30, 0x2e, 0x32, 0x2d, 0x62, 0x12, 0x0c, + 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x12, 0x16, 0x0a, 0x12, + 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x5f, 0x52, 0x45, 0x56, + 0x5f, 0x42, 0x10, 0x04, 0x12, 0x34, 0x0a, 0x0e, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x31, + 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x05, 0x1a, 0x20, 0xea, 0xaa, 0x19, 0x1c, 0x12, 0x05, + 0x31, 0x2e, 0x31, 0x2d, 0x61, 0x12, 0x07, 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x2d, 0x61, 0x12, 0x0a, + 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x50, + 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x05, + 0x12, 0x34, 0x0a, 0x0e, 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, + 0x5f, 0x42, 0x10, 0x06, 0x1a, 0x20, 0xea, 0xaa, 0x19, 0x1c, 0x12, 0x05, 0x31, 0x2e, 0x31, 0x2d, + 0x62, 0x12, 0x07, 0x31, 0x2e, 0x31, 0x2e, 0x30, 0x2d, 0x62, 0x12, 0x0a, 0x56, 0x31, 0x5f, 0x31, + 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, + 0x56, 0x31, 0x5f, 0x31, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x42, 0x10, 0x06, 0x12, 0x31, 0x0a, 0x10, + 0x50, 0x48, 0x59, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, + 0x10, 0x07, 0x1a, 0x1b, 0xea, 0xaa, 0x19, 0x17, 0x12, 0x07, 0x31, 0x2e, 0x30, 0x2e, 0x33, 0x2d, + 0x61, 0x12, 0x0c, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x5f, 0x52, 0x45, 0x56, 0x5f, 0x41, 0x12, + 0x16, 0x0a, 0x12, 0x52, 0x50, 0x30, 0x30, 0x31, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x5f, + 0x52, 0x45, 0x56, 0x5f, 0x41, 0x10, 0x07, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, + 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x30, 0x10, 0x08, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, + 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x31, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x52, + 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x32, 0x10, 0x0a, 0x12, 0x10, 0x0a, + 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x33, 0x10, 0x0b, 0x12, + 0x10, 0x0a, 0x0c, 0x52, 0x50, 0x30, 0x30, 0x32, 0x5f, 0x56, 0x31, 0x5f, 0x30, 0x5f, 0x34, 0x10, + 0x0c, 0x1a, 0x54, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0xf2, 0xaa, 0x19, 0x48, 0x0a, 0x46, 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, 0x2e, 0x50, + 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x10, 0x01, 0x2a, 0x87, 0x03, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, + 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, + 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x44, + 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0f, 0x0a, + 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0f, + 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x35, 0x10, 0x05, 0x12, + 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x36, 0x10, 0x06, + 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x37, 0x10, + 0x07, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x38, + 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, + 0x39, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, + 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, + 0x54, 0x45, 0x5f, 0x31, 0x31, 0x10, 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, + 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x32, 0x10, 0x0c, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, + 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x33, 0x10, 0x0d, 0x12, 0x10, 0x0a, 0x0c, 0x44, + 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x34, 0x10, 0x0e, 0x12, 0x10, 0x0a, + 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, + 0x60, 0xea, 0xaa, 0x19, 0x0d, 0x10, 0x01, 0x2a, 0x09, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, + 0x54, 0x45, 0xf2, 0xaa, 0x19, 0x4b, 0x0a, 0x49, 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, 0x2e, 0x50, 0x48, 0x59, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x10, 0x01, - 0x2a, 0x87, 0x03, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, - 0x30, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, - 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, - 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, - 0x54, 0x45, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, - 0x41, 0x54, 0x45, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, 0x5f, - 0x52, 0x41, 0x54, 0x45, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, 0x41, - 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, 0x54, - 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x0f, 0x0a, 0x0b, 0x44, 0x41, - 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x44, - 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x39, 0x10, 0x09, 0x12, 0x10, 0x0a, 0x0c, - 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, 0x10, - 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x31, 0x10, 0x0b, - 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x31, 0x32, - 0x10, 0x0c, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, - 0x31, 0x33, 0x10, 0x0d, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, - 0x45, 0x5f, 0x31, 0x34, 0x10, 0x0e, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, - 0x41, 0x54, 0x45, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, 0x60, 0xea, 0xaa, 0x19, 0x0d, 0x10, 0x01, - 0x2a, 0x09, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0xf2, 0xaa, 0x19, 0x4b, 0x0a, - 0x49, 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, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0xba, 0x02, 0x0a, 0x0e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, - 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, - 0x54, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, - 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x16, 0x0a, - 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, - 0x54, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, - 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x16, 0x0a, - 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, - 0x54, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, - 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x16, 0x0a, - 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, - 0x54, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, - 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x37, 0x10, 0x07, 0x1a, 0x68, 0xea, - 0xaa, 0x19, 0x14, 0x10, 0x01, 0x2a, 0x10, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, - 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0xf2, 0xaa, 0x19, 0x4c, 0x0a, 0x4a, 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, 0x2e, 0x44, 0x61, 0x74, - 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x63, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x5d, 0x0a, 0x0f, 0x4a, 0x6f, 0x69, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, - 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x10, 0x00, 0x12, 0x12, - 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, - 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x4b, 0x45, 0x59, - 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x04, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0xff, 0x01, 0x1a, 0x06, - 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x3f, 0x0a, 0x11, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, - 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x53, 0x53, - 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x02, 0x1a, - 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x38, 0x0a, 0x0a, 0x43, 0x46, 0x4c, 0x69, 0x73, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x52, 0x45, 0x51, 0x55, 0x45, 0x4e, - 0x43, 0x49, 0x45, 0x53, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x53, 0x10, 0x01, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, - 0x01, 0x2a, 0x3d, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, - 0x41, 0x53, 0x53, 0x5f, 0x41, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, - 0x5f, 0x42, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x43, 0x10, - 0x02, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x18, 0x01, 0x2a, 0x05, 0x43, 0x4c, 0x41, 0x53, 0x53, - 0x2a, 0x78, 0x0a, 0x12, 0x54, 0x78, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, - 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x4f, 0x57, 0x45, 0x53, 0x54, - 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x42, - 0x45, 0x4c, 0x4f, 0x57, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x0a, 0x0a, - 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x42, 0x4f, - 0x56, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x48, - 0x49, 0x47, 0x48, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x49, 0x47, 0x48, 0x45, 0x53, 0x54, - 0x10, 0x06, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0xe4, 0x03, 0x0a, 0x14, 0x4d, - 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, - 0x69, 0x65, 0x72, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x30, - 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, - 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x43, 0x48, - 0x45, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x43, 0x49, 0x44, 0x5f, 0x4c, 0x49, 0x4e, - 0x4b, 0x5f, 0x41, 0x44, 0x52, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x44, - 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, - 0x49, 0x44, 0x5f, 0x52, 0x58, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, - 0x50, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x5f, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x4e, - 0x45, 0x57, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, - 0x43, 0x49, 0x44, 0x5f, 0x52, 0x58, 0x5f, 0x54, 0x49, 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x45, - 0x54, 0x55, 0x50, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, 0x44, 0x5f, 0x54, 0x58, 0x5f, - 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x09, 0x12, 0x12, 0x0a, - 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x4c, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, - 0x0a, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4b, 0x45, 0x59, 0x10, 0x0b, - 0x12, 0x17, 0x0a, 0x13, 0x43, 0x49, 0x44, 0x5f, 0x41, 0x44, 0x52, 0x5f, 0x50, 0x41, 0x52, 0x41, - 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x0c, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, - 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x0d, 0x12, 0x14, - 0x0a, 0x10, 0x43, 0x49, 0x44, 0x5f, 0x46, 0x4f, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x4a, 0x4f, - 0x49, 0x4e, 0x10, 0x0e, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4a, 0x4f, - 0x49, 0x4e, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x0f, - 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, 0x44, 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x4c, 0x4f, - 0x54, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x10, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x49, 0x44, 0x5f, - 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x4c, 0x4f, 0x54, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, - 0x4c, 0x10, 0x11, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x49, 0x44, 0x5f, 0x42, 0x45, 0x41, 0x43, 0x4f, - 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x49, 0x4e, 0x47, 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, - 0x44, 0x5f, 0x42, 0x45, 0x41, 0x43, 0x4f, 0x4e, 0x5f, 0x46, 0x52, 0x45, 0x51, 0x10, 0x13, 0x12, - 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x4f, - 0x44, 0x45, 0x10, 0x20, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x18, 0x01, 0x2a, 0x03, 0x43, 0x49, - 0x44, 0x2a, 0xe6, 0x02, 0x0a, 0x13, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, - 0x44, 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x55, 0x54, - 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, - 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x10, 0x0a, - 0x0c, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x34, 0x10, 0x02, 0x12, - 0x10, 0x0a, 0x0c, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x38, 0x10, - 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, - 0x31, 0x36, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, - 0x4c, 0x45, 0x5f, 0x33, 0x32, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, - 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x36, 0x34, 0x10, 0x06, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x55, - 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x12, - 0x0a, 0x0e, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x35, 0x36, - 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, - 0x5f, 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, - 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x44, - 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, - 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x34, - 0x30, 0x39, 0x36, 0x10, 0x0c, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, - 0x43, 0x4c, 0x45, 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x55, - 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, 0x0e, - 0x12, 0x14, 0x0a, 0x10, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x33, - 0x32, 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x12, 0xea, 0xaa, 0x19, 0x0e, 0x18, 0x01, 0x2a, 0x0a, - 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x2a, 0xc1, 0x01, 0x0a, 0x0e, 0x50, - 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x11, 0x0a, - 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x31, 0x53, 0x10, 0x00, - 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x32, - 0x53, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, - 0x59, 0x5f, 0x34, 0x53, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, - 0x56, 0x45, 0x52, 0x59, 0x5f, 0x38, 0x53, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x49, 0x4e, - 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x31, 0x36, 0x53, 0x10, 0x04, 0x12, 0x12, 0x0a, - 0x0e, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x33, 0x32, 0x53, 0x10, - 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, - 0x36, 0x34, 0x53, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, - 0x45, 0x52, 0x59, 0x5f, 0x31, 0x32, 0x38, 0x53, 0x10, 0x07, 0x1a, 0x12, 0xea, 0xaa, 0x19, 0x0e, - 0x18, 0x01, 0x2a, 0x0a, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x2a, 0x9b, - 0x03, 0x0a, 0x13, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, + 0x67, 0x2f, 0x74, 0x74, 0x6e, 0x70, 0x62, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x2a, 0xba, 0x02, 0x0a, 0x0e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, + 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, + 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, + 0x5f, 0x31, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, + 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, + 0x5f, 0x33, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, + 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, + 0x5f, 0x35, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, + 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, + 0x44, 0x41, 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, + 0x5f, 0x37, 0x10, 0x07, 0x1a, 0x68, 0xea, 0xaa, 0x19, 0x14, 0x10, 0x01, 0x2a, 0x10, 0x44, 0x41, + 0x54, 0x41, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0xf2, 0xaa, + 0x19, 0x4c, 0x0a, 0x4a, 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, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x61, 0x74, 0x65, 0x4f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x5d, + 0x0a, 0x0f, 0x4a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x54, + 0x45, 0x58, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, + 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45, 0x4a, + 0x4f, 0x49, 0x4e, 0x5f, 0x4b, 0x45, 0x59, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x04, 0x4a, 0x4f, + 0x49, 0x4e, 0x10, 0xff, 0x01, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x3f, 0x0a, + 0x11, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x10, 0x00, 0x12, + 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, + 0x4b, 0x45, 0x59, 0x53, 0x10, 0x02, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x38, + 0x0a, 0x0a, 0x43, 0x46, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, + 0x46, 0x52, 0x45, 0x51, 0x55, 0x45, 0x4e, 0x43, 0x49, 0x45, 0x53, 0x10, 0x00, 0x12, 0x11, 0x0a, + 0x0d, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4d, 0x41, 0x53, 0x4b, 0x53, 0x10, 0x01, + 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, 0x01, 0x2a, 0x3d, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x73, + 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x41, 0x10, 0x00, 0x12, 0x0b, + 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x42, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x43, + 0x4c, 0x41, 0x53, 0x53, 0x5f, 0x43, 0x10, 0x02, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x18, 0x01, + 0x2a, 0x05, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x2a, 0x78, 0x0a, 0x12, 0x54, 0x78, 0x53, 0x63, 0x68, + 0x65, 0x64, 0x75, 0x6c, 0x65, 0x50, 0x72, 0x69, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0a, 0x0a, + 0x06, 0x4c, 0x4f, 0x57, 0x45, 0x53, 0x54, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, + 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x42, 0x45, 0x4c, 0x4f, 0x57, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, + 0x41, 0x4c, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x03, + 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x42, 0x4f, 0x56, 0x45, 0x5f, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, + 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x05, 0x12, 0x0b, 0x0a, 0x07, + 0x48, 0x49, 0x47, 0x48, 0x45, 0x53, 0x54, 0x10, 0x06, 0x1a, 0x06, 0xea, 0xaa, 0x19, 0x02, 0x18, + 0x01, 0x2a, 0xbc, 0x05, 0x0a, 0x14, 0x4d, 0x41, 0x43, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, + 0x44, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, 0x44, + 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, + 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, + 0x43, 0x49, 0x44, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x41, 0x44, 0x52, 0x10, 0x03, 0x12, 0x12, + 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, + 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x58, 0x5f, 0x50, 0x41, 0x52, + 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, + 0x44, 0x5f, 0x44, 0x45, 0x56, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x10, 0x06, 0x12, 0x13, + 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x4e, 0x45, 0x57, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, + 0x4c, 0x10, 0x07, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x58, 0x5f, 0x54, 0x49, + 0x4d, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, + 0x43, 0x49, 0x44, 0x5f, 0x54, 0x58, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, + 0x55, 0x50, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x4c, 0x5f, 0x43, + 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x0a, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x49, 0x44, 0x5f, + 0x52, 0x45, 0x4b, 0x45, 0x59, 0x10, 0x0b, 0x12, 0x17, 0x0a, 0x13, 0x43, 0x49, 0x44, 0x5f, 0x41, + 0x44, 0x52, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x0c, + 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x54, + 0x49, 0x4d, 0x45, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x43, 0x49, 0x44, 0x5f, 0x46, 0x4f, 0x52, + 0x43, 0x45, 0x5f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x10, 0x0e, 0x12, 0x1a, 0x0a, 0x16, 0x43, + 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x5f, + 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, 0x0f, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, 0x44, 0x5f, 0x50, + 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x4c, 0x4f, 0x54, 0x5f, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x10, 0x12, + 0x19, 0x0a, 0x15, 0x43, 0x49, 0x44, 0x5f, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x4c, 0x4f, 0x54, + 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x10, 0x11, 0x12, 0x15, 0x0a, 0x11, 0x43, 0x49, + 0x44, 0x5f, 0x42, 0x45, 0x41, 0x43, 0x4f, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x49, 0x4e, 0x47, 0x10, + 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x42, 0x45, 0x41, 0x43, 0x4f, 0x4e, 0x5f, + 0x46, 0x52, 0x45, 0x51, 0x10, 0x13, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x49, 0x44, 0x5f, 0x44, 0x45, + 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x20, 0x12, 0x12, 0x0a, 0x0e, 0x43, + 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x10, 0x40, 0x12, + 0x1d, 0x0a, 0x19, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x45, 0x4e, 0x44, + 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x10, 0x41, 0x12, 0x19, + 0x0a, 0x15, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x46, 0x49, 0x4c, 0x54, + 0x45, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x42, 0x12, 0x20, 0x0a, 0x1c, 0x43, 0x49, 0x44, + 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x50, + 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x43, 0x12, 0x1e, 0x0a, 0x1a, 0x43, + 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x54, 0x52, 0x4c, 0x5f, 0x55, 0x50, + 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x44, 0x12, 0x21, 0x0a, 0x1d, 0x43, + 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x55, + 0x52, 0x45, 0x5f, 0x46, 0x57, 0x44, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x10, 0x45, 0x12, 0x23, + 0x0a, 0x1f, 0x43, 0x49, 0x44, 0x5f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4e, 0x4f, 0x54, 0x49, + 0x46, 0x59, 0x5f, 0x4e, 0x45, 0x57, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, + 0x45, 0x10, 0x46, 0x1a, 0x0b, 0xea, 0xaa, 0x19, 0x07, 0x18, 0x01, 0x2a, 0x03, 0x43, 0x49, 0x44, + 0x2a, 0xb2, 0x02, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x41, 0x44, 0x50, 0x65, 0x72, + 0x69, 0x6f, 0x64, 0x69, 0x63, 0x69, 0x74, 0x79, 0x12, 0x22, 0x0a, 0x1e, 0x52, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x49, 0x54, + 0x59, 0x5f, 0x31, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x2a, 0x0a, 0x26, + 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, + 0x49, 0x43, 0x49, 0x54, 0x59, 0x5f, 0x35, 0x30, 0x30, 0x5f, 0x4d, 0x49, 0x4c, 0x4c, 0x49, 0x53, + 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x53, 0x10, 0x01, 0x12, 0x2a, 0x0a, 0x26, 0x52, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x49, 0x54, + 0x59, 0x5f, 0x32, 0x35, 0x30, 0x5f, 0x4d, 0x49, 0x4c, 0x4c, 0x49, 0x53, 0x45, 0x43, 0x4f, 0x4e, + 0x44, 0x53, 0x10, 0x02, 0x12, 0x2a, 0x0a, 0x26, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x41, + 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x49, 0x54, 0x59, 0x5f, 0x31, 0x30, + 0x30, 0x5f, 0x4d, 0x49, 0x4c, 0x4c, 0x49, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x53, 0x10, 0x03, + 0x12, 0x29, 0x0a, 0x25, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, + 0x52, 0x49, 0x4f, 0x44, 0x49, 0x43, 0x49, 0x54, 0x59, 0x5f, 0x35, 0x30, 0x5f, 0x4d, 0x49, 0x4c, + 0x4c, 0x49, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x53, 0x10, 0x04, 0x12, 0x29, 0x0a, 0x25, 0x52, + 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x49, + 0x43, 0x49, 0x54, 0x59, 0x5f, 0x32, 0x30, 0x5f, 0x4d, 0x49, 0x4c, 0x4c, 0x49, 0x53, 0x45, 0x43, + 0x4f, 0x4e, 0x44, 0x53, 0x10, 0x05, 0x1a, 0x1d, 0xea, 0xaa, 0x19, 0x19, 0x18, 0x01, 0x2a, 0x15, + 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x41, 0x44, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, + 0x49, 0x43, 0x49, 0x54, 0x59, 0x2a, 0x94, 0x02, 0x0a, 0x16, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x43, 0x68, 0x41, 0x63, 0x6b, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, + 0x12, 0x20, 0x0a, 0x1c, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, + 0x5f, 0x43, 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x30, + 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, 0x4f, + 0x4e, 0x44, 0x5f, 0x43, 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, + 0x5f, 0x32, 0x30, 0x30, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, + 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x43, 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, + 0x46, 0x53, 0x45, 0x54, 0x5f, 0x34, 0x30, 0x30, 0x10, 0x02, 0x12, 0x22, 0x0a, 0x1e, 0x52, 0x45, + 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x43, 0x48, 0x5f, 0x41, 0x43, + 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x38, 0x30, 0x30, 0x10, 0x03, 0x12, 0x23, + 0x0a, 0x1f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x43, + 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x31, 0x36, 0x30, + 0x30, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, + 0x4f, 0x4e, 0x44, 0x5f, 0x43, 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, + 0x54, 0x5f, 0x33, 0x32, 0x30, 0x30, 0x10, 0x05, 0x1a, 0x22, 0xea, 0xaa, 0x19, 0x1e, 0x18, 0x01, + 0x2a, 0x1a, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x5f, 0x43, + 0x48, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x2a, 0xb4, 0x01, 0x0a, + 0x14, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x42, 0x75, 0x63, 0x6b, 0x65, + 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4c, + 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, + 0x5f, 0x31, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4c, 0x49, + 0x4d, 0x49, 0x54, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, + 0x32, 0x10, 0x01, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4c, 0x49, 0x4d, + 0x49, 0x54, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x34, + 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x4c, 0x49, 0x4d, 0x49, + 0x54, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x31, 0x32, + 0x10, 0x03, 0x1a, 0x1f, 0xea, 0xaa, 0x19, 0x1b, 0x18, 0x01, 0x2a, 0x17, 0x52, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x53, + 0x49, 0x5a, 0x45, 0x2a, 0xbc, 0x01, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x53, 0x6d, 0x61, + 0x72, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1e, 0x0a, + 0x1a, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x45, 0x4e, 0x41, + 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x38, 0x10, 0x00, 0x12, 0x1f, 0x0a, + 0x1b, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x45, 0x4e, 0x41, + 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x31, 0x36, 0x10, 0x01, 0x12, 0x1f, + 0x0a, 0x1b, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x45, 0x4e, + 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x33, 0x32, 0x10, 0x02, 0x12, + 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x45, + 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x45, 0x56, 0x45, 0x4c, 0x5f, 0x36, 0x34, 0x10, 0x03, + 0x1a, 0x20, 0xea, 0xaa, 0x19, 0x1c, 0x18, 0x01, 0x2a, 0x18, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, + 0x53, 0x4d, 0x41, 0x52, 0x54, 0x5f, 0x45, 0x4e, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x4c, 0x45, 0x56, + 0x45, 0x4c, 0x2a, 0x6c, 0x0a, 0x0f, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, 0x52, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x57, + 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, + 0x4c, 0x54, 0x10, 0x00, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x57, 0x4f, + 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x53, 0x45, 0x43, 0x4f, 0x4e, 0x44, + 0x41, 0x52, 0x59, 0x10, 0x01, 0x1a, 0x19, 0xea, 0xaa, 0x19, 0x15, 0x18, 0x01, 0x2a, 0x11, 0x52, + 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x57, 0x4f, 0x52, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x4e, 0x45, 0x4c, + 0x2a, 0xdb, 0x01, 0x0a, 0x16, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x73, 0x65, 0x74, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x1e, 0x52, + 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, + 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x5a, 0x45, 0x52, 0x4f, 0x10, 0x00, 0x12, + 0x29, 0x0a, 0x25, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x5f, 0x4c, + 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x52, 0x45, 0x4c, + 0x4f, 0x41, 0x44, 0x5f, 0x52, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x27, 0x0a, 0x23, 0x52, 0x45, + 0x4c, 0x41, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, + 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x58, 0x5f, 0x56, 0x41, 0x4c, 0x55, + 0x45, 0x10, 0x02, 0x12, 0x26, 0x0a, 0x22, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x52, 0x45, 0x53, + 0x45, 0x54, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, + 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, 0x10, 0x03, 0x1a, 0x21, 0xea, 0xaa, 0x19, + 0x1d, 0x18, 0x01, 0x2a, 0x19, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x52, 0x45, 0x53, 0x45, 0x54, + 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x45, 0x52, 0x2a, 0xaf, + 0x01, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x43, 0x74, 0x72, 0x6c, 0x55, 0x70, 0x6c, 0x69, + 0x6e, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x2a, + 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x54, 0x52, 0x4c, 0x5f, 0x55, 0x50, 0x4c, 0x49, 0x4e, + 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, + 0x41, 0x44, 0x5f, 0x57, 0x5f, 0x46, 0x5f, 0x43, 0x4e, 0x54, 0x10, 0x00, 0x12, 0x3b, 0x0a, 0x37, + 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x54, 0x52, 0x4c, 0x5f, 0x55, 0x50, 0x4c, 0x49, 0x4e, + 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, + 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x52, 0x55, 0x53, 0x54, 0x45, 0x44, 0x5f, 0x45, 0x4e, 0x44, + 0x5f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x10, 0x01, 0x1a, 0x25, 0xea, 0xaa, 0x19, 0x21, 0x18, + 0x01, 0x2a, 0x1d, 0x52, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x43, 0x54, 0x52, 0x4c, 0x5f, 0x55, 0x50, + 0x4c, 0x49, 0x4e, 0x4b, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, + 0x2a, 0xe6, 0x02, 0x0a, 0x13, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x44, + 0x75, 0x74, 0x79, 0x43, 0x79, 0x63, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x55, 0x54, 0x59, + 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x55, + 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, + 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x34, 0x10, 0x02, 0x12, 0x10, + 0x0a, 0x0c, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x38, 0x10, 0x03, + 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, + 0x36, 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, + 0x45, 0x5f, 0x33, 0x32, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, + 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x36, 0x34, 0x10, 0x06, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x55, 0x54, + 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x12, 0x0a, + 0x0e, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x35, 0x36, 0x10, + 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, + 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, + 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0a, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, + 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, 0x12, + 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x34, 0x30, + 0x39, 0x36, 0x10, 0x0c, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, + 0x4c, 0x45, 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x14, 0x0a, 0x10, 0x44, 0x55, 0x54, + 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, 0x0e, 0x12, + 0x14, 0x0a, 0x10, 0x44, 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x5f, 0x33, 0x32, + 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x12, 0xea, 0xaa, 0x19, 0x0e, 0x18, 0x01, 0x2a, 0x0a, 0x44, + 0x55, 0x54, 0x59, 0x5f, 0x43, 0x59, 0x43, 0x4c, 0x45, 0x2a, 0xc1, 0x01, 0x0a, 0x0e, 0x50, 0x69, + 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x11, 0x0a, 0x0d, + 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x31, 0x53, 0x10, 0x00, 0x12, + 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x32, 0x53, + 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, + 0x5f, 0x34, 0x53, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, + 0x45, 0x52, 0x59, 0x5f, 0x38, 0x53, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x49, 0x4e, 0x47, + 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x31, 0x36, 0x53, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, + 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x33, 0x32, 0x53, 0x10, 0x05, + 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x5f, 0x36, + 0x34, 0x53, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, + 0x52, 0x59, 0x5f, 0x31, 0x32, 0x38, 0x53, 0x10, 0x07, 0x1a, 0x12, 0xea, 0xaa, 0x19, 0x0e, 0x18, + 0x01, 0x2a, 0x0a, 0x50, 0x49, 0x4e, 0x47, 0x5f, 0x45, 0x56, 0x45, 0x52, 0x59, 0x2a, 0x9b, 0x03, + 0x0a, 0x13, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, + 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, + 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x36, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x33, 0x32, 0x10, 0x01, 0x12, + 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, + 0x36, 0x34, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, + 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x04, + 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, + 0x5f, 0x35, 0x31, 0x32, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, + 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x06, 0x12, 0x15, 0x0a, + 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x32, 0x30, + 0x34, 0x38, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, + 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, 0x52, + 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x38, 0x31, 0x39, 0x32, + 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, + 0x4e, 0x54, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x33, 0x32, 0x37, 0x36, 0x38, + 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, + 0x4e, 0x54, 0x5f, 0x36, 0x35, 0x35, 0x33, 0x36, 0x10, 0x0c, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x33, 0x31, 0x30, 0x37, + 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, + 0x55, 0x4e, 0x54, 0x5f, 0x32, 0x36, 0x32, 0x31, 0x34, 0x34, 0x10, 0x0e, 0x12, 0x17, 0x0a, 0x13, + 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x35, 0x32, 0x34, + 0x32, 0x38, 0x38, 0x10, 0x0f, 0x1a, 0x14, 0xea, 0xaa, 0x19, 0x10, 0x18, 0x01, 0x2a, 0x0c, 0x52, + 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2a, 0xdf, 0x02, 0x0a, 0x12, + 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, + 0x45, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, + 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, + 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x52, + 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x11, + 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x34, 0x10, + 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, + 0x5f, 0x35, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, + 0x49, 0x4d, 0x45, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, + 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x11, 0x0a, + 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x39, 0x10, 0x09, + 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, + 0x31, 0x30, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, + 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x31, 0x10, 0x0b, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, + 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x32, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, + 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x33, 0x10, 0x0d, + 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, + 0x31, 0x34, 0x10, 0x0e, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, + 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, 0x13, 0xea, 0xaa, 0x19, 0x0f, 0x18, 0x01, + 0x2a, 0x0b, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x2a, 0xd5, 0x01, + 0x0a, 0x14, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, - 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x36, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x33, 0x32, 0x10, 0x01, - 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, - 0x5f, 0x36, 0x34, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x32, 0x35, 0x36, 0x10, - 0x04, 0x12, 0x14, 0x0a, 0x10, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, - 0x54, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, - 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x06, 0x12, 0x15, - 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x32, - 0x30, 0x34, 0x38, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, - 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x38, 0x31, 0x39, - 0x32, 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, - 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x33, 0x32, 0x37, 0x36, - 0x38, 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, - 0x55, 0x4e, 0x54, 0x5f, 0x36, 0x35, 0x35, 0x33, 0x36, 0x10, 0x0c, 0x12, 0x17, 0x0a, 0x13, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x31, 0x33, 0x31, 0x30, - 0x37, 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, - 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x32, 0x36, 0x32, 0x31, 0x34, 0x34, 0x10, 0x0e, 0x12, 0x17, 0x0a, - 0x13, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x35, 0x32, - 0x34, 0x32, 0x38, 0x38, 0x10, 0x0f, 0x1a, 0x14, 0xea, 0xaa, 0x19, 0x10, 0x18, 0x01, 0x2a, 0x0c, - 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x2a, 0xdf, 0x02, 0x0a, - 0x12, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x45, 0x78, 0x70, 0x6f, 0x6e, - 0x65, 0x6e, 0x74, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, - 0x4d, 0x45, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, - 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, - 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, - 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x33, 0x10, 0x03, 0x12, - 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x34, - 0x10, 0x04, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, - 0x45, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x11, 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, - 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x11, 0x0a, 0x0d, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x11, - 0x0a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x39, 0x10, - 0x09, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, - 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x31, 0x10, 0x0b, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, - 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x32, 0x10, 0x0c, 0x12, 0x12, 0x0a, - 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x33, 0x10, - 0x0d, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, - 0x5f, 0x31, 0x34, 0x10, 0x0e, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x54, 0x49, 0x4d, 0x45, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, 0x13, 0xea, 0xaa, 0x19, 0x0f, 0x18, - 0x01, 0x2a, 0x0b, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x54, 0x49, 0x4d, 0x45, 0x2a, 0xd5, - 0x01, 0x0a, 0x14, 0x52, 0x65, 0x6a, 0x6f, 0x69, 0x6e, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x45, - 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, - 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, - 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x31, 0x10, - 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, - 0x4f, 0x44, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, - 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x52, - 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x34, 0x10, 0x04, + 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x52, + 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, - 0x44, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, - 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x37, 0x10, 0x07, 0x1a, - 0x15, 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, - 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x2a, 0xe0, 0x02, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, - 0x65, 0x45, 0x49, 0x52, 0x50, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, - 0x45, 0x49, 0x52, 0x50, 0x5f, 0x38, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x30, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, - 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x32, 0x10, 0x02, - 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, - 0x31, 0x33, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, - 0x49, 0x52, 0x50, 0x5f, 0x31, 0x34, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x36, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, - 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x38, 0x10, 0x06, - 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, - 0x32, 0x30, 0x10, 0x07, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, - 0x49, 0x52, 0x50, 0x5f, 0x32, 0x31, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, 0x34, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, - 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, 0x36, 0x10, 0x0a, - 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, - 0x32, 0x37, 0x10, 0x0b, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, - 0x49, 0x52, 0x50, 0x5f, 0x32, 0x39, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, - 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x33, 0x30, 0x10, 0x0d, 0x12, 0x12, 0x0a, 0x0e, - 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x33, 0x33, 0x10, 0x0e, - 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, - 0x33, 0x36, 0x10, 0x0f, 0x1a, 0x13, 0xea, 0xaa, 0x19, 0x0f, 0x18, 0x01, 0x2a, 0x0b, 0x44, 0x45, - 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x2a, 0x99, 0x03, 0x0a, 0x13, 0x41, 0x44, - 0x52, 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, - 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, - 0x49, 0x54, 0x5f, 0x31, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, - 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, - 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x34, 0x10, 0x02, + 0x44, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, + 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, + 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x34, 0x10, 0x04, 0x12, + 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, + 0x5f, 0x35, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, + 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x13, 0x0a, 0x0f, 0x52, 0x45, 0x4a, + 0x4f, 0x49, 0x4e, 0x5f, 0x50, 0x45, 0x52, 0x49, 0x4f, 0x44, 0x5f, 0x37, 0x10, 0x07, 0x1a, 0x15, + 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, 0x0d, 0x52, 0x45, 0x4a, 0x4f, 0x49, 0x4e, 0x5f, 0x50, + 0x45, 0x52, 0x49, 0x4f, 0x44, 0x2a, 0xe0, 0x02, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x45, 0x49, 0x52, 0x50, 0x12, 0x11, 0x0a, 0x0d, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, + 0x49, 0x52, 0x50, 0x5f, 0x38, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, + 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x30, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x44, + 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x32, 0x10, 0x02, 0x12, + 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, + 0x33, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, + 0x52, 0x50, 0x5f, 0x31, 0x34, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, + 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x36, 0x10, 0x05, 0x12, 0x12, 0x0a, 0x0e, 0x44, + 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x31, 0x38, 0x10, 0x06, 0x12, + 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, + 0x30, 0x10, 0x07, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, + 0x52, 0x50, 0x5f, 0x32, 0x31, 0x10, 0x08, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, + 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, 0x34, 0x10, 0x09, 0x12, 0x12, 0x0a, 0x0e, 0x44, + 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, 0x36, 0x10, 0x0a, 0x12, + 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x32, + 0x37, 0x10, 0x0b, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, + 0x52, 0x50, 0x5f, 0x32, 0x39, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, + 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x33, 0x30, 0x10, 0x0d, 0x12, 0x12, 0x0a, 0x0e, 0x44, + 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x33, 0x33, 0x10, 0x0e, 0x12, + 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x5f, 0x33, + 0x36, 0x10, 0x0f, 0x1a, 0x13, 0xea, 0xaa, 0x19, 0x0f, 0x18, 0x01, 0x2a, 0x0b, 0x44, 0x45, 0x56, + 0x49, 0x43, 0x45, 0x5f, 0x45, 0x49, 0x52, 0x50, 0x2a, 0x99, 0x03, 0x0a, 0x13, 0x41, 0x44, 0x52, + 0x41, 0x63, 0x6b, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, - 0x54, 0x5f, 0x38, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, - 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x36, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x41, - 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x33, 0x32, 0x10, - 0x05, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, - 0x49, 0x54, 0x5f, 0x36, 0x34, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, - 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x15, - 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, - 0x32, 0x35, 0x36, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, - 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, - 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x30, - 0x32, 0x34, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, - 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, - 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x34, 0x30, - 0x39, 0x36, 0x10, 0x0c, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, - 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, - 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x36, - 0x33, 0x38, 0x34, 0x10, 0x0e, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, - 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x33, 0x32, 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x15, - 0xea, 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, 0x0d, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, - 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x2a, 0x99, 0x03, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, - 0x44, 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, - 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, - 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, - 0x4c, 0x41, 0x59, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, - 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, - 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x38, 0x10, - 0x03, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, - 0x41, 0x59, 0x5f, 0x31, 0x36, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, - 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x33, 0x32, 0x10, 0x05, 0x12, 0x14, 0x0a, - 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x36, - 0x34, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, - 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, - 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x32, 0x35, 0x36, 0x10, - 0x08, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, - 0x41, 0x59, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, - 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0a, - 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, - 0x59, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, - 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x0c, - 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, - 0x59, 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, - 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, - 0x0e, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, - 0x41, 0x59, 0x5f, 0x33, 0x32, 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x15, 0xea, 0xaa, 0x19, 0x11, - 0x18, 0x01, 0x2a, 0x0d, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, - 0x59, 0x2a, 0xea, 0x02, 0x0a, 0x07, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x0e, 0x0a, - 0x0a, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x39, 0x10, 0x09, 0x12, 0x0f, 0x0a, - 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, 0x0f, - 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x31, 0x10, 0x0b, 0x12, - 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x32, 0x10, 0x0c, - 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x33, 0x10, - 0x0d, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x34, - 0x10, 0x0e, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, - 0x35, 0x10, 0x0f, 0x1a, 0x59, 0xea, 0xaa, 0x19, 0x0c, 0x10, 0x01, 0x2a, 0x08, 0x52, 0x58, 0x5f, - 0x44, 0x45, 0x4c, 0x41, 0x59, 0xf2, 0xaa, 0x19, 0x45, 0x0a, 0x43, 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, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, - 0x61, 0x79, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0xa8, - 0x02, 0x0a, 0x05, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, - 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x49, 0x4e, - 0x4f, 0x52, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, - 0x52, 0x46, 0x55, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, - 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, - 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, - 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, - 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, - 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x0f, 0x0a, 0x0b, - 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x0f, 0x0a, - 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x39, 0x10, 0x09, 0x12, 0x10, - 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x30, 0x10, 0x0a, - 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x31, - 0x10, 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, - 0x31, 0x32, 0x10, 0x0c, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, - 0x55, 0x5f, 0x31, 0x33, 0x10, 0x0d, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, - 0x52, 0x46, 0x55, 0x5f, 0x31, 0x34, 0x10, 0x0e, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, - 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, - 0x18, 0x01, 0x2a, 0x05, 0x4d, 0x49, 0x4e, 0x4f, 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, + 0x54, 0x5f, 0x31, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, + 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, + 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x34, 0x10, 0x02, 0x12, + 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, + 0x5f, 0x38, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, + 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x36, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, + 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x33, 0x32, 0x10, 0x05, + 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, + 0x54, 0x5f, 0x36, 0x34, 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, + 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x15, 0x0a, + 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x32, + 0x35, 0x36, 0x10, 0x08, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, + 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, 0x41, + 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x30, 0x32, + 0x34, 0x10, 0x0a, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, + 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, 0x41, + 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x34, 0x30, 0x39, + 0x36, 0x10, 0x0c, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, + 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x41, + 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x31, 0x36, 0x33, + 0x38, 0x34, 0x10, 0x0e, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, + 0x4c, 0x49, 0x4d, 0x49, 0x54, 0x5f, 0x33, 0x32, 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x15, 0xea, + 0xaa, 0x19, 0x11, 0x18, 0x01, 0x2a, 0x0d, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x4c, + 0x49, 0x4d, 0x49, 0x54, 0x2a, 0x99, 0x03, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x41, 0x63, 0x6b, 0x44, + 0x65, 0x6c, 0x61, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x0a, 0x0f, + 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x10, + 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, + 0x41, 0x59, 0x5f, 0x32, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, + 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x41, + 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x38, 0x10, 0x03, + 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x31, 0x36, 0x10, 0x04, 0x12, 0x14, 0x0a, 0x10, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, + 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x33, 0x32, 0x10, 0x05, 0x12, 0x14, 0x0a, 0x10, + 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x36, 0x34, + 0x10, 0x06, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, + 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x32, 0x38, 0x10, 0x07, 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, + 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x32, 0x35, 0x36, 0x10, 0x08, + 0x12, 0x15, 0x0a, 0x11, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x35, 0x31, 0x32, 0x10, 0x09, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, + 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x30, 0x32, 0x34, 0x10, 0x0a, 0x12, + 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, + 0x5f, 0x32, 0x30, 0x34, 0x38, 0x10, 0x0b, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, + 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x30, 0x39, 0x36, 0x10, 0x0c, 0x12, + 0x16, 0x0a, 0x12, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, + 0x5f, 0x38, 0x31, 0x39, 0x32, 0x10, 0x0d, 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, 0x41, + 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x36, 0x33, 0x38, 0x34, 0x10, 0x0e, + 0x12, 0x17, 0x0a, 0x13, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, + 0x59, 0x5f, 0x33, 0x32, 0x37, 0x36, 0x38, 0x10, 0x0f, 0x1a, 0x15, 0xea, 0xaa, 0x19, 0x11, 0x18, + 0x01, 0x2a, 0x0d, 0x41, 0x44, 0x52, 0x5f, 0x41, 0x43, 0x4b, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, + 0x2a, 0xea, 0x02, 0x0a, 0x07, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x0e, 0x0a, 0x0a, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x39, 0x10, 0x09, 0x12, 0x0f, 0x0a, 0x0b, + 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, 0x0f, 0x0a, + 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x31, 0x10, 0x0b, 0x12, 0x0f, + 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x32, 0x10, 0x0c, 0x12, + 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x33, 0x10, 0x0d, + 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x34, 0x10, + 0x0e, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x58, 0x5f, 0x44, 0x45, 0x4c, 0x41, 0x59, 0x5f, 0x31, 0x35, + 0x10, 0x0f, 0x1a, 0x59, 0xea, 0xaa, 0x19, 0x0c, 0x10, 0x01, 0x2a, 0x08, 0x52, 0x58, 0x5f, 0x44, + 0x45, 0x4c, 0x41, 0x59, 0xf2, 0xaa, 0x19, 0x45, 0x0a, 0x43, 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, 0x2e, 0x52, 0x78, 0x44, 0x65, 0x6c, 0x61, + 0x79, 0x5f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0xa8, 0x02, + 0x0a, 0x05, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, + 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x30, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x49, 0x4e, 0x4f, + 0x52, 0x5f, 0x31, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, + 0x46, 0x55, 0x5f, 0x32, 0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, + 0x52, 0x46, 0x55, 0x5f, 0x33, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, 0x52, + 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x34, 0x10, 0x04, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, 0x4f, + 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x35, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, 0x4e, + 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x36, 0x10, 0x06, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x49, + 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x37, 0x10, 0x07, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, + 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x38, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, + 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x39, 0x10, 0x09, 0x12, 0x10, 0x0a, + 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x30, 0x10, 0x0a, 0x12, + 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x31, 0x10, + 0x0b, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, + 0x32, 0x10, 0x0c, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, 0x46, 0x55, + 0x5f, 0x31, 0x33, 0x10, 0x0d, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, 0x5f, 0x52, + 0x46, 0x55, 0x5f, 0x31, 0x34, 0x10, 0x0e, 0x12, 0x10, 0x0a, 0x0c, 0x4d, 0x49, 0x4e, 0x4f, 0x52, + 0x5f, 0x52, 0x46, 0x55, 0x5f, 0x31, 0x35, 0x10, 0x0f, 0x1a, 0x0d, 0xea, 0xaa, 0x19, 0x09, 0x18, + 0x01, 0x2a, 0x05, 0x4d, 0x49, 0x4e, 0x4f, 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 ( @@ -7377,205 +9790,269 @@ func file_ttn_lorawan_v3_lorawan_proto_rawDescGZIP() []byte { return file_ttn_lorawan_v3_lorawan_proto_rawDescData } -var file_ttn_lorawan_v3_lorawan_proto_enumTypes = make([]protoimpl.EnumInfo, 22) -var file_ttn_lorawan_v3_lorawan_proto_msgTypes = make([]protoimpl.MessageInfo, 63) +var file_ttn_lorawan_v3_lorawan_proto_enumTypes = make([]protoimpl.EnumInfo, 29) +var file_ttn_lorawan_v3_lorawan_proto_msgTypes = make([]protoimpl.MessageInfo, 85) var file_ttn_lorawan_v3_lorawan_proto_goTypes = []interface{}{ - (MType)(0), // 0: ttn.lorawan.v3.MType - (Major)(0), // 1: ttn.lorawan.v3.Major - (MACVersion)(0), // 2: ttn.lorawan.v3.MACVersion - (PHYVersion)(0), // 3: ttn.lorawan.v3.PHYVersion - (DataRateIndex)(0), // 4: ttn.lorawan.v3.DataRateIndex - (DataRateOffset)(0), // 5: ttn.lorawan.v3.DataRateOffset - (JoinRequestType)(0), // 6: ttn.lorawan.v3.JoinRequestType - (RejoinRequestType)(0), // 7: ttn.lorawan.v3.RejoinRequestType - (CFListType)(0), // 8: ttn.lorawan.v3.CFListType - (Class)(0), // 9: ttn.lorawan.v3.Class - (TxSchedulePriority)(0), // 10: ttn.lorawan.v3.TxSchedulePriority - (MACCommandIdentifier)(0), // 11: ttn.lorawan.v3.MACCommandIdentifier - (AggregatedDutyCycle)(0), // 12: ttn.lorawan.v3.AggregatedDutyCycle - (PingSlotPeriod)(0), // 13: ttn.lorawan.v3.PingSlotPeriod - (RejoinCountExponent)(0), // 14: ttn.lorawan.v3.RejoinCountExponent - (RejoinTimeExponent)(0), // 15: ttn.lorawan.v3.RejoinTimeExponent - (RejoinPeriodExponent)(0), // 16: ttn.lorawan.v3.RejoinPeriodExponent - (DeviceEIRP)(0), // 17: ttn.lorawan.v3.DeviceEIRP - (ADRAckLimitExponent)(0), // 18: ttn.lorawan.v3.ADRAckLimitExponent - (ADRAckDelayExponent)(0), // 19: ttn.lorawan.v3.ADRAckDelayExponent - (RxDelay)(0), // 20: ttn.lorawan.v3.RxDelay - (Minor)(0), // 21: ttn.lorawan.v3.Minor - (*Message)(nil), // 22: ttn.lorawan.v3.Message - (*MHDR)(nil), // 23: ttn.lorawan.v3.MHDR - (*MACPayload)(nil), // 24: ttn.lorawan.v3.MACPayload - (*FHDR)(nil), // 25: ttn.lorawan.v3.FHDR - (*FCtrl)(nil), // 26: ttn.lorawan.v3.FCtrl - (*JoinRequestPayload)(nil), // 27: ttn.lorawan.v3.JoinRequestPayload - (*RejoinRequestPayload)(nil), // 28: ttn.lorawan.v3.RejoinRequestPayload - (*JoinAcceptPayload)(nil), // 29: ttn.lorawan.v3.JoinAcceptPayload - (*DLSettings)(nil), // 30: ttn.lorawan.v3.DLSettings - (*CFList)(nil), // 31: ttn.lorawan.v3.CFList - (*LoRaDataRate)(nil), // 32: ttn.lorawan.v3.LoRaDataRate - (*FSKDataRate)(nil), // 33: ttn.lorawan.v3.FSKDataRate - (*LRFHSSDataRate)(nil), // 34: ttn.lorawan.v3.LRFHSSDataRate - (*DataRate)(nil), // 35: ttn.lorawan.v3.DataRate - (*TxSettings)(nil), // 36: ttn.lorawan.v3.TxSettings - (*GatewayAntennaIdentifiers)(nil), // 37: ttn.lorawan.v3.GatewayAntennaIdentifiers - (*ClassBCGatewayIdentifiers)(nil), // 38: ttn.lorawan.v3.ClassBCGatewayIdentifiers - (*UplinkToken)(nil), // 39: ttn.lorawan.v3.UplinkToken - (*DownlinkPath)(nil), // 40: ttn.lorawan.v3.DownlinkPath - (*TxRequest)(nil), // 41: ttn.lorawan.v3.TxRequest - (*MACCommand)(nil), // 42: ttn.lorawan.v3.MACCommand - (*MACCommands)(nil), // 43: ttn.lorawan.v3.MACCommands - (*FrequencyValue)(nil), // 44: ttn.lorawan.v3.FrequencyValue - (*ZeroableFrequencyValue)(nil), // 45: ttn.lorawan.v3.ZeroableFrequencyValue - (*DataRateOffsetValue)(nil), // 46: ttn.lorawan.v3.DataRateOffsetValue - (*DataRateIndexValue)(nil), // 47: ttn.lorawan.v3.DataRateIndexValue - (*PingSlotPeriodValue)(nil), // 48: ttn.lorawan.v3.PingSlotPeriodValue - (*AggregatedDutyCycleValue)(nil), // 49: ttn.lorawan.v3.AggregatedDutyCycleValue - (*RxDelayValue)(nil), // 50: ttn.lorawan.v3.RxDelayValue - (*ADRAckLimitExponentValue)(nil), // 51: ttn.lorawan.v3.ADRAckLimitExponentValue - (*ADRAckDelayExponentValue)(nil), // 52: ttn.lorawan.v3.ADRAckDelayExponentValue - (*DeviceEIRPValue)(nil), // 53: ttn.lorawan.v3.DeviceEIRPValue - (*TxSettings_Downlink)(nil), // 54: ttn.lorawan.v3.TxSettings.Downlink - (*MACCommand_ResetInd)(nil), // 55: ttn.lorawan.v3.MACCommand.ResetInd - (*MACCommand_ResetConf)(nil), // 56: ttn.lorawan.v3.MACCommand.ResetConf - (*MACCommand_LinkCheckAns)(nil), // 57: ttn.lorawan.v3.MACCommand.LinkCheckAns - (*MACCommand_LinkADRReq)(nil), // 58: ttn.lorawan.v3.MACCommand.LinkADRReq - (*MACCommand_LinkADRAns)(nil), // 59: ttn.lorawan.v3.MACCommand.LinkADRAns - (*MACCommand_DutyCycleReq)(nil), // 60: ttn.lorawan.v3.MACCommand.DutyCycleReq - (*MACCommand_RxParamSetupReq)(nil), // 61: ttn.lorawan.v3.MACCommand.RxParamSetupReq - (*MACCommand_RxParamSetupAns)(nil), // 62: ttn.lorawan.v3.MACCommand.RxParamSetupAns - (*MACCommand_DevStatusAns)(nil), // 63: ttn.lorawan.v3.MACCommand.DevStatusAns - (*MACCommand_NewChannelReq)(nil), // 64: ttn.lorawan.v3.MACCommand.NewChannelReq - (*MACCommand_NewChannelAns)(nil), // 65: ttn.lorawan.v3.MACCommand.NewChannelAns - (*MACCommand_DLChannelReq)(nil), // 66: ttn.lorawan.v3.MACCommand.DLChannelReq - (*MACCommand_DLChannelAns)(nil), // 67: ttn.lorawan.v3.MACCommand.DLChannelAns - (*MACCommand_RxTimingSetupReq)(nil), // 68: ttn.lorawan.v3.MACCommand.RxTimingSetupReq - (*MACCommand_TxParamSetupReq)(nil), // 69: ttn.lorawan.v3.MACCommand.TxParamSetupReq - (*MACCommand_RekeyInd)(nil), // 70: ttn.lorawan.v3.MACCommand.RekeyInd - (*MACCommand_RekeyConf)(nil), // 71: ttn.lorawan.v3.MACCommand.RekeyConf - (*MACCommand_ADRParamSetupReq)(nil), // 72: ttn.lorawan.v3.MACCommand.ADRParamSetupReq - (*MACCommand_DeviceTimeAns)(nil), // 73: ttn.lorawan.v3.MACCommand.DeviceTimeAns - (*MACCommand_ForceRejoinReq)(nil), // 74: ttn.lorawan.v3.MACCommand.ForceRejoinReq - (*MACCommand_RejoinParamSetupReq)(nil), // 75: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq - (*MACCommand_RejoinParamSetupAns)(nil), // 76: ttn.lorawan.v3.MACCommand.RejoinParamSetupAns - (*MACCommand_PingSlotInfoReq)(nil), // 77: ttn.lorawan.v3.MACCommand.PingSlotInfoReq - (*MACCommand_PingSlotChannelReq)(nil), // 78: ttn.lorawan.v3.MACCommand.PingSlotChannelReq - (*MACCommand_PingSlotChannelAns)(nil), // 79: ttn.lorawan.v3.MACCommand.PingSlotChannelAns - (*MACCommand_BeaconTimingAns)(nil), // 80: ttn.lorawan.v3.MACCommand.BeaconTimingAns - (*MACCommand_BeaconFreqReq)(nil), // 81: ttn.lorawan.v3.MACCommand.BeaconFreqReq - (*MACCommand_BeaconFreqAns)(nil), // 82: ttn.lorawan.v3.MACCommand.BeaconFreqAns - (*MACCommand_DeviceModeInd)(nil), // 83: ttn.lorawan.v3.MACCommand.DeviceModeInd - (*MACCommand_DeviceModeConf)(nil), // 84: ttn.lorawan.v3.MACCommand.DeviceModeConf - (*structpb.Struct)(nil), // 85: google.protobuf.Struct - (*timestamppb.Timestamp)(nil), // 86: google.protobuf.Timestamp - (*GatewayIdentifiers)(nil), // 87: ttn.lorawan.v3.GatewayIdentifiers + (MType)(0), // 0: ttn.lorawan.v3.MType + (Major)(0), // 1: ttn.lorawan.v3.Major + (MACVersion)(0), // 2: ttn.lorawan.v3.MACVersion + (PHYVersion)(0), // 3: ttn.lorawan.v3.PHYVersion + (DataRateIndex)(0), // 4: ttn.lorawan.v3.DataRateIndex + (DataRateOffset)(0), // 5: ttn.lorawan.v3.DataRateOffset + (JoinRequestType)(0), // 6: ttn.lorawan.v3.JoinRequestType + (RejoinRequestType)(0), // 7: ttn.lorawan.v3.RejoinRequestType + (CFListType)(0), // 8: ttn.lorawan.v3.CFListType + (Class)(0), // 9: ttn.lorawan.v3.Class + (TxSchedulePriority)(0), // 10: ttn.lorawan.v3.TxSchedulePriority + (MACCommandIdentifier)(0), // 11: ttn.lorawan.v3.MACCommandIdentifier + (RelayCADPeriodicity)(0), // 12: ttn.lorawan.v3.RelayCADPeriodicity + (RelaySecondChAckOffset)(0), // 13: ttn.lorawan.v3.RelaySecondChAckOffset + (RelayLimitBucketSize)(0), // 14: ttn.lorawan.v3.RelayLimitBucketSize + (RelaySmartEnableLevel)(0), // 15: ttn.lorawan.v3.RelaySmartEnableLevel + (RelayWORChannel)(0), // 16: ttn.lorawan.v3.RelayWORChannel + (RelayResetLimitCounter)(0), // 17: ttn.lorawan.v3.RelayResetLimitCounter + (RelayCtrlUplinkListAction)(0), // 18: ttn.lorawan.v3.RelayCtrlUplinkListAction + (AggregatedDutyCycle)(0), // 19: ttn.lorawan.v3.AggregatedDutyCycle + (PingSlotPeriod)(0), // 20: ttn.lorawan.v3.PingSlotPeriod + (RejoinCountExponent)(0), // 21: ttn.lorawan.v3.RejoinCountExponent + (RejoinTimeExponent)(0), // 22: ttn.lorawan.v3.RejoinTimeExponent + (RejoinPeriodExponent)(0), // 23: ttn.lorawan.v3.RejoinPeriodExponent + (DeviceEIRP)(0), // 24: ttn.lorawan.v3.DeviceEIRP + (ADRAckLimitExponent)(0), // 25: ttn.lorawan.v3.ADRAckLimitExponent + (ADRAckDelayExponent)(0), // 26: ttn.lorawan.v3.ADRAckDelayExponent + (RxDelay)(0), // 27: ttn.lorawan.v3.RxDelay + (Minor)(0), // 28: ttn.lorawan.v3.Minor + (*Message)(nil), // 29: ttn.lorawan.v3.Message + (*MHDR)(nil), // 30: ttn.lorawan.v3.MHDR + (*MACPayload)(nil), // 31: ttn.lorawan.v3.MACPayload + (*FHDR)(nil), // 32: ttn.lorawan.v3.FHDR + (*FCtrl)(nil), // 33: ttn.lorawan.v3.FCtrl + (*JoinRequestPayload)(nil), // 34: ttn.lorawan.v3.JoinRequestPayload + (*RejoinRequestPayload)(nil), // 35: ttn.lorawan.v3.RejoinRequestPayload + (*JoinAcceptPayload)(nil), // 36: ttn.lorawan.v3.JoinAcceptPayload + (*DLSettings)(nil), // 37: ttn.lorawan.v3.DLSettings + (*CFList)(nil), // 38: ttn.lorawan.v3.CFList + (*LoRaDataRate)(nil), // 39: ttn.lorawan.v3.LoRaDataRate + (*FSKDataRate)(nil), // 40: ttn.lorawan.v3.FSKDataRate + (*LRFHSSDataRate)(nil), // 41: ttn.lorawan.v3.LRFHSSDataRate + (*DataRate)(nil), // 42: ttn.lorawan.v3.DataRate + (*TxSettings)(nil), // 43: ttn.lorawan.v3.TxSettings + (*GatewayAntennaIdentifiers)(nil), // 44: ttn.lorawan.v3.GatewayAntennaIdentifiers + (*ClassBCGatewayIdentifiers)(nil), // 45: ttn.lorawan.v3.ClassBCGatewayIdentifiers + (*UplinkToken)(nil), // 46: ttn.lorawan.v3.UplinkToken + (*DownlinkPath)(nil), // 47: ttn.lorawan.v3.DownlinkPath + (*TxRequest)(nil), // 48: ttn.lorawan.v3.TxRequest + (*RelaySecondChannel)(nil), // 49: ttn.lorawan.v3.RelaySecondChannel + (*RelayUplinkForwardLimits)(nil), // 50: ttn.lorawan.v3.RelayUplinkForwardLimits + (*RelayForwardLimits)(nil), // 51: ttn.lorawan.v3.RelayForwardLimits + (*RelayEndDeviceAlwaysMode)(nil), // 52: ttn.lorawan.v3.RelayEndDeviceAlwaysMode + (*RelayEndDeviceDynamicMode)(nil), // 53: ttn.lorawan.v3.RelayEndDeviceDynamicMode + (*RelayEndDeviceControlledMode)(nil), // 54: ttn.lorawan.v3.RelayEndDeviceControlledMode + (*MACCommand)(nil), // 55: ttn.lorawan.v3.MACCommand + (*MACCommands)(nil), // 56: ttn.lorawan.v3.MACCommands + (*FrequencyValue)(nil), // 57: ttn.lorawan.v3.FrequencyValue + (*ZeroableFrequencyValue)(nil), // 58: ttn.lorawan.v3.ZeroableFrequencyValue + (*DataRateOffsetValue)(nil), // 59: ttn.lorawan.v3.DataRateOffsetValue + (*DataRateIndexValue)(nil), // 60: ttn.lorawan.v3.DataRateIndexValue + (*PingSlotPeriodValue)(nil), // 61: ttn.lorawan.v3.PingSlotPeriodValue + (*AggregatedDutyCycleValue)(nil), // 62: ttn.lorawan.v3.AggregatedDutyCycleValue + (*RxDelayValue)(nil), // 63: ttn.lorawan.v3.RxDelayValue + (*ADRAckLimitExponentValue)(nil), // 64: ttn.lorawan.v3.ADRAckLimitExponentValue + (*ADRAckDelayExponentValue)(nil), // 65: ttn.lorawan.v3.ADRAckDelayExponentValue + (*DeviceEIRPValue)(nil), // 66: ttn.lorawan.v3.DeviceEIRPValue + (*RelayForwardUplinkReq)(nil), // 67: ttn.lorawan.v3.RelayForwardUplinkReq + (*RelayForwardDownlinkReq)(nil), // 68: ttn.lorawan.v3.RelayForwardDownlinkReq + (*RelayUplinkToken)(nil), // 69: ttn.lorawan.v3.RelayUplinkToken + (*TxSettings_Downlink)(nil), // 70: ttn.lorawan.v3.TxSettings.Downlink + (*MACCommand_ResetInd)(nil), // 71: ttn.lorawan.v3.MACCommand.ResetInd + (*MACCommand_ResetConf)(nil), // 72: ttn.lorawan.v3.MACCommand.ResetConf + (*MACCommand_LinkCheckAns)(nil), // 73: ttn.lorawan.v3.MACCommand.LinkCheckAns + (*MACCommand_LinkADRReq)(nil), // 74: ttn.lorawan.v3.MACCommand.LinkADRReq + (*MACCommand_LinkADRAns)(nil), // 75: ttn.lorawan.v3.MACCommand.LinkADRAns + (*MACCommand_DutyCycleReq)(nil), // 76: ttn.lorawan.v3.MACCommand.DutyCycleReq + (*MACCommand_RxParamSetupReq)(nil), // 77: ttn.lorawan.v3.MACCommand.RxParamSetupReq + (*MACCommand_RxParamSetupAns)(nil), // 78: ttn.lorawan.v3.MACCommand.RxParamSetupAns + (*MACCommand_DevStatusAns)(nil), // 79: ttn.lorawan.v3.MACCommand.DevStatusAns + (*MACCommand_NewChannelReq)(nil), // 80: ttn.lorawan.v3.MACCommand.NewChannelReq + (*MACCommand_NewChannelAns)(nil), // 81: ttn.lorawan.v3.MACCommand.NewChannelAns + (*MACCommand_DLChannelReq)(nil), // 82: ttn.lorawan.v3.MACCommand.DLChannelReq + (*MACCommand_DLChannelAns)(nil), // 83: ttn.lorawan.v3.MACCommand.DLChannelAns + (*MACCommand_RxTimingSetupReq)(nil), // 84: ttn.lorawan.v3.MACCommand.RxTimingSetupReq + (*MACCommand_TxParamSetupReq)(nil), // 85: ttn.lorawan.v3.MACCommand.TxParamSetupReq + (*MACCommand_RekeyInd)(nil), // 86: ttn.lorawan.v3.MACCommand.RekeyInd + (*MACCommand_RekeyConf)(nil), // 87: ttn.lorawan.v3.MACCommand.RekeyConf + (*MACCommand_ADRParamSetupReq)(nil), // 88: ttn.lorawan.v3.MACCommand.ADRParamSetupReq + (*MACCommand_DeviceTimeAns)(nil), // 89: ttn.lorawan.v3.MACCommand.DeviceTimeAns + (*MACCommand_ForceRejoinReq)(nil), // 90: ttn.lorawan.v3.MACCommand.ForceRejoinReq + (*MACCommand_RejoinParamSetupReq)(nil), // 91: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq + (*MACCommand_RejoinParamSetupAns)(nil), // 92: ttn.lorawan.v3.MACCommand.RejoinParamSetupAns + (*MACCommand_PingSlotInfoReq)(nil), // 93: ttn.lorawan.v3.MACCommand.PingSlotInfoReq + (*MACCommand_PingSlotChannelReq)(nil), // 94: ttn.lorawan.v3.MACCommand.PingSlotChannelReq + (*MACCommand_PingSlotChannelAns)(nil), // 95: ttn.lorawan.v3.MACCommand.PingSlotChannelAns + (*MACCommand_BeaconTimingAns)(nil), // 96: ttn.lorawan.v3.MACCommand.BeaconTimingAns + (*MACCommand_BeaconFreqReq)(nil), // 97: ttn.lorawan.v3.MACCommand.BeaconFreqReq + (*MACCommand_BeaconFreqAns)(nil), // 98: ttn.lorawan.v3.MACCommand.BeaconFreqAns + (*MACCommand_DeviceModeInd)(nil), // 99: ttn.lorawan.v3.MACCommand.DeviceModeInd + (*MACCommand_DeviceModeConf)(nil), // 100: ttn.lorawan.v3.MACCommand.DeviceModeConf + (*MACCommand_RelayConfReq)(nil), // 101: ttn.lorawan.v3.MACCommand.RelayConfReq + (*MACCommand_RelayConfAns)(nil), // 102: ttn.lorawan.v3.MACCommand.RelayConfAns + (*MACCommand_RelayEndDeviceConfReq)(nil), // 103: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq + (*MACCommand_RelayEndDeviceConfAns)(nil), // 104: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfAns + (*MACCommand_RelayUpdateUplinkListReq)(nil), // 105: ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListReq + (*MACCommand_RelayUpdateUplinkListAns)(nil), // 106: ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListAns + (*MACCommand_RelayCtrlUplinkListReq)(nil), // 107: ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListReq + (*MACCommand_RelayCtrlUplinkListAns)(nil), // 108: ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListAns + (*MACCommand_RelayConfigureFwdLimitReq)(nil), // 109: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq + (*MACCommand_RelayConfigureFwdLimitAns)(nil), // 110: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitAns + (*MACCommand_RelayNotifyNewEndDeviceReq)(nil), // 111: ttn.lorawan.v3.MACCommand.RelayNotifyNewEndDeviceReq + (*MACCommand_RelayConfReq_Configuration)(nil), // 112: ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration + (*MACCommand_RelayEndDeviceConfReq_Configuration)(nil), // 113: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration + (*structpb.Struct)(nil), // 114: google.protobuf.Struct + (*timestamppb.Timestamp)(nil), // 115: google.protobuf.Timestamp + (*GatewayIdentifiers)(nil), // 116: ttn.lorawan.v3.GatewayIdentifiers + (*EndDeviceIdentifiers)(nil), // 117: ttn.lorawan.v3.EndDeviceIdentifiers } var file_ttn_lorawan_v3_lorawan_proto_depIdxs = []int32{ - 23, // 0: ttn.lorawan.v3.Message.m_hdr:type_name -> ttn.lorawan.v3.MHDR - 24, // 1: ttn.lorawan.v3.Message.mac_payload:type_name -> ttn.lorawan.v3.MACPayload - 27, // 2: ttn.lorawan.v3.Message.join_request_payload:type_name -> ttn.lorawan.v3.JoinRequestPayload - 29, // 3: ttn.lorawan.v3.Message.join_accept_payload:type_name -> ttn.lorawan.v3.JoinAcceptPayload - 28, // 4: ttn.lorawan.v3.Message.rejoin_request_payload:type_name -> ttn.lorawan.v3.RejoinRequestPayload + 30, // 0: ttn.lorawan.v3.Message.m_hdr:type_name -> ttn.lorawan.v3.MHDR + 31, // 1: ttn.lorawan.v3.Message.mac_payload:type_name -> ttn.lorawan.v3.MACPayload + 34, // 2: ttn.lorawan.v3.Message.join_request_payload:type_name -> ttn.lorawan.v3.JoinRequestPayload + 36, // 3: ttn.lorawan.v3.Message.join_accept_payload:type_name -> ttn.lorawan.v3.JoinAcceptPayload + 35, // 4: ttn.lorawan.v3.Message.rejoin_request_payload:type_name -> ttn.lorawan.v3.RejoinRequestPayload 0, // 5: ttn.lorawan.v3.MHDR.m_type:type_name -> ttn.lorawan.v3.MType 1, // 6: ttn.lorawan.v3.MHDR.major:type_name -> ttn.lorawan.v3.Major - 25, // 7: ttn.lorawan.v3.MACPayload.f_hdr:type_name -> ttn.lorawan.v3.FHDR - 85, // 8: ttn.lorawan.v3.MACPayload.decoded_payload:type_name -> google.protobuf.Struct - 26, // 9: ttn.lorawan.v3.FHDR.f_ctrl:type_name -> ttn.lorawan.v3.FCtrl + 32, // 7: ttn.lorawan.v3.MACPayload.f_hdr:type_name -> ttn.lorawan.v3.FHDR + 114, // 8: ttn.lorawan.v3.MACPayload.decoded_payload:type_name -> google.protobuf.Struct + 33, // 9: ttn.lorawan.v3.FHDR.f_ctrl:type_name -> ttn.lorawan.v3.FCtrl 7, // 10: ttn.lorawan.v3.RejoinRequestPayload.rejoin_type:type_name -> ttn.lorawan.v3.RejoinRequestType - 30, // 11: ttn.lorawan.v3.JoinAcceptPayload.dl_settings:type_name -> ttn.lorawan.v3.DLSettings - 20, // 12: ttn.lorawan.v3.JoinAcceptPayload.rx_delay:type_name -> ttn.lorawan.v3.RxDelay - 31, // 13: ttn.lorawan.v3.JoinAcceptPayload.cf_list:type_name -> ttn.lorawan.v3.CFList + 37, // 11: ttn.lorawan.v3.JoinAcceptPayload.dl_settings:type_name -> ttn.lorawan.v3.DLSettings + 27, // 12: ttn.lorawan.v3.JoinAcceptPayload.rx_delay:type_name -> ttn.lorawan.v3.RxDelay + 38, // 13: ttn.lorawan.v3.JoinAcceptPayload.cf_list:type_name -> ttn.lorawan.v3.CFList 5, // 14: ttn.lorawan.v3.DLSettings.rx1_dr_offset:type_name -> ttn.lorawan.v3.DataRateOffset 4, // 15: ttn.lorawan.v3.DLSettings.rx2_dr:type_name -> ttn.lorawan.v3.DataRateIndex 8, // 16: ttn.lorawan.v3.CFList.type:type_name -> ttn.lorawan.v3.CFListType - 32, // 17: ttn.lorawan.v3.DataRate.lora:type_name -> ttn.lorawan.v3.LoRaDataRate - 33, // 18: ttn.lorawan.v3.DataRate.fsk:type_name -> ttn.lorawan.v3.FSKDataRate - 34, // 19: ttn.lorawan.v3.DataRate.lrfhss:type_name -> ttn.lorawan.v3.LRFHSSDataRate - 35, // 20: ttn.lorawan.v3.TxSettings.data_rate:type_name -> ttn.lorawan.v3.DataRate - 86, // 21: ttn.lorawan.v3.TxSettings.time:type_name -> google.protobuf.Timestamp - 54, // 22: ttn.lorawan.v3.TxSettings.downlink:type_name -> ttn.lorawan.v3.TxSettings.Downlink - 87, // 23: ttn.lorawan.v3.GatewayAntennaIdentifiers.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers - 87, // 24: ttn.lorawan.v3.ClassBCGatewayIdentifiers.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers - 37, // 25: ttn.lorawan.v3.UplinkToken.ids:type_name -> ttn.lorawan.v3.GatewayAntennaIdentifiers - 86, // 26: ttn.lorawan.v3.UplinkToken.server_time:type_name -> google.protobuf.Timestamp - 86, // 27: ttn.lorawan.v3.UplinkToken.gateway_time:type_name -> google.protobuf.Timestamp - 37, // 28: ttn.lorawan.v3.DownlinkPath.fixed:type_name -> ttn.lorawan.v3.GatewayAntennaIdentifiers + 39, // 17: ttn.lorawan.v3.DataRate.lora:type_name -> ttn.lorawan.v3.LoRaDataRate + 40, // 18: ttn.lorawan.v3.DataRate.fsk:type_name -> ttn.lorawan.v3.FSKDataRate + 41, // 19: ttn.lorawan.v3.DataRate.lrfhss:type_name -> ttn.lorawan.v3.LRFHSSDataRate + 42, // 20: ttn.lorawan.v3.TxSettings.data_rate:type_name -> ttn.lorawan.v3.DataRate + 115, // 21: ttn.lorawan.v3.TxSettings.time:type_name -> google.protobuf.Timestamp + 70, // 22: ttn.lorawan.v3.TxSettings.downlink:type_name -> ttn.lorawan.v3.TxSettings.Downlink + 116, // 23: ttn.lorawan.v3.GatewayAntennaIdentifiers.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers + 116, // 24: ttn.lorawan.v3.ClassBCGatewayIdentifiers.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers + 44, // 25: ttn.lorawan.v3.UplinkToken.ids:type_name -> ttn.lorawan.v3.GatewayAntennaIdentifiers + 115, // 26: ttn.lorawan.v3.UplinkToken.server_time:type_name -> google.protobuf.Timestamp + 115, // 27: ttn.lorawan.v3.UplinkToken.gateway_time:type_name -> google.protobuf.Timestamp + 44, // 28: ttn.lorawan.v3.DownlinkPath.fixed:type_name -> ttn.lorawan.v3.GatewayAntennaIdentifiers 9, // 29: ttn.lorawan.v3.TxRequest.class:type_name -> ttn.lorawan.v3.Class - 40, // 30: ttn.lorawan.v3.TxRequest.downlink_paths:type_name -> ttn.lorawan.v3.DownlinkPath - 20, // 31: ttn.lorawan.v3.TxRequest.rx1_delay:type_name -> ttn.lorawan.v3.RxDelay - 35, // 32: ttn.lorawan.v3.TxRequest.rx1_data_rate:type_name -> ttn.lorawan.v3.DataRate - 35, // 33: ttn.lorawan.v3.TxRequest.rx2_data_rate:type_name -> ttn.lorawan.v3.DataRate + 47, // 30: ttn.lorawan.v3.TxRequest.downlink_paths:type_name -> ttn.lorawan.v3.DownlinkPath + 27, // 31: ttn.lorawan.v3.TxRequest.rx1_delay:type_name -> ttn.lorawan.v3.RxDelay + 42, // 32: ttn.lorawan.v3.TxRequest.rx1_data_rate:type_name -> ttn.lorawan.v3.DataRate + 42, // 33: ttn.lorawan.v3.TxRequest.rx2_data_rate:type_name -> ttn.lorawan.v3.DataRate 10, // 34: ttn.lorawan.v3.TxRequest.priority:type_name -> ttn.lorawan.v3.TxSchedulePriority - 86, // 35: ttn.lorawan.v3.TxRequest.absolute_time:type_name -> google.protobuf.Timestamp - 85, // 36: ttn.lorawan.v3.TxRequest.advanced:type_name -> google.protobuf.Struct - 11, // 37: ttn.lorawan.v3.MACCommand.cid:type_name -> ttn.lorawan.v3.MACCommandIdentifier - 55, // 38: ttn.lorawan.v3.MACCommand.reset_ind:type_name -> ttn.lorawan.v3.MACCommand.ResetInd - 56, // 39: ttn.lorawan.v3.MACCommand.reset_conf:type_name -> ttn.lorawan.v3.MACCommand.ResetConf - 57, // 40: ttn.lorawan.v3.MACCommand.link_check_ans:type_name -> ttn.lorawan.v3.MACCommand.LinkCheckAns - 58, // 41: ttn.lorawan.v3.MACCommand.link_adr_req:type_name -> ttn.lorawan.v3.MACCommand.LinkADRReq - 59, // 42: ttn.lorawan.v3.MACCommand.link_adr_ans:type_name -> ttn.lorawan.v3.MACCommand.LinkADRAns - 60, // 43: ttn.lorawan.v3.MACCommand.duty_cycle_req:type_name -> ttn.lorawan.v3.MACCommand.DutyCycleReq - 61, // 44: ttn.lorawan.v3.MACCommand.rx_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RxParamSetupReq - 62, // 45: ttn.lorawan.v3.MACCommand.rx_param_setup_ans:type_name -> ttn.lorawan.v3.MACCommand.RxParamSetupAns - 63, // 46: ttn.lorawan.v3.MACCommand.dev_status_ans:type_name -> ttn.lorawan.v3.MACCommand.DevStatusAns - 64, // 47: ttn.lorawan.v3.MACCommand.new_channel_req:type_name -> ttn.lorawan.v3.MACCommand.NewChannelReq - 65, // 48: ttn.lorawan.v3.MACCommand.new_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.NewChannelAns - 66, // 49: ttn.lorawan.v3.MACCommand.dl_channel_req:type_name -> ttn.lorawan.v3.MACCommand.DLChannelReq - 67, // 50: ttn.lorawan.v3.MACCommand.dl_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.DLChannelAns - 68, // 51: ttn.lorawan.v3.MACCommand.rx_timing_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RxTimingSetupReq - 69, // 52: ttn.lorawan.v3.MACCommand.tx_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.TxParamSetupReq - 70, // 53: ttn.lorawan.v3.MACCommand.rekey_ind:type_name -> ttn.lorawan.v3.MACCommand.RekeyInd - 71, // 54: ttn.lorawan.v3.MACCommand.rekey_conf:type_name -> ttn.lorawan.v3.MACCommand.RekeyConf - 72, // 55: ttn.lorawan.v3.MACCommand.adr_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.ADRParamSetupReq - 73, // 56: ttn.lorawan.v3.MACCommand.device_time_ans:type_name -> ttn.lorawan.v3.MACCommand.DeviceTimeAns - 74, // 57: ttn.lorawan.v3.MACCommand.force_rejoin_req:type_name -> ttn.lorawan.v3.MACCommand.ForceRejoinReq - 75, // 58: ttn.lorawan.v3.MACCommand.rejoin_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RejoinParamSetupReq - 76, // 59: ttn.lorawan.v3.MACCommand.rejoin_param_setup_ans:type_name -> ttn.lorawan.v3.MACCommand.RejoinParamSetupAns - 77, // 60: ttn.lorawan.v3.MACCommand.ping_slot_info_req:type_name -> ttn.lorawan.v3.MACCommand.PingSlotInfoReq - 78, // 61: ttn.lorawan.v3.MACCommand.ping_slot_channel_req:type_name -> ttn.lorawan.v3.MACCommand.PingSlotChannelReq - 79, // 62: ttn.lorawan.v3.MACCommand.ping_slot_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.PingSlotChannelAns - 80, // 63: ttn.lorawan.v3.MACCommand.beacon_timing_ans:type_name -> ttn.lorawan.v3.MACCommand.BeaconTimingAns - 81, // 64: ttn.lorawan.v3.MACCommand.beacon_freq_req:type_name -> ttn.lorawan.v3.MACCommand.BeaconFreqReq - 82, // 65: ttn.lorawan.v3.MACCommand.beacon_freq_ans:type_name -> ttn.lorawan.v3.MACCommand.BeaconFreqAns - 83, // 66: ttn.lorawan.v3.MACCommand.device_mode_ind:type_name -> ttn.lorawan.v3.MACCommand.DeviceModeInd - 84, // 67: ttn.lorawan.v3.MACCommand.device_mode_conf:type_name -> ttn.lorawan.v3.MACCommand.DeviceModeConf - 42, // 68: ttn.lorawan.v3.MACCommands.commands:type_name -> ttn.lorawan.v3.MACCommand - 5, // 69: ttn.lorawan.v3.DataRateOffsetValue.value:type_name -> ttn.lorawan.v3.DataRateOffset - 4, // 70: ttn.lorawan.v3.DataRateIndexValue.value:type_name -> ttn.lorawan.v3.DataRateIndex - 13, // 71: ttn.lorawan.v3.PingSlotPeriodValue.value:type_name -> ttn.lorawan.v3.PingSlotPeriod - 12, // 72: ttn.lorawan.v3.AggregatedDutyCycleValue.value:type_name -> ttn.lorawan.v3.AggregatedDutyCycle - 20, // 73: ttn.lorawan.v3.RxDelayValue.value:type_name -> ttn.lorawan.v3.RxDelay - 18, // 74: ttn.lorawan.v3.ADRAckLimitExponentValue.value:type_name -> ttn.lorawan.v3.ADRAckLimitExponent - 19, // 75: ttn.lorawan.v3.ADRAckDelayExponentValue.value:type_name -> ttn.lorawan.v3.ADRAckDelayExponent - 17, // 76: ttn.lorawan.v3.DeviceEIRPValue.value:type_name -> ttn.lorawan.v3.DeviceEIRP - 21, // 77: ttn.lorawan.v3.MACCommand.ResetInd.minor_version:type_name -> ttn.lorawan.v3.Minor - 21, // 78: ttn.lorawan.v3.MACCommand.ResetConf.minor_version:type_name -> ttn.lorawan.v3.Minor - 4, // 79: ttn.lorawan.v3.MACCommand.LinkADRReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 12, // 80: ttn.lorawan.v3.MACCommand.DutyCycleReq.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycle - 4, // 81: ttn.lorawan.v3.MACCommand.RxParamSetupReq.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 5, // 82: ttn.lorawan.v3.MACCommand.RxParamSetupReq.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffset - 4, // 83: ttn.lorawan.v3.MACCommand.NewChannelReq.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 4, // 84: ttn.lorawan.v3.MACCommand.NewChannelReq.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 20, // 85: ttn.lorawan.v3.MACCommand.RxTimingSetupReq.delay:type_name -> ttn.lorawan.v3.RxDelay - 17, // 86: ttn.lorawan.v3.MACCommand.TxParamSetupReq.max_eirp_index:type_name -> ttn.lorawan.v3.DeviceEIRP - 21, // 87: ttn.lorawan.v3.MACCommand.RekeyInd.minor_version:type_name -> ttn.lorawan.v3.Minor - 21, // 88: ttn.lorawan.v3.MACCommand.RekeyConf.minor_version:type_name -> ttn.lorawan.v3.Minor - 18, // 89: ttn.lorawan.v3.MACCommand.ADRParamSetupReq.adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponent - 19, // 90: ttn.lorawan.v3.MACCommand.ADRParamSetupReq.adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponent - 86, // 91: ttn.lorawan.v3.MACCommand.DeviceTimeAns.time:type_name -> google.protobuf.Timestamp - 7, // 92: ttn.lorawan.v3.MACCommand.ForceRejoinReq.rejoin_type:type_name -> ttn.lorawan.v3.RejoinRequestType - 4, // 93: ttn.lorawan.v3.MACCommand.ForceRejoinReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 16, // 94: ttn.lorawan.v3.MACCommand.ForceRejoinReq.period_exponent:type_name -> ttn.lorawan.v3.RejoinPeriodExponent - 14, // 95: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq.max_count_exponent:type_name -> ttn.lorawan.v3.RejoinCountExponent - 15, // 96: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq.max_time_exponent:type_name -> ttn.lorawan.v3.RejoinTimeExponent - 13, // 97: ttn.lorawan.v3.MACCommand.PingSlotInfoReq.period:type_name -> ttn.lorawan.v3.PingSlotPeriod - 4, // 98: ttn.lorawan.v3.MACCommand.PingSlotChannelReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex - 9, // 99: ttn.lorawan.v3.MACCommand.DeviceModeInd.class:type_name -> ttn.lorawan.v3.Class - 9, // 100: ttn.lorawan.v3.MACCommand.DeviceModeConf.class:type_name -> ttn.lorawan.v3.Class - 101, // [101:101] is the sub-list for method output_type - 101, // [101:101] is the sub-list for method input_type - 101, // [101:101] is the sub-list for extension type_name - 101, // [101:101] is the sub-list for extension extendee - 0, // [0:101] is the sub-list for field type_name + 115, // 35: ttn.lorawan.v3.TxRequest.absolute_time:type_name -> google.protobuf.Timestamp + 114, // 36: ttn.lorawan.v3.TxRequest.advanced:type_name -> google.protobuf.Struct + 13, // 37: ttn.lorawan.v3.RelaySecondChannel.ack_offset:type_name -> ttn.lorawan.v3.RelaySecondChAckOffset + 4, // 38: ttn.lorawan.v3.RelaySecondChannel.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 14, // 39: ttn.lorawan.v3.RelayUplinkForwardLimits.bucket_size:type_name -> ttn.lorawan.v3.RelayLimitBucketSize + 14, // 40: ttn.lorawan.v3.RelayForwardLimits.bucket_size:type_name -> ttn.lorawan.v3.RelayLimitBucketSize + 15, // 41: ttn.lorawan.v3.RelayEndDeviceDynamicMode.smart_enable_level:type_name -> ttn.lorawan.v3.RelaySmartEnableLevel + 11, // 42: ttn.lorawan.v3.MACCommand.cid:type_name -> ttn.lorawan.v3.MACCommandIdentifier + 71, // 43: ttn.lorawan.v3.MACCommand.reset_ind:type_name -> ttn.lorawan.v3.MACCommand.ResetInd + 72, // 44: ttn.lorawan.v3.MACCommand.reset_conf:type_name -> ttn.lorawan.v3.MACCommand.ResetConf + 73, // 45: ttn.lorawan.v3.MACCommand.link_check_ans:type_name -> ttn.lorawan.v3.MACCommand.LinkCheckAns + 74, // 46: ttn.lorawan.v3.MACCommand.link_adr_req:type_name -> ttn.lorawan.v3.MACCommand.LinkADRReq + 75, // 47: ttn.lorawan.v3.MACCommand.link_adr_ans:type_name -> ttn.lorawan.v3.MACCommand.LinkADRAns + 76, // 48: ttn.lorawan.v3.MACCommand.duty_cycle_req:type_name -> ttn.lorawan.v3.MACCommand.DutyCycleReq + 77, // 49: ttn.lorawan.v3.MACCommand.rx_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RxParamSetupReq + 78, // 50: ttn.lorawan.v3.MACCommand.rx_param_setup_ans:type_name -> ttn.lorawan.v3.MACCommand.RxParamSetupAns + 79, // 51: ttn.lorawan.v3.MACCommand.dev_status_ans:type_name -> ttn.lorawan.v3.MACCommand.DevStatusAns + 80, // 52: ttn.lorawan.v3.MACCommand.new_channel_req:type_name -> ttn.lorawan.v3.MACCommand.NewChannelReq + 81, // 53: ttn.lorawan.v3.MACCommand.new_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.NewChannelAns + 82, // 54: ttn.lorawan.v3.MACCommand.dl_channel_req:type_name -> ttn.lorawan.v3.MACCommand.DLChannelReq + 83, // 55: ttn.lorawan.v3.MACCommand.dl_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.DLChannelAns + 84, // 56: ttn.lorawan.v3.MACCommand.rx_timing_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RxTimingSetupReq + 85, // 57: ttn.lorawan.v3.MACCommand.tx_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.TxParamSetupReq + 86, // 58: ttn.lorawan.v3.MACCommand.rekey_ind:type_name -> ttn.lorawan.v3.MACCommand.RekeyInd + 87, // 59: ttn.lorawan.v3.MACCommand.rekey_conf:type_name -> ttn.lorawan.v3.MACCommand.RekeyConf + 88, // 60: ttn.lorawan.v3.MACCommand.adr_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.ADRParamSetupReq + 89, // 61: ttn.lorawan.v3.MACCommand.device_time_ans:type_name -> ttn.lorawan.v3.MACCommand.DeviceTimeAns + 90, // 62: ttn.lorawan.v3.MACCommand.force_rejoin_req:type_name -> ttn.lorawan.v3.MACCommand.ForceRejoinReq + 91, // 63: ttn.lorawan.v3.MACCommand.rejoin_param_setup_req:type_name -> ttn.lorawan.v3.MACCommand.RejoinParamSetupReq + 92, // 64: ttn.lorawan.v3.MACCommand.rejoin_param_setup_ans:type_name -> ttn.lorawan.v3.MACCommand.RejoinParamSetupAns + 93, // 65: ttn.lorawan.v3.MACCommand.ping_slot_info_req:type_name -> ttn.lorawan.v3.MACCommand.PingSlotInfoReq + 94, // 66: ttn.lorawan.v3.MACCommand.ping_slot_channel_req:type_name -> ttn.lorawan.v3.MACCommand.PingSlotChannelReq + 95, // 67: ttn.lorawan.v3.MACCommand.ping_slot_channel_ans:type_name -> ttn.lorawan.v3.MACCommand.PingSlotChannelAns + 96, // 68: ttn.lorawan.v3.MACCommand.beacon_timing_ans:type_name -> ttn.lorawan.v3.MACCommand.BeaconTimingAns + 97, // 69: ttn.lorawan.v3.MACCommand.beacon_freq_req:type_name -> ttn.lorawan.v3.MACCommand.BeaconFreqReq + 98, // 70: ttn.lorawan.v3.MACCommand.beacon_freq_ans:type_name -> ttn.lorawan.v3.MACCommand.BeaconFreqAns + 99, // 71: ttn.lorawan.v3.MACCommand.device_mode_ind:type_name -> ttn.lorawan.v3.MACCommand.DeviceModeInd + 100, // 72: ttn.lorawan.v3.MACCommand.device_mode_conf:type_name -> ttn.lorawan.v3.MACCommand.DeviceModeConf + 101, // 73: ttn.lorawan.v3.MACCommand.relay_conf_req:type_name -> ttn.lorawan.v3.MACCommand.RelayConfReq + 102, // 74: ttn.lorawan.v3.MACCommand.relay_conf_ans:type_name -> ttn.lorawan.v3.MACCommand.RelayConfAns + 103, // 75: ttn.lorawan.v3.MACCommand.relay_end_device_conf_req:type_name -> ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq + 104, // 76: ttn.lorawan.v3.MACCommand.relay_end_device_conf_ans:type_name -> ttn.lorawan.v3.MACCommand.RelayEndDeviceConfAns + 105, // 77: ttn.lorawan.v3.MACCommand.relay_update_uplink_list_req:type_name -> ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListReq + 106, // 78: ttn.lorawan.v3.MACCommand.relay_update_uplink_list_ans:type_name -> ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListAns + 107, // 79: ttn.lorawan.v3.MACCommand.relay_ctrl_uplink_list_req:type_name -> ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListReq + 108, // 80: ttn.lorawan.v3.MACCommand.relay_ctrl_uplink_list_ans:type_name -> ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListAns + 109, // 81: ttn.lorawan.v3.MACCommand.relay_configure_fwd_limit_req:type_name -> ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq + 110, // 82: ttn.lorawan.v3.MACCommand.relay_configure_fwd_limit_ans:type_name -> ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitAns + 111, // 83: ttn.lorawan.v3.MACCommand.relay_notify_new_end_device_req:type_name -> ttn.lorawan.v3.MACCommand.RelayNotifyNewEndDeviceReq + 55, // 84: ttn.lorawan.v3.MACCommands.commands:type_name -> ttn.lorawan.v3.MACCommand + 5, // 85: ttn.lorawan.v3.DataRateOffsetValue.value:type_name -> ttn.lorawan.v3.DataRateOffset + 4, // 86: ttn.lorawan.v3.DataRateIndexValue.value:type_name -> ttn.lorawan.v3.DataRateIndex + 20, // 87: ttn.lorawan.v3.PingSlotPeriodValue.value:type_name -> ttn.lorawan.v3.PingSlotPeriod + 19, // 88: ttn.lorawan.v3.AggregatedDutyCycleValue.value:type_name -> ttn.lorawan.v3.AggregatedDutyCycle + 27, // 89: ttn.lorawan.v3.RxDelayValue.value:type_name -> ttn.lorawan.v3.RxDelay + 25, // 90: ttn.lorawan.v3.ADRAckLimitExponentValue.value:type_name -> ttn.lorawan.v3.ADRAckLimitExponent + 26, // 91: ttn.lorawan.v3.ADRAckDelayExponentValue.value:type_name -> ttn.lorawan.v3.ADRAckDelayExponent + 24, // 92: ttn.lorawan.v3.DeviceEIRPValue.value:type_name -> ttn.lorawan.v3.DeviceEIRP + 42, // 93: ttn.lorawan.v3.RelayForwardUplinkReq.data_rate:type_name -> ttn.lorawan.v3.DataRate + 16, // 94: ttn.lorawan.v3.RelayForwardUplinkReq.wor_channel:type_name -> ttn.lorawan.v3.RelayWORChannel + 117, // 95: ttn.lorawan.v3.RelayUplinkToken.ids:type_name -> ttn.lorawan.v3.EndDeviceIdentifiers + 28, // 96: ttn.lorawan.v3.MACCommand.ResetInd.minor_version:type_name -> ttn.lorawan.v3.Minor + 28, // 97: ttn.lorawan.v3.MACCommand.ResetConf.minor_version:type_name -> ttn.lorawan.v3.Minor + 4, // 98: ttn.lorawan.v3.MACCommand.LinkADRReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 19, // 99: ttn.lorawan.v3.MACCommand.DutyCycleReq.max_duty_cycle:type_name -> ttn.lorawan.v3.AggregatedDutyCycle + 4, // 100: ttn.lorawan.v3.MACCommand.RxParamSetupReq.rx2_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 5, // 101: ttn.lorawan.v3.MACCommand.RxParamSetupReq.rx1_data_rate_offset:type_name -> ttn.lorawan.v3.DataRateOffset + 4, // 102: ttn.lorawan.v3.MACCommand.NewChannelReq.min_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 4, // 103: ttn.lorawan.v3.MACCommand.NewChannelReq.max_data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 27, // 104: ttn.lorawan.v3.MACCommand.RxTimingSetupReq.delay:type_name -> ttn.lorawan.v3.RxDelay + 24, // 105: ttn.lorawan.v3.MACCommand.TxParamSetupReq.max_eirp_index:type_name -> ttn.lorawan.v3.DeviceEIRP + 28, // 106: ttn.lorawan.v3.MACCommand.RekeyInd.minor_version:type_name -> ttn.lorawan.v3.Minor + 28, // 107: ttn.lorawan.v3.MACCommand.RekeyConf.minor_version:type_name -> ttn.lorawan.v3.Minor + 25, // 108: ttn.lorawan.v3.MACCommand.ADRParamSetupReq.adr_ack_limit_exponent:type_name -> ttn.lorawan.v3.ADRAckLimitExponent + 26, // 109: ttn.lorawan.v3.MACCommand.ADRParamSetupReq.adr_ack_delay_exponent:type_name -> ttn.lorawan.v3.ADRAckDelayExponent + 115, // 110: ttn.lorawan.v3.MACCommand.DeviceTimeAns.time:type_name -> google.protobuf.Timestamp + 7, // 111: ttn.lorawan.v3.MACCommand.ForceRejoinReq.rejoin_type:type_name -> ttn.lorawan.v3.RejoinRequestType + 4, // 112: ttn.lorawan.v3.MACCommand.ForceRejoinReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 23, // 113: ttn.lorawan.v3.MACCommand.ForceRejoinReq.period_exponent:type_name -> ttn.lorawan.v3.RejoinPeriodExponent + 21, // 114: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq.max_count_exponent:type_name -> ttn.lorawan.v3.RejoinCountExponent + 22, // 115: ttn.lorawan.v3.MACCommand.RejoinParamSetupReq.max_time_exponent:type_name -> ttn.lorawan.v3.RejoinTimeExponent + 20, // 116: ttn.lorawan.v3.MACCommand.PingSlotInfoReq.period:type_name -> ttn.lorawan.v3.PingSlotPeriod + 4, // 117: ttn.lorawan.v3.MACCommand.PingSlotChannelReq.data_rate_index:type_name -> ttn.lorawan.v3.DataRateIndex + 9, // 118: ttn.lorawan.v3.MACCommand.DeviceModeInd.class:type_name -> ttn.lorawan.v3.Class + 9, // 119: ttn.lorawan.v3.MACCommand.DeviceModeConf.class:type_name -> ttn.lorawan.v3.Class + 112, // 120: ttn.lorawan.v3.MACCommand.RelayConfReq.configuration:type_name -> ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration + 113, // 121: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.configuration:type_name -> ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration + 50, // 122: ttn.lorawan.v3.MACCommand.RelayUpdateUplinkListReq.forward_limits:type_name -> ttn.lorawan.v3.RelayUplinkForwardLimits + 18, // 123: ttn.lorawan.v3.MACCommand.RelayCtrlUplinkListReq.action:type_name -> ttn.lorawan.v3.RelayCtrlUplinkListAction + 17, // 124: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq.reset_limit_counter:type_name -> ttn.lorawan.v3.RelayResetLimitCounter + 51, // 125: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq.join_request_limits:type_name -> ttn.lorawan.v3.RelayForwardLimits + 51, // 126: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq.notify_limits:type_name -> ttn.lorawan.v3.RelayForwardLimits + 51, // 127: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq.global_uplink_limits:type_name -> ttn.lorawan.v3.RelayForwardLimits + 51, // 128: ttn.lorawan.v3.MACCommand.RelayConfigureFwdLimitReq.overall_limits:type_name -> ttn.lorawan.v3.RelayForwardLimits + 49, // 129: ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration.second_channel:type_name -> ttn.lorawan.v3.RelaySecondChannel + 12, // 130: ttn.lorawan.v3.MACCommand.RelayConfReq.Configuration.cad_periodicity:type_name -> ttn.lorawan.v3.RelayCADPeriodicity + 52, // 131: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration.always:type_name -> ttn.lorawan.v3.RelayEndDeviceAlwaysMode + 53, // 132: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration.dynamic:type_name -> ttn.lorawan.v3.RelayEndDeviceDynamicMode + 54, // 133: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration.end_device_controlled:type_name -> ttn.lorawan.v3.RelayEndDeviceControlledMode + 49, // 134: ttn.lorawan.v3.MACCommand.RelayEndDeviceConfReq.Configuration.second_channel:type_name -> ttn.lorawan.v3.RelaySecondChannel + 135, // [135:135] is the sub-list for method output_type + 135, // [135:135] is the sub-list for method input_type + 135, // [135:135] is the sub-list for extension type_name + 135, // [135:135] is the sub-list for extension extendee + 0, // [0:135] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_lorawan_proto_init() } @@ -7597,8 +10074,224 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MHDR); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MHDR); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACPayload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FHDR); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FCtrl); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinRequestPayload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RejoinRequestPayload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*JoinAcceptPayload); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DLSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CFList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoRaDataRate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FSKDataRate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LRFHSSDataRate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataRate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TxSettings); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GatewayAntennaIdentifiers); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClassBCGatewayIdentifiers); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UplinkToken); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DownlinkPath); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TxRequest); i { case 0: return &v.state case 1: @@ -7609,8 +10302,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACPayload); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelaySecondChannel); i { case 0: return &v.state case 1: @@ -7621,8 +10314,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FHDR); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayUplinkForwardLimits); i { case 0: return &v.state case 1: @@ -7633,8 +10326,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FCtrl); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayForwardLimits); i { case 0: return &v.state case 1: @@ -7645,8 +10338,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JoinRequestPayload); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayEndDeviceAlwaysMode); i { case 0: return &v.state case 1: @@ -7657,8 +10350,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RejoinRequestPayload); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayEndDeviceDynamicMode); i { case 0: return &v.state case 1: @@ -7669,8 +10362,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JoinAcceptPayload); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayEndDeviceControlledMode); i { case 0: return &v.state case 1: @@ -7681,8 +10374,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DLSettings); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand); i { case 0: return &v.state case 1: @@ -7693,8 +10386,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CFList); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommands); i { case 0: return &v.state case 1: @@ -7705,8 +10398,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoRaDataRate); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FrequencyValue); i { case 0: return &v.state case 1: @@ -7717,8 +10410,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FSKDataRate); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ZeroableFrequencyValue); i { case 0: return &v.state case 1: @@ -7729,8 +10422,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LRFHSSDataRate); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataRateOffsetValue); i { case 0: return &v.state case 1: @@ -7741,8 +10434,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataRate); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataRateIndexValue); i { case 0: return &v.state case 1: @@ -7753,8 +10446,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TxSettings); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PingSlotPeriodValue); i { case 0: return &v.state case 1: @@ -7765,8 +10458,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GatewayAntennaIdentifiers); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AggregatedDutyCycleValue); i { case 0: return &v.state case 1: @@ -7777,8 +10470,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ClassBCGatewayIdentifiers); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RxDelayValue); i { case 0: return &v.state case 1: @@ -7789,8 +10482,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UplinkToken); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ADRAckLimitExponentValue); i { case 0: return &v.state case 1: @@ -7801,8 +10494,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DownlinkPath); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ADRAckDelayExponentValue); i { case 0: return &v.state case 1: @@ -7813,8 +10506,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TxRequest); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceEIRPValue); i { case 0: return &v.state case 1: @@ -7825,8 +10518,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayForwardUplinkReq); i { case 0: return &v.state case 1: @@ -7837,8 +10530,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommands); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayForwardDownlinkReq); i { case 0: return &v.state case 1: @@ -7849,8 +10542,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FrequencyValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayUplinkToken); i { case 0: return &v.state case 1: @@ -7861,8 +10554,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ZeroableFrequencyValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TxSettings_Downlink); i { case 0: return &v.state case 1: @@ -7873,8 +10566,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataRateOffsetValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_ResetInd); i { case 0: return &v.state case 1: @@ -7885,8 +10578,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataRateIndexValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_ResetConf); i { case 0: return &v.state case 1: @@ -7897,8 +10590,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PingSlotPeriodValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_LinkCheckAns); i { case 0: return &v.state case 1: @@ -7909,8 +10602,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*AggregatedDutyCycleValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_LinkADRReq); i { case 0: return &v.state case 1: @@ -7921,8 +10614,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RxDelayValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_LinkADRAns); i { case 0: return &v.state case 1: @@ -7933,8 +10626,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRAckLimitExponentValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DutyCycleReq); i { case 0: return &v.state case 1: @@ -7945,8 +10638,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ADRAckDelayExponentValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RxParamSetupReq); i { case 0: return &v.state case 1: @@ -7957,8 +10650,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeviceEIRPValue); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RxParamSetupAns); i { case 0: return &v.state case 1: @@ -7969,8 +10662,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TxSettings_Downlink); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DevStatusAns); i { case 0: return &v.state case 1: @@ -7981,8 +10674,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_ResetInd); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_NewChannelReq); i { case 0: return &v.state case 1: @@ -7993,8 +10686,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_ResetConf); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_NewChannelAns); i { case 0: return &v.state case 1: @@ -8005,8 +10698,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_LinkCheckAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DLChannelReq); i { case 0: return &v.state case 1: @@ -8017,8 +10710,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_LinkADRReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DLChannelAns); i { case 0: return &v.state case 1: @@ -8029,8 +10722,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_LinkADRAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RxTimingSetupReq); i { case 0: return &v.state case 1: @@ -8041,8 +10734,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DutyCycleReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_TxParamSetupReq); i { case 0: return &v.state case 1: @@ -8053,8 +10746,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RxParamSetupReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RekeyInd); i { case 0: return &v.state case 1: @@ -8065,8 +10758,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RxParamSetupAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RekeyConf); i { case 0: return &v.state case 1: @@ -8077,8 +10770,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DevStatusAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_ADRParamSetupReq); i { case 0: return &v.state case 1: @@ -8089,8 +10782,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_NewChannelReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DeviceTimeAns); i { case 0: return &v.state case 1: @@ -8101,8 +10794,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_NewChannelAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_ForceRejoinReq); i { case 0: return &v.state case 1: @@ -8113,8 +10806,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DLChannelReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RejoinParamSetupReq); i { case 0: return &v.state case 1: @@ -8125,8 +10818,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DLChannelAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[63].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RejoinParamSetupAns); i { case 0: return &v.state case 1: @@ -8137,8 +10830,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RxTimingSetupReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[64].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_PingSlotInfoReq); i { case 0: return &v.state case 1: @@ -8149,8 +10842,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_TxParamSetupReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[65].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_PingSlotChannelReq); i { case 0: return &v.state case 1: @@ -8161,8 +10854,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RekeyInd); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[66].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_PingSlotChannelAns); i { case 0: return &v.state case 1: @@ -8173,8 +10866,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RekeyConf); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[67].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_BeaconTimingAns); i { case 0: return &v.state case 1: @@ -8185,8 +10878,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[50].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_ADRParamSetupReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[68].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_BeaconFreqReq); i { case 0: return &v.state case 1: @@ -8197,8 +10890,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[51].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DeviceTimeAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[69].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_BeaconFreqAns); i { case 0: return &v.state case 1: @@ -8209,8 +10902,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[52].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_ForceRejoinReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[70].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DeviceModeInd); i { case 0: return &v.state case 1: @@ -8221,8 +10914,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[53].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RejoinParamSetupReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[71].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_DeviceModeConf); i { case 0: return &v.state case 1: @@ -8233,8 +10926,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[54].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_RejoinParamSetupAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[72].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayConfReq); i { case 0: return &v.state case 1: @@ -8245,8 +10938,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[55].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_PingSlotInfoReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[73].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayConfAns); i { case 0: return &v.state case 1: @@ -8257,8 +10950,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[56].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_PingSlotChannelReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[74].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayEndDeviceConfReq); i { case 0: return &v.state case 1: @@ -8269,8 +10962,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[57].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_PingSlotChannelAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[75].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayEndDeviceConfAns); i { case 0: return &v.state case 1: @@ -8281,8 +10974,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[58].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_BeaconTimingAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[76].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayUpdateUplinkListReq); i { case 0: return &v.state case 1: @@ -8293,8 +10986,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[59].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_BeaconFreqReq); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[77].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayUpdateUplinkListAns); i { case 0: return &v.state case 1: @@ -8305,8 +10998,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[60].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_BeaconFreqAns); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[78].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayCtrlUplinkListReq); i { case 0: return &v.state case 1: @@ -8317,8 +11010,8 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[61].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DeviceModeInd); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[79].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayCtrlUplinkListAns); i { case 0: return &v.state case 1: @@ -8329,8 +11022,56 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { return nil } } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[62].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MACCommand_DeviceModeConf); i { + file_ttn_lorawan_v3_lorawan_proto_msgTypes[80].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayConfigureFwdLimitReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[81].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayConfigureFwdLimitAns); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[82].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayNotifyNewEndDeviceReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[83].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayConfReq_Configuration); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[84].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MACCommand_RelayEndDeviceConfReq_Configuration); i { case 0: return &v.state case 1: @@ -8357,7 +11098,7 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { (*DownlinkPath_UplinkToken)(nil), (*DownlinkPath_Fixed)(nil), } - file_ttn_lorawan_v3_lorawan_proto_msgTypes[20].OneofWrappers = []interface{}{ + file_ttn_lorawan_v3_lorawan_proto_msgTypes[26].OneofWrappers = []interface{}{ (*MACCommand_RawPayload)(nil), (*MACCommand_ResetInd_)(nil), (*MACCommand_ResetConf_)(nil), @@ -8389,14 +11130,30 @@ func file_ttn_lorawan_v3_lorawan_proto_init() { (*MACCommand_BeaconFreqAns_)(nil), (*MACCommand_DeviceModeInd_)(nil), (*MACCommand_DeviceModeConf_)(nil), + (*MACCommand_RelayConfReq_)(nil), + (*MACCommand_RelayConfAns_)(nil), + (*MACCommand_RelayEndDeviceConfReq_)(nil), + (*MACCommand_RelayEndDeviceConfAns_)(nil), + (*MACCommand_RelayUpdateUplinkListReq_)(nil), + (*MACCommand_RelayUpdateUplinkListAns_)(nil), + (*MACCommand_RelayCtrlUplinkListReq_)(nil), + (*MACCommand_RelayCtrlUplinkListAns_)(nil), + (*MACCommand_RelayConfigureFwdLimitReq_)(nil), + (*MACCommand_RelayConfigureFwdLimitAns_)(nil), + (*MACCommand_RelayNotifyNewEndDeviceReq_)(nil), + } + file_ttn_lorawan_v3_lorawan_proto_msgTypes[84].OneofWrappers = []interface{}{ + (*MACCommand_RelayEndDeviceConfReq_Configuration_Always)(nil), + (*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic)(nil), + (*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ttn_lorawan_v3_lorawan_proto_rawDesc, - NumEnums: 22, - NumMessages: 63, + NumEnums: 29, + NumMessages: 85, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/ttnpb/lorawan.pb.paths.fm.go b/pkg/ttnpb/lorawan.pb.paths.fm.go index 477846bc13..ca77ac871e 100644 --- a/pkg/ttnpb/lorawan.pb.paths.fm.go +++ b/pkg/ttnpb/lorawan.pb.paths.fm.go @@ -377,6 +377,46 @@ var TxRequestFieldPathsTopLevel = []string{ "rx2_data_rate", "rx2_frequency", } +var RelaySecondChannelFieldPathsNested = []string{ + "ack_offset", + "data_rate_index", + "frequency", +} + +var RelaySecondChannelFieldPathsTopLevel = []string{ + "ack_offset", + "data_rate_index", + "frequency", +} +var RelayUplinkForwardLimitsFieldPathsNested = []string{ + "bucket_size", + "reload_rate", +} + +var RelayUplinkForwardLimitsFieldPathsTopLevel = []string{ + "bucket_size", + "reload_rate", +} +var RelayForwardLimitsFieldPathsNested = []string{ + "bucket_size", + "reload_rate", +} + +var RelayForwardLimitsFieldPathsTopLevel = []string{ + "bucket_size", + "reload_rate", +} +var RelayEndDeviceAlwaysModeFieldPathsNested []string +var RelayEndDeviceAlwaysModeFieldPathsTopLevel []string +var RelayEndDeviceDynamicModeFieldPathsNested = []string{ + "smart_enable_level", +} + +var RelayEndDeviceDynamicModeFieldPathsTopLevel = []string{ + "smart_enable_level", +} +var RelayEndDeviceControlledModeFieldPathsNested []string +var RelayEndDeviceControlledModeFieldPathsTopLevel []string var MACCommandFieldPathsNested = []string{ "cid", "payload", @@ -451,6 +491,75 @@ var MACCommandFieldPathsNested = []string{ "payload.rekey_conf.minor_version", "payload.rekey_ind", "payload.rekey_ind.minor_version", + "payload.relay_conf_ans", + "payload.relay_conf_ans.cad_periodicity_ack", + "payload.relay_conf_ans.default_channel_index_ack", + "payload.relay_conf_ans.second_channel_ack_offset_ack", + "payload.relay_conf_ans.second_channel_data_rate_index_ack", + "payload.relay_conf_ans.second_channel_frequency_ack", + "payload.relay_conf_ans.second_channel_index_ack", + "payload.relay_conf_req", + "payload.relay_conf_req.configuration", + "payload.relay_conf_req.configuration.cad_periodicity", + "payload.relay_conf_req.configuration.default_channel_index", + "payload.relay_conf_req.configuration.second_channel", + "payload.relay_conf_req.configuration.second_channel.ack_offset", + "payload.relay_conf_req.configuration.second_channel.data_rate_index", + "payload.relay_conf_req.configuration.second_channel.frequency", + "payload.relay_configure_fwd_limit_ans", + "payload.relay_configure_fwd_limit_req", + "payload.relay_configure_fwd_limit_req.global_uplink_limits", + "payload.relay_configure_fwd_limit_req.global_uplink_limits.bucket_size", + "payload.relay_configure_fwd_limit_req.global_uplink_limits.reload_rate", + "payload.relay_configure_fwd_limit_req.join_request_limits", + "payload.relay_configure_fwd_limit_req.join_request_limits.bucket_size", + "payload.relay_configure_fwd_limit_req.join_request_limits.reload_rate", + "payload.relay_configure_fwd_limit_req.notify_limits", + "payload.relay_configure_fwd_limit_req.notify_limits.bucket_size", + "payload.relay_configure_fwd_limit_req.notify_limits.reload_rate", + "payload.relay_configure_fwd_limit_req.overall_limits", + "payload.relay_configure_fwd_limit_req.overall_limits.bucket_size", + "payload.relay_configure_fwd_limit_req.overall_limits.reload_rate", + "payload.relay_configure_fwd_limit_req.reset_limit_counter", + "payload.relay_ctrl_uplink_list_ans", + "payload.relay_ctrl_uplink_list_ans.rule_index_ack", + "payload.relay_ctrl_uplink_list_ans.w_f_cnt", + "payload.relay_ctrl_uplink_list_req", + "payload.relay_ctrl_uplink_list_req.action", + "payload.relay_ctrl_uplink_list_req.rule_index", + "payload.relay_end_device_conf_ans", + "payload.relay_end_device_conf_ans.backoff_ack", + "payload.relay_end_device_conf_ans.second_channel_data_rate_index_ack", + "payload.relay_end_device_conf_ans.second_channel_frequency_ack", + "payload.relay_end_device_conf_ans.second_channel_index_ack", + "payload.relay_end_device_conf_req", + "payload.relay_end_device_conf_req.configuration", + "payload.relay_end_device_conf_req.configuration.backoff", + "payload.relay_end_device_conf_req.configuration.mode", + "payload.relay_end_device_conf_req.configuration.mode.always", + "payload.relay_end_device_conf_req.configuration.mode.dynamic", + "payload.relay_end_device_conf_req.configuration.mode.dynamic.smart_enable_level", + "payload.relay_end_device_conf_req.configuration.mode.end_device_controlled", + "payload.relay_end_device_conf_req.configuration.second_channel", + "payload.relay_end_device_conf_req.configuration.second_channel.ack_offset", + "payload.relay_end_device_conf_req.configuration.second_channel.data_rate_index", + "payload.relay_end_device_conf_req.configuration.second_channel.frequency", + "payload.relay_end_device_conf_req.configuration.serving_device_id", + "payload.relay_notify_new_end_device_req", + "payload.relay_notify_new_end_device_req.dev_addr", + "payload.relay_notify_new_end_device_req.rssi", + "payload.relay_notify_new_end_device_req.snr", + "payload.relay_update_uplink_list_ans", + "payload.relay_update_uplink_list_req", + "payload.relay_update_uplink_list_req.dev_addr", + "payload.relay_update_uplink_list_req.device_id", + "payload.relay_update_uplink_list_req.forward_limits", + "payload.relay_update_uplink_list_req.forward_limits.bucket_size", + "payload.relay_update_uplink_list_req.forward_limits.reload_rate", + "payload.relay_update_uplink_list_req.root_wor_s_key", + "payload.relay_update_uplink_list_req.rule_index", + "payload.relay_update_uplink_list_req.session_key_id", + "payload.relay_update_uplink_list_req.w_f_cnt", "payload.reset_conf", "payload.reset_conf.minor_version", "payload.reset_ind", @@ -552,6 +661,58 @@ var DeviceEIRPValueFieldPathsNested = []string{ var DeviceEIRPValueFieldPathsTopLevel = []string{ "value", } +var RelayForwardUplinkReqFieldPathsNested = []string{ + "data_rate", + "data_rate.modulation", + "data_rate.modulation.fsk", + "data_rate.modulation.fsk.bit_rate", + "data_rate.modulation.lora", + "data_rate.modulation.lora.bandwidth", + "data_rate.modulation.lora.coding_rate", + "data_rate.modulation.lora.spreading_factor", + "data_rate.modulation.lrfhss", + "data_rate.modulation.lrfhss.coding_rate", + "data_rate.modulation.lrfhss.modulation_type", + "data_rate.modulation.lrfhss.operating_channel_width", + "frequency", + "raw_payload", + "rssi", + "snr", + "wor_channel", +} + +var RelayForwardUplinkReqFieldPathsTopLevel = []string{ + "data_rate", + "frequency", + "raw_payload", + "rssi", + "snr", + "wor_channel", +} +var RelayForwardDownlinkReqFieldPathsNested = []string{ + "raw_payload", +} + +var RelayForwardDownlinkReqFieldPathsTopLevel = []string{ + "raw_payload", +} +var RelayUplinkTokenFieldPathsNested = []string{ + "full_f_cnt", + "ids", + "ids.application_ids", + "ids.application_ids.application_id", + "ids.dev_addr", + "ids.dev_eui", + "ids.device_id", + "ids.join_eui", + "session_key_id", +} + +var RelayUplinkTokenFieldPathsTopLevel = []string{ + "full_f_cnt", + "ids", + "session_key_id", +} var TxSettings_DownlinkFieldPathsNested = []string{ "antenna_index", "invert_polarization", @@ -829,3 +990,175 @@ var MACCommand_DeviceModeConfFieldPathsNested = []string{ var MACCommand_DeviceModeConfFieldPathsTopLevel = []string{ "class", } +var MACCommand_RelayConfReqFieldPathsNested = []string{ + "configuration", + "configuration.cad_periodicity", + "configuration.default_channel_index", + "configuration.second_channel", + "configuration.second_channel.ack_offset", + "configuration.second_channel.data_rate_index", + "configuration.second_channel.frequency", +} + +var MACCommand_RelayConfReqFieldPathsTopLevel = []string{ + "configuration", +} +var MACCommand_RelayConfAnsFieldPathsNested = []string{ + "cad_periodicity_ack", + "default_channel_index_ack", + "second_channel_ack_offset_ack", + "second_channel_data_rate_index_ack", + "second_channel_frequency_ack", + "second_channel_index_ack", +} + +var MACCommand_RelayConfAnsFieldPathsTopLevel = []string{ + "cad_periodicity_ack", + "default_channel_index_ack", + "second_channel_ack_offset_ack", + "second_channel_data_rate_index_ack", + "second_channel_frequency_ack", + "second_channel_index_ack", +} +var MACCommand_RelayEndDeviceConfReqFieldPathsNested = []string{ + "configuration", + "configuration.backoff", + "configuration.mode", + "configuration.mode.always", + "configuration.mode.dynamic", + "configuration.mode.dynamic.smart_enable_level", + "configuration.mode.end_device_controlled", + "configuration.second_channel", + "configuration.second_channel.ack_offset", + "configuration.second_channel.data_rate_index", + "configuration.second_channel.frequency", + "configuration.serving_device_id", +} + +var MACCommand_RelayEndDeviceConfReqFieldPathsTopLevel = []string{ + "configuration", +} +var MACCommand_RelayEndDeviceConfAnsFieldPathsNested = []string{ + "backoff_ack", + "second_channel_data_rate_index_ack", + "second_channel_frequency_ack", + "second_channel_index_ack", +} + +var MACCommand_RelayEndDeviceConfAnsFieldPathsTopLevel = []string{ + "backoff_ack", + "second_channel_data_rate_index_ack", + "second_channel_frequency_ack", + "second_channel_index_ack", +} +var MACCommand_RelayUpdateUplinkListReqFieldPathsNested = []string{ + "dev_addr", + "device_id", + "forward_limits", + "forward_limits.bucket_size", + "forward_limits.reload_rate", + "root_wor_s_key", + "rule_index", + "session_key_id", + "w_f_cnt", +} + +var MACCommand_RelayUpdateUplinkListReqFieldPathsTopLevel = []string{ + "dev_addr", + "device_id", + "forward_limits", + "root_wor_s_key", + "rule_index", + "session_key_id", + "w_f_cnt", +} +var MACCommand_RelayUpdateUplinkListAnsFieldPathsNested []string +var MACCommand_RelayUpdateUplinkListAnsFieldPathsTopLevel []string +var MACCommand_RelayCtrlUplinkListReqFieldPathsNested = []string{ + "action", + "rule_index", +} + +var MACCommand_RelayCtrlUplinkListReqFieldPathsTopLevel = []string{ + "action", + "rule_index", +} +var MACCommand_RelayCtrlUplinkListAnsFieldPathsNested = []string{ + "rule_index_ack", + "w_f_cnt", +} + +var MACCommand_RelayCtrlUplinkListAnsFieldPathsTopLevel = []string{ + "rule_index_ack", + "w_f_cnt", +} +var MACCommand_RelayConfigureFwdLimitReqFieldPathsNested = []string{ + "global_uplink_limits", + "global_uplink_limits.bucket_size", + "global_uplink_limits.reload_rate", + "join_request_limits", + "join_request_limits.bucket_size", + "join_request_limits.reload_rate", + "notify_limits", + "notify_limits.bucket_size", + "notify_limits.reload_rate", + "overall_limits", + "overall_limits.bucket_size", + "overall_limits.reload_rate", + "reset_limit_counter", +} + +var MACCommand_RelayConfigureFwdLimitReqFieldPathsTopLevel = []string{ + "global_uplink_limits", + "join_request_limits", + "notify_limits", + "overall_limits", + "reset_limit_counter", +} +var MACCommand_RelayConfigureFwdLimitAnsFieldPathsNested []string +var MACCommand_RelayConfigureFwdLimitAnsFieldPathsTopLevel []string +var MACCommand_RelayNotifyNewEndDeviceReqFieldPathsNested = []string{ + "dev_addr", + "rssi", + "snr", +} + +var MACCommand_RelayNotifyNewEndDeviceReqFieldPathsTopLevel = []string{ + "dev_addr", + "rssi", + "snr", +} +var MACCommand_RelayConfReq_ConfigurationFieldPathsNested = []string{ + "cad_periodicity", + "default_channel_index", + "second_channel", + "second_channel.ack_offset", + "second_channel.data_rate_index", + "second_channel.frequency", +} + +var MACCommand_RelayConfReq_ConfigurationFieldPathsTopLevel = []string{ + "cad_periodicity", + "default_channel_index", + "second_channel", +} +var MACCommand_RelayEndDeviceConfReq_ConfigurationFieldPathsNested = []string{ + "backoff", + "mode", + "mode.always", + "mode.dynamic", + "mode.dynamic.smart_enable_level", + "mode.end_device_controlled", + "second_channel", + "second_channel.ack_offset", + "second_channel.data_rate_index", + "second_channel.frequency", + "serving_device_id", +} + +var MACCommand_RelayEndDeviceConfReq_ConfigurationFieldPathsTopLevel = []string{ + "backoff", + "mode", + "second_channel", + "serving_device_id", +} diff --git a/pkg/ttnpb/lorawan.pb.setters.fm.go b/pkg/ttnpb/lorawan.pb.setters.fm.go index cfba782da7..69b540cbae 100644 --- a/pkg/ttnpb/lorawan.pb.setters.fm.go +++ b/pkg/ttnpb/lorawan.pb.setters.fm.go @@ -1482,6 +1482,139 @@ func (dst *TxRequest) SetFields(src *TxRequest, paths ...string) error { return nil } +func (dst *RelaySecondChannel) SetFields(src *RelaySecondChannel, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "ack_offset": + if len(subs) > 0 { + return fmt.Errorf("'ack_offset' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.AckOffset = src.AckOffset + } else { + dst.AckOffset = 0 + } + case "data_rate_index": + if len(subs) > 0 { + return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DataRateIndex = src.DataRateIndex + } else { + dst.DataRateIndex = 0 + } + case "frequency": + if len(subs) > 0 { + return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Frequency = src.Frequency + } else { + var zero uint64 + dst.Frequency = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayUplinkForwardLimits) SetFields(src *RelayUplinkForwardLimits, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "bucket_size": + if len(subs) > 0 { + return fmt.Errorf("'bucket_size' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.BucketSize = src.BucketSize + } else { + dst.BucketSize = 0 + } + case "reload_rate": + if len(subs) > 0 { + return fmt.Errorf("'reload_rate' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ReloadRate = src.ReloadRate + } else { + var zero uint32 + dst.ReloadRate = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayForwardLimits) SetFields(src *RelayForwardLimits, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "bucket_size": + if len(subs) > 0 { + return fmt.Errorf("'bucket_size' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.BucketSize = src.BucketSize + } else { + dst.BucketSize = 0 + } + case "reload_rate": + if len(subs) > 0 { + return fmt.Errorf("'reload_rate' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ReloadRate = src.ReloadRate + } else { + var zero uint32 + dst.ReloadRate = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayEndDeviceAlwaysMode) SetFields(src *RelayEndDeviceAlwaysMode, paths ...string) error { + if len(paths) != 0 { + return fmt.Errorf("message RelayEndDeviceAlwaysMode has no fields, but paths %s were specified", paths) + } + return nil +} + +func (dst *RelayEndDeviceDynamicMode) SetFields(src *RelayEndDeviceDynamicMode, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "smart_enable_level": + if len(subs) > 0 { + return fmt.Errorf("'smart_enable_level' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.SmartEnableLevel = src.SmartEnableLevel + } else { + dst.SmartEnableLevel = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayEndDeviceControlledMode) SetFields(src *RelayEndDeviceControlledMode, paths ...string) error { + if len(paths) != 0 { + return fmt.Errorf("message RelayEndDeviceControlledMode has no fields, but paths %s were specified", paths) + } + return nil +} + func (dst *MACCommand) SetFields(src *MACCommand, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { @@ -2610,172 +2743,999 @@ func (dst *MACCommand) SetFields(src *MACCommand, paths ...string) error { dst.Payload = nil } } - - default: - return fmt.Errorf("invalid oneof field: '%s.%s'", name, oneofName) - } - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *MACCommands) SetFields(src *MACCommands, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "commands": - if len(subs) > 0 { - return fmt.Errorf("'commands' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Commands = src.Commands - } else { - dst.Commands = nil - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *FrequencyValue) SetFields(src *FrequencyValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - var zero uint64 - dst.Value = zero - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *ZeroableFrequencyValue) SetFields(src *ZeroableFrequencyValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - var zero uint64 - dst.Value = zero - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *DataRateOffsetValue) SetFields(src *DataRateOffsetValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - dst.Value = 0 - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *DataRateIndexValue) SetFields(src *DataRateIndexValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - dst.Value = 0 - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *PingSlotPeriodValue) SetFields(src *PingSlotPeriodValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - dst.Value = 0 - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *AggregatedDutyCycleValue) SetFields(src *AggregatedDutyCycleValue, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "value": - if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Value = src.Value - } else { - dst.Value = 0 - } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *RxDelayValue) SetFields(src *RxDelayValue, paths ...string) error { - for name, subs := range _processPaths(paths) { + case "relay_conf_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayConfReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_conf_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayConfReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_conf_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayConfReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayConfReq_).RelayConfReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayConfReq_).RelayConfReq + } else if srcTypeOk { + newDst = &MACCommand_RelayConfReq{} + dst.Payload = &MACCommand_RelayConfReq_{RelayConfReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_conf_ans": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayConfAns_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_conf_ans', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayConfAns_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_conf_ans', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayConfAns + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayConfAns_).RelayConfAns + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayConfAns_).RelayConfAns + } else if srcTypeOk { + newDst = &MACCommand_RelayConfAns{} + dst.Payload = &MACCommand_RelayConfAns_{RelayConfAns: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_end_device_conf_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayEndDeviceConfReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_end_device_conf_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayEndDeviceConfReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_end_device_conf_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayEndDeviceConfReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayEndDeviceConfReq_).RelayEndDeviceConfReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayEndDeviceConfReq_).RelayEndDeviceConfReq + } else if srcTypeOk { + newDst = &MACCommand_RelayEndDeviceConfReq{} + dst.Payload = &MACCommand_RelayEndDeviceConfReq_{RelayEndDeviceConfReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_end_device_conf_ans": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayEndDeviceConfAns_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_end_device_conf_ans', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayEndDeviceConfAns_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_end_device_conf_ans', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayEndDeviceConfAns + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayEndDeviceConfAns_).RelayEndDeviceConfAns + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayEndDeviceConfAns_).RelayEndDeviceConfAns + } else if srcTypeOk { + newDst = &MACCommand_RelayEndDeviceConfAns{} + dst.Payload = &MACCommand_RelayEndDeviceConfAns_{RelayEndDeviceConfAns: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_update_uplink_list_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayUpdateUplinkListReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_update_uplink_list_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayUpdateUplinkListReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_update_uplink_list_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayUpdateUplinkListReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayUpdateUplinkListReq_).RelayUpdateUplinkListReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayUpdateUplinkListReq_).RelayUpdateUplinkListReq + } else if srcTypeOk { + newDst = &MACCommand_RelayUpdateUplinkListReq{} + dst.Payload = &MACCommand_RelayUpdateUplinkListReq_{RelayUpdateUplinkListReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_update_uplink_list_ans": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayUpdateUplinkListAns_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_update_uplink_list_ans', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayUpdateUplinkListAns_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_update_uplink_list_ans', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayUpdateUplinkListAns + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayUpdateUplinkListAns_).RelayUpdateUplinkListAns + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayUpdateUplinkListAns_).RelayUpdateUplinkListAns + } else if srcTypeOk { + newDst = &MACCommand_RelayUpdateUplinkListAns{} + dst.Payload = &MACCommand_RelayUpdateUplinkListAns_{RelayUpdateUplinkListAns: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_ctrl_uplink_list_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayCtrlUplinkListReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_ctrl_uplink_list_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayCtrlUplinkListReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_ctrl_uplink_list_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayCtrlUplinkListReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayCtrlUplinkListReq_).RelayCtrlUplinkListReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayCtrlUplinkListReq_).RelayCtrlUplinkListReq + } else if srcTypeOk { + newDst = &MACCommand_RelayCtrlUplinkListReq{} + dst.Payload = &MACCommand_RelayCtrlUplinkListReq_{RelayCtrlUplinkListReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_ctrl_uplink_list_ans": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayCtrlUplinkListAns_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_ctrl_uplink_list_ans', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayCtrlUplinkListAns_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_ctrl_uplink_list_ans', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayCtrlUplinkListAns + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayCtrlUplinkListAns_).RelayCtrlUplinkListAns + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayCtrlUplinkListAns_).RelayCtrlUplinkListAns + } else if srcTypeOk { + newDst = &MACCommand_RelayCtrlUplinkListAns{} + dst.Payload = &MACCommand_RelayCtrlUplinkListAns_{RelayCtrlUplinkListAns: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_configure_fwd_limit_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayConfigureFwdLimitReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_configure_fwd_limit_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayConfigureFwdLimitReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_configure_fwd_limit_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayConfigureFwdLimitReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayConfigureFwdLimitReq_).RelayConfigureFwdLimitReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayConfigureFwdLimitReq_).RelayConfigureFwdLimitReq + } else if srcTypeOk { + newDst = &MACCommand_RelayConfigureFwdLimitReq{} + dst.Payload = &MACCommand_RelayConfigureFwdLimitReq_{RelayConfigureFwdLimitReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_configure_fwd_limit_ans": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayConfigureFwdLimitAns_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_configure_fwd_limit_ans', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayConfigureFwdLimitAns_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_configure_fwd_limit_ans', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayConfigureFwdLimitAns + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayConfigureFwdLimitAns_).RelayConfigureFwdLimitAns + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayConfigureFwdLimitAns_).RelayConfigureFwdLimitAns + } else if srcTypeOk { + newDst = &MACCommand_RelayConfigureFwdLimitAns{} + dst.Payload = &MACCommand_RelayConfigureFwdLimitAns_{RelayConfigureFwdLimitAns: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + case "relay_notify_new_end_device_req": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Payload.(*MACCommand_RelayNotifyNewEndDeviceReq_) + } + if srcValid := srcTypeOk || src == nil || src.Payload == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'relay_notify_new_end_device_req', while different oneof is set in source") + } + _, dstTypeOk := dst.Payload.(*MACCommand_RelayNotifyNewEndDeviceReq_) + if dstValid := dstTypeOk || dst.Payload == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'relay_notify_new_end_device_req', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *MACCommand_RelayNotifyNewEndDeviceReq + if srcTypeOk { + newSrc = src.Payload.(*MACCommand_RelayNotifyNewEndDeviceReq_).RelayNotifyNewEndDeviceReq + } + if dstTypeOk { + newDst = dst.Payload.(*MACCommand_RelayNotifyNewEndDeviceReq_).RelayNotifyNewEndDeviceReq + } else if srcTypeOk { + newDst = &MACCommand_RelayNotifyNewEndDeviceReq{} + dst.Payload = &MACCommand_RelayNotifyNewEndDeviceReq_{RelayNotifyNewEndDeviceReq: newDst} + } else { + dst.Payload = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Payload = src.Payload + } else { + dst.Payload = nil + } + } + + default: + return fmt.Errorf("invalid oneof field: '%s.%s'", name, oneofName) + } + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommands) SetFields(src *MACCommands, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "commands": + if len(subs) > 0 { + return fmt.Errorf("'commands' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Commands = src.Commands + } else { + dst.Commands = nil + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *FrequencyValue) SetFields(src *FrequencyValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + var zero uint64 + dst.Value = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *ZeroableFrequencyValue) SetFields(src *ZeroableFrequencyValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + var zero uint64 + dst.Value = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *DataRateOffsetValue) SetFields(src *DataRateOffsetValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *DataRateIndexValue) SetFields(src *DataRateIndexValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *PingSlotPeriodValue) SetFields(src *PingSlotPeriodValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *AggregatedDutyCycleValue) SetFields(src *AggregatedDutyCycleValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RxDelayValue) SetFields(src *RxDelayValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *ADRAckLimitExponentValue) SetFields(src *ADRAckLimitExponentValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *ADRAckDelayExponentValue) SetFields(src *ADRAckDelayExponentValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *DeviceEIRPValue) SetFields(src *DeviceEIRPValue, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "value": + if len(subs) > 0 { + return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Value = src.Value + } else { + dst.Value = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayForwardUplinkReq) SetFields(src *RelayForwardUplinkReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "data_rate": + if len(subs) > 0 { + var newDst, newSrc *DataRate + if (src == nil || src.DataRate == nil) && dst.DataRate == nil { + continue + } + if src != nil { + newSrc = src.DataRate + } + if dst.DataRate != nil { + newDst = dst.DataRate + } else { + newDst = &DataRate{} + dst.DataRate = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.DataRate = src.DataRate + } else { + dst.DataRate = nil + } + } + case "snr": + if len(subs) > 0 { + return fmt.Errorf("'snr' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Snr = src.Snr + } else { + var zero int32 + dst.Snr = zero + } + case "rssi": + if len(subs) > 0 { + return fmt.Errorf("'rssi' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rssi = src.Rssi + } else { + var zero int32 + dst.Rssi = zero + } + case "wor_channel": + if len(subs) > 0 { + return fmt.Errorf("'wor_channel' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.WorChannel = src.WorChannel + } else { + dst.WorChannel = 0 + } + case "frequency": + if len(subs) > 0 { + return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Frequency = src.Frequency + } else { + var zero uint64 + dst.Frequency = zero + } + case "raw_payload": + if len(subs) > 0 { + return fmt.Errorf("'raw_payload' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.RawPayload = src.RawPayload + } else { + dst.RawPayload = nil + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayForwardDownlinkReq) SetFields(src *RelayForwardDownlinkReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "raw_payload": + if len(subs) > 0 { + return fmt.Errorf("'raw_payload' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.RawPayload = src.RawPayload + } else { + dst.RawPayload = nil + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *RelayUplinkToken) SetFields(src *RelayUplinkToken, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "ids": + if len(subs) > 0 { + var newDst, newSrc *EndDeviceIdentifiers + if (src == nil || src.Ids == nil) && dst.Ids == nil { + continue + } + if src != nil { + newSrc = src.Ids + } + if dst.Ids != nil { + newDst = dst.Ids + } else { + newDst = &EndDeviceIdentifiers{} + dst.Ids = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Ids = src.Ids + } else { + dst.Ids = nil + } + } + case "session_key_id": + if len(subs) > 0 { + return fmt.Errorf("'session_key_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.SessionKeyId = src.SessionKeyId + } else { + dst.SessionKeyId = nil + } + case "full_f_cnt": + if len(subs) > 0 { + return fmt.Errorf("'full_f_cnt' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.FullFCnt = src.FullFCnt + } else { + var zero uint32 + dst.FullFCnt = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *TxSettings_Downlink) SetFields(src *TxSettings_Downlink, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "antenna_index": + if len(subs) > 0 { + return fmt.Errorf("'antenna_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.AntennaIndex = src.AntennaIndex + } else { + var zero uint32 + dst.AntennaIndex = zero + } + case "tx_power": + if len(subs) > 0 { + return fmt.Errorf("'tx_power' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.TxPower = src.TxPower + } else { + var zero float32 + dst.TxPower = zero + } + case "invert_polarization": + if len(subs) > 0 { + return fmt.Errorf("'invert_polarization' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.InvertPolarization = src.InvertPolarization + } else { + var zero bool + dst.InvertPolarization = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_ResetInd) SetFields(src *MACCommand_ResetInd, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "minor_version": + if len(subs) > 0 { + return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.MinorVersion = src.MinorVersion + } else { + dst.MinorVersion = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_ResetConf) SetFields(src *MACCommand_ResetConf, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "minor_version": + if len(subs) > 0 { + return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.MinorVersion = src.MinorVersion + } else { + dst.MinorVersion = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_LinkCheckAns) SetFields(src *MACCommand_LinkCheckAns, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "margin": + if len(subs) > 0 { + return fmt.Errorf("'margin' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Margin = src.Margin + } else { + var zero uint32 + dst.Margin = zero + } + case "gateway_count": + if len(subs) > 0 { + return fmt.Errorf("'gateway_count' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.GatewayCount = src.GatewayCount + } else { + var zero uint32 + dst.GatewayCount = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_LinkADRReq) SetFields(src *MACCommand_LinkADRReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "data_rate_index": + if len(subs) > 0 { + return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DataRateIndex = src.DataRateIndex + } else { + dst.DataRateIndex = 0 + } + case "tx_power_index": + if len(subs) > 0 { + return fmt.Errorf("'tx_power_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.TxPowerIndex = src.TxPowerIndex + } else { + var zero uint32 + dst.TxPowerIndex = zero + } + case "channel_mask": + if len(subs) > 0 { + return fmt.Errorf("'channel_mask' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ChannelMask = src.ChannelMask + } else { + dst.ChannelMask = nil + } + case "channel_mask_control": + if len(subs) > 0 { + return fmt.Errorf("'channel_mask_control' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ChannelMaskControl = src.ChannelMaskControl + } else { + var zero uint32 + dst.ChannelMaskControl = zero + } + case "nb_trans": + if len(subs) > 0 { + return fmt.Errorf("'nb_trans' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.NbTrans = src.NbTrans + } else { + var zero uint32 + dst.NbTrans = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_LinkADRAns) SetFields(src *MACCommand_LinkADRAns, paths ...string) error { + for name, subs := range _processPaths(paths) { switch name { - case "value": + case "channel_mask_ack": if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + return fmt.Errorf("'channel_mask_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.Value = src.Value + dst.ChannelMaskAck = src.ChannelMaskAck } else { - dst.Value = 0 + var zero bool + dst.ChannelMaskAck = zero + } + case "data_rate_index_ack": + if len(subs) > 0 { + return fmt.Errorf("'data_rate_index_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DataRateIndexAck = src.DataRateIndexAck + } else { + var zero bool + dst.DataRateIndexAck = zero + } + case "tx_power_index_ack": + if len(subs) > 0 { + return fmt.Errorf("'tx_power_index_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.TxPowerIndexAck = src.TxPowerIndexAck + } else { + var zero bool + dst.TxPowerIndexAck = zero } default: @@ -2785,17 +3745,17 @@ func (dst *RxDelayValue) SetFields(src *RxDelayValue, paths ...string) error { return nil } -func (dst *ADRAckLimitExponentValue) SetFields(src *ADRAckLimitExponentValue, paths ...string) error { +func (dst *MACCommand_DutyCycleReq) SetFields(src *MACCommand_DutyCycleReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "value": + case "max_duty_cycle": if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_duty_cycle' has no subfields, but %s were specified", subs) } if src != nil { - dst.Value = src.Value + dst.MaxDutyCycle = src.MaxDutyCycle } else { - dst.Value = 0 + dst.MaxDutyCycle = 0 } default: @@ -2805,17 +3765,36 @@ func (dst *ADRAckLimitExponentValue) SetFields(src *ADRAckLimitExponentValue, pa return nil } -func (dst *ADRAckDelayExponentValue) SetFields(src *ADRAckDelayExponentValue, paths ...string) error { +func (dst *MACCommand_RxParamSetupReq) SetFields(src *MACCommand_RxParamSetupReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "value": + case "rx2_data_rate_index": if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rx2_data_rate_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.Value = src.Value + dst.Rx2DataRateIndex = src.Rx2DataRateIndex } else { - dst.Value = 0 + dst.Rx2DataRateIndex = 0 + } + case "rx1_data_rate_offset": + if len(subs) > 0 { + return fmt.Errorf("'rx1_data_rate_offset' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rx1DataRateOffset = src.Rx1DataRateOffset + } else { + dst.Rx1DataRateOffset = 0 + } + case "rx2_frequency": + if len(subs) > 0 { + return fmt.Errorf("'rx2_frequency' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rx2Frequency = src.Rx2Frequency + } else { + var zero uint64 + dst.Rx2Frequency = zero } default: @@ -2825,17 +3804,38 @@ func (dst *ADRAckDelayExponentValue) SetFields(src *ADRAckDelayExponentValue, pa return nil } -func (dst *DeviceEIRPValue) SetFields(src *DeviceEIRPValue, paths ...string) error { +func (dst *MACCommand_RxParamSetupAns) SetFields(src *MACCommand_RxParamSetupAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "value": + case "rx2_data_rate_index_ack": if len(subs) > 0 { - return fmt.Errorf("'value' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rx2_data_rate_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.Value = src.Value + dst.Rx2DataRateIndexAck = src.Rx2DataRateIndexAck } else { - dst.Value = 0 + var zero bool + dst.Rx2DataRateIndexAck = zero + } + case "rx1_data_rate_offset_ack": + if len(subs) > 0 { + return fmt.Errorf("'rx1_data_rate_offset_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rx1DataRateOffsetAck = src.Rx1DataRateOffsetAck + } else { + var zero bool + dst.Rx1DataRateOffsetAck = zero + } + case "rx2_frequency_ack": + if len(subs) > 0 { + return fmt.Errorf("'rx2_frequency_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rx2FrequencyAck = src.Rx2FrequencyAck + } else { + var zero bool + dst.Rx2FrequencyAck = zero } default: @@ -2845,38 +3845,77 @@ func (dst *DeviceEIRPValue) SetFields(src *DeviceEIRPValue, paths ...string) err return nil } -func (dst *TxSettings_Downlink) SetFields(src *TxSettings_Downlink, paths ...string) error { +func (dst *MACCommand_DevStatusAns) SetFields(src *MACCommand_DevStatusAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "antenna_index": + case "battery": if len(subs) > 0 { - return fmt.Errorf("'antenna_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'battery' has no subfields, but %s were specified", subs) } if src != nil { - dst.AntennaIndex = src.AntennaIndex + dst.Battery = src.Battery } else { var zero uint32 - dst.AntennaIndex = zero + dst.Battery = zero } - case "tx_power": + case "margin": if len(subs) > 0 { - return fmt.Errorf("'tx_power' has no subfields, but %s were specified", subs) + return fmt.Errorf("'margin' has no subfields, but %s were specified", subs) } if src != nil { - dst.TxPower = src.TxPower + dst.Margin = src.Margin } else { - var zero float32 - dst.TxPower = zero + var zero int32 + dst.Margin = zero } - case "invert_polarization": + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_NewChannelReq) SetFields(src *MACCommand_NewChannelReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "channel_index": if len(subs) > 0 { - return fmt.Errorf("'invert_polarization' has no subfields, but %s were specified", subs) + return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.InvertPolarization = src.InvertPolarization + dst.ChannelIndex = src.ChannelIndex } else { - var zero bool - dst.InvertPolarization = zero + var zero uint32 + dst.ChannelIndex = zero + } + case "frequency": + if len(subs) > 0 { + return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Frequency = src.Frequency + } else { + var zero uint64 + dst.Frequency = zero + } + case "min_data_rate_index": + if len(subs) > 0 { + return fmt.Errorf("'min_data_rate_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.MinDataRateIndex = src.MinDataRateIndex + } else { + dst.MinDataRateIndex = 0 + } + case "max_data_rate_index": + if len(subs) > 0 { + return fmt.Errorf("'max_data_rate_index' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.MaxDataRateIndex = src.MaxDataRateIndex + } else { + dst.MaxDataRateIndex = 0 } default: @@ -2886,17 +3925,28 @@ func (dst *TxSettings_Downlink) SetFields(src *TxSettings_Downlink, paths ...str return nil } -func (dst *MACCommand_ResetInd) SetFields(src *MACCommand_ResetInd, paths ...string) error { +func (dst *MACCommand_NewChannelAns) SetFields(src *MACCommand_NewChannelAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "minor_version": + case "frequency_ack": if len(subs) > 0 { - return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) + return fmt.Errorf("'frequency_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.MinorVersion = src.MinorVersion + dst.FrequencyAck = src.FrequencyAck } else { - dst.MinorVersion = 0 + var zero bool + dst.FrequencyAck = zero + } + case "data_rate_ack": + if len(subs) > 0 { + return fmt.Errorf("'data_rate_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DataRateAck = src.DataRateAck + } else { + var zero bool + dst.DataRateAck = zero } default: @@ -2906,17 +3956,28 @@ func (dst *MACCommand_ResetInd) SetFields(src *MACCommand_ResetInd, paths ...str return nil } -func (dst *MACCommand_ResetConf) SetFields(src *MACCommand_ResetConf, paths ...string) error { +func (dst *MACCommand_DLChannelReq) SetFields(src *MACCommand_DLChannelReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "minor_version": + case "channel_index": if len(subs) > 0 { - return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) + return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.MinorVersion = src.MinorVersion + dst.ChannelIndex = src.ChannelIndex } else { - dst.MinorVersion = 0 + var zero uint32 + dst.ChannelIndex = zero + } + case "frequency": + if len(subs) > 0 { + return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Frequency = src.Frequency + } else { + var zero uint64 + dst.Frequency = zero } default: @@ -2926,28 +3987,28 @@ func (dst *MACCommand_ResetConf) SetFields(src *MACCommand_ResetConf, paths ...s return nil } -func (dst *MACCommand_LinkCheckAns) SetFields(src *MACCommand_LinkCheckAns, paths ...string) error { +func (dst *MACCommand_DLChannelAns) SetFields(src *MACCommand_DLChannelAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "margin": + case "channel_index_ack": if len(subs) > 0 { - return fmt.Errorf("'margin' has no subfields, but %s were specified", subs) + return fmt.Errorf("'channel_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.Margin = src.Margin + dst.ChannelIndexAck = src.ChannelIndexAck } else { - var zero uint32 - dst.Margin = zero + var zero bool + dst.ChannelIndexAck = zero } - case "gateway_count": + case "frequency_ack": if len(subs) > 0 { - return fmt.Errorf("'gateway_count' has no subfields, but %s were specified", subs) + return fmt.Errorf("'frequency_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.GatewayCount = src.GatewayCount + dst.FrequencyAck = src.FrequencyAck } else { - var zero uint32 - dst.GatewayCount = zero + var zero bool + dst.FrequencyAck = zero } default: @@ -2957,56 +4018,77 @@ func (dst *MACCommand_LinkCheckAns) SetFields(src *MACCommand_LinkCheckAns, path return nil } -func (dst *MACCommand_LinkADRReq) SetFields(src *MACCommand_LinkADRReq, paths ...string) error { +func (dst *MACCommand_RxTimingSetupReq) SetFields(src *MACCommand_RxTimingSetupReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "data_rate_index": + case "delay": if len(subs) > 0 { - return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'delay' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateIndex = src.DataRateIndex + dst.Delay = src.Delay } else { - dst.DataRateIndex = 0 + dst.Delay = 0 } - case "tx_power_index": + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_TxParamSetupReq) SetFields(src *MACCommand_TxParamSetupReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "max_eirp_index": if len(subs) > 0 { - return fmt.Errorf("'tx_power_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_eirp_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.TxPowerIndex = src.TxPowerIndex + dst.MaxEirpIndex = src.MaxEirpIndex } else { - var zero uint32 - dst.TxPowerIndex = zero + dst.MaxEirpIndex = 0 } - case "channel_mask": + case "uplink_dwell_time": if len(subs) > 0 { - return fmt.Errorf("'channel_mask' has no subfields, but %s were specified", subs) + return fmt.Errorf("'uplink_dwell_time' has no subfields, but %s were specified", subs) } if src != nil { - dst.ChannelMask = src.ChannelMask + dst.UplinkDwellTime = src.UplinkDwellTime } else { - dst.ChannelMask = nil + var zero bool + dst.UplinkDwellTime = zero } - case "channel_mask_control": + case "downlink_dwell_time": if len(subs) > 0 { - return fmt.Errorf("'channel_mask_control' has no subfields, but %s were specified", subs) + return fmt.Errorf("'downlink_dwell_time' has no subfields, but %s were specified", subs) } if src != nil { - dst.ChannelMaskControl = src.ChannelMaskControl + dst.DownlinkDwellTime = src.DownlinkDwellTime } else { - var zero uint32 - dst.ChannelMaskControl = zero + var zero bool + dst.DownlinkDwellTime = zero } - case "nb_trans": + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_RekeyInd) SetFields(src *MACCommand_RekeyInd, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "minor_version": if len(subs) > 0 { - return fmt.Errorf("'nb_trans' has no subfields, but %s were specified", subs) + return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) } if src != nil { - dst.NbTrans = src.NbTrans + dst.MinorVersion = src.MinorVersion } else { - var zero uint32 - dst.NbTrans = zero + dst.MinorVersion = 0 } default: @@ -3016,38 +4098,46 @@ func (dst *MACCommand_LinkADRReq) SetFields(src *MACCommand_LinkADRReq, paths .. return nil } -func (dst *MACCommand_LinkADRAns) SetFields(src *MACCommand_LinkADRAns, paths ...string) error { +func (dst *MACCommand_RekeyConf) SetFields(src *MACCommand_RekeyConf, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "channel_mask_ack": + case "minor_version": if len(subs) > 0 { - return fmt.Errorf("'channel_mask_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) } if src != nil { - dst.ChannelMaskAck = src.ChannelMaskAck + dst.MinorVersion = src.MinorVersion } else { - var zero bool - dst.ChannelMaskAck = zero + dst.MinorVersion = 0 } - case "data_rate_index_ack": + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_ADRParamSetupReq) SetFields(src *MACCommand_ADRParamSetupReq, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "adr_ack_limit_exponent": if len(subs) > 0 { - return fmt.Errorf("'data_rate_index_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'adr_ack_limit_exponent' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateIndexAck = src.DataRateIndexAck + dst.AdrAckLimitExponent = src.AdrAckLimitExponent } else { - var zero bool - dst.DataRateIndexAck = zero + dst.AdrAckLimitExponent = 0 } - case "tx_power_index_ack": + case "adr_ack_delay_exponent": if len(subs) > 0 { - return fmt.Errorf("'tx_power_index_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'adr_ack_delay_exponent' has no subfields, but %s were specified", subs) } if src != nil { - dst.TxPowerIndexAck = src.TxPowerIndexAck + dst.AdrAckDelayExponent = src.AdrAckDelayExponent } else { - var zero bool - dst.TxPowerIndexAck = zero + dst.AdrAckDelayExponent = 0 } default: @@ -3057,17 +4147,17 @@ func (dst *MACCommand_LinkADRAns) SetFields(src *MACCommand_LinkADRAns, paths .. return nil } -func (dst *MACCommand_DutyCycleReq) SetFields(src *MACCommand_DutyCycleReq, paths ...string) error { +func (dst *MACCommand_DeviceTimeAns) SetFields(src *MACCommand_DeviceTimeAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "max_duty_cycle": + case "time": if len(subs) > 0 { - return fmt.Errorf("'max_duty_cycle' has no subfields, but %s were specified", subs) + return fmt.Errorf("'time' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxDutyCycle = src.MaxDutyCycle + dst.Time = src.Time } else { - dst.MaxDutyCycle = 0 + dst.Time = nil } default: @@ -3077,36 +4167,45 @@ func (dst *MACCommand_DutyCycleReq) SetFields(src *MACCommand_DutyCycleReq, path return nil } -func (dst *MACCommand_RxParamSetupReq) SetFields(src *MACCommand_RxParamSetupReq, paths ...string) error { +func (dst *MACCommand_ForceRejoinReq) SetFields(src *MACCommand_ForceRejoinReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "rx2_data_rate_index": + case "rejoin_type": if len(subs) > 0 { - return fmt.Errorf("'rx2_data_rate_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rejoin_type' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx2DataRateIndex = src.Rx2DataRateIndex + dst.RejoinType = src.RejoinType } else { - dst.Rx2DataRateIndex = 0 + dst.RejoinType = 0 } - case "rx1_data_rate_offset": + case "data_rate_index": if len(subs) > 0 { - return fmt.Errorf("'rx1_data_rate_offset' has no subfields, but %s were specified", subs) + return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx1DataRateOffset = src.Rx1DataRateOffset + dst.DataRateIndex = src.DataRateIndex } else { - dst.Rx1DataRateOffset = 0 + dst.DataRateIndex = 0 } - case "rx2_frequency": + case "max_retries": if len(subs) > 0 { - return fmt.Errorf("'rx2_frequency' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_retries' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx2Frequency = src.Rx2Frequency + dst.MaxRetries = src.MaxRetries } else { - var zero uint64 - dst.Rx2Frequency = zero + var zero uint32 + dst.MaxRetries = zero + } + case "period_exponent": + if len(subs) > 0 { + return fmt.Errorf("'period_exponent' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.PeriodExponent = src.PeriodExponent + } else { + dst.PeriodExponent = 0 } default: @@ -3116,38 +4215,47 @@ func (dst *MACCommand_RxParamSetupReq) SetFields(src *MACCommand_RxParamSetupReq return nil } -func (dst *MACCommand_RxParamSetupAns) SetFields(src *MACCommand_RxParamSetupAns, paths ...string) error { +func (dst *MACCommand_RejoinParamSetupReq) SetFields(src *MACCommand_RejoinParamSetupReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "rx2_data_rate_index_ack": + case "max_count_exponent": if len(subs) > 0 { - return fmt.Errorf("'rx2_data_rate_index_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_count_exponent' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx2DataRateIndexAck = src.Rx2DataRateIndexAck + dst.MaxCountExponent = src.MaxCountExponent } else { - var zero bool - dst.Rx2DataRateIndexAck = zero + dst.MaxCountExponent = 0 } - case "rx1_data_rate_offset_ack": + case "max_time_exponent": if len(subs) > 0 { - return fmt.Errorf("'rx1_data_rate_offset_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_time_exponent' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx1DataRateOffsetAck = src.Rx1DataRateOffsetAck + dst.MaxTimeExponent = src.MaxTimeExponent } else { - var zero bool - dst.Rx1DataRateOffsetAck = zero + dst.MaxTimeExponent = 0 } - case "rx2_frequency_ack": + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_RejoinParamSetupAns) SetFields(src *MACCommand_RejoinParamSetupAns, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "max_time_exponent_ack": if len(subs) > 0 { - return fmt.Errorf("'rx2_frequency_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'max_time_exponent_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.Rx2FrequencyAck = src.Rx2FrequencyAck + dst.MaxTimeExponentAck = src.MaxTimeExponentAck } else { var zero bool - dst.Rx2FrequencyAck = zero + dst.MaxTimeExponentAck = zero } default: @@ -3157,28 +4265,17 @@ func (dst *MACCommand_RxParamSetupAns) SetFields(src *MACCommand_RxParamSetupAns return nil } -func (dst *MACCommand_DevStatusAns) SetFields(src *MACCommand_DevStatusAns, paths ...string) error { +func (dst *MACCommand_PingSlotInfoReq) SetFields(src *MACCommand_PingSlotInfoReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "battery": - if len(subs) > 0 { - return fmt.Errorf("'battery' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Battery = src.Battery - } else { - var zero uint32 - dst.Battery = zero - } - case "margin": + case "period": if len(subs) > 0 { - return fmt.Errorf("'margin' has no subfields, but %s were specified", subs) + return fmt.Errorf("'period' has no subfields, but %s were specified", subs) } if src != nil { - dst.Margin = src.Margin + dst.Period = src.Period } else { - var zero int32 - dst.Margin = zero + dst.Period = 0 } default: @@ -3188,19 +4285,9 @@ func (dst *MACCommand_DevStatusAns) SetFields(src *MACCommand_DevStatusAns, path return nil } -func (dst *MACCommand_NewChannelReq) SetFields(src *MACCommand_NewChannelReq, paths ...string) error { +func (dst *MACCommand_PingSlotChannelReq) SetFields(src *MACCommand_PingSlotChannelReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "channel_index": - if len(subs) > 0 { - return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.ChannelIndex = src.ChannelIndex - } else { - var zero uint32 - dst.ChannelIndex = zero - } case "frequency": if len(subs) > 0 { return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) @@ -3211,23 +4298,14 @@ func (dst *MACCommand_NewChannelReq) SetFields(src *MACCommand_NewChannelReq, pa var zero uint64 dst.Frequency = zero } - case "min_data_rate_index": - if len(subs) > 0 { - return fmt.Errorf("'min_data_rate_index' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.MinDataRateIndex = src.MinDataRateIndex - } else { - dst.MinDataRateIndex = 0 - } - case "max_data_rate_index": + case "data_rate_index": if len(subs) > 0 { - return fmt.Errorf("'max_data_rate_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxDataRateIndex = src.MaxDataRateIndex + dst.DataRateIndex = src.DataRateIndex } else { - dst.MaxDataRateIndex = 0 + dst.DataRateIndex = 0 } default: @@ -3237,7 +4315,7 @@ func (dst *MACCommand_NewChannelReq) SetFields(src *MACCommand_NewChannelReq, pa return nil } -func (dst *MACCommand_NewChannelAns) SetFields(src *MACCommand_NewChannelAns, paths ...string) error { +func (dst *MACCommand_PingSlotChannelAns) SetFields(src *MACCommand_PingSlotChannelAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { case "frequency_ack": @@ -3250,15 +4328,46 @@ func (dst *MACCommand_NewChannelAns) SetFields(src *MACCommand_NewChannelAns, pa var zero bool dst.FrequencyAck = zero } - case "data_rate_ack": + case "data_rate_index_ack": + if len(subs) > 0 { + return fmt.Errorf("'data_rate_index_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DataRateIndexAck = src.DataRateIndexAck + } else { + var zero bool + dst.DataRateIndexAck = zero + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} + +func (dst *MACCommand_BeaconTimingAns) SetFields(src *MACCommand_BeaconTimingAns, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "delay": + if len(subs) > 0 { + return fmt.Errorf("'delay' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Delay = src.Delay + } else { + var zero uint32 + dst.Delay = zero + } + case "channel_index": if len(subs) > 0 { - return fmt.Errorf("'data_rate_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateAck = src.DataRateAck + dst.ChannelIndex = src.ChannelIndex } else { - var zero bool - dst.DataRateAck = zero + var zero uint32 + dst.ChannelIndex = zero } default: @@ -3268,19 +4377,9 @@ func (dst *MACCommand_NewChannelAns) SetFields(src *MACCommand_NewChannelAns, pa return nil } -func (dst *MACCommand_DLChannelReq) SetFields(src *MACCommand_DLChannelReq, paths ...string) error { +func (dst *MACCommand_BeaconFreqReq) SetFields(src *MACCommand_BeaconFreqReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "channel_index": - if len(subs) > 0 { - return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.ChannelIndex = src.ChannelIndex - } else { - var zero uint32 - dst.ChannelIndex = zero - } case "frequency": if len(subs) > 0 { return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) @@ -3299,19 +4398,9 @@ func (dst *MACCommand_DLChannelReq) SetFields(src *MACCommand_DLChannelReq, path return nil } -func (dst *MACCommand_DLChannelAns) SetFields(src *MACCommand_DLChannelAns, paths ...string) error { +func (dst *MACCommand_BeaconFreqAns) SetFields(src *MACCommand_BeaconFreqAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "channel_index_ack": - if len(subs) > 0 { - return fmt.Errorf("'channel_index_ack' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.ChannelIndexAck = src.ChannelIndexAck - } else { - var zero bool - dst.ChannelIndexAck = zero - } case "frequency_ack": if len(subs) > 0 { return fmt.Errorf("'frequency_ack' has no subfields, but %s were specified", subs) @@ -3330,17 +4419,17 @@ func (dst *MACCommand_DLChannelAns) SetFields(src *MACCommand_DLChannelAns, path return nil } -func (dst *MACCommand_RxTimingSetupReq) SetFields(src *MACCommand_RxTimingSetupReq, paths ...string) error { +func (dst *MACCommand_DeviceModeInd) SetFields(src *MACCommand_DeviceModeInd, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "delay": + case "class": if len(subs) > 0 { - return fmt.Errorf("'delay' has no subfields, but %s were specified", subs) + return fmt.Errorf("'class' has no subfields, but %s were specified", subs) } if src != nil { - dst.Delay = src.Delay + dst.Class = src.Class } else { - dst.Delay = 0 + dst.Class = 0 } default: @@ -3350,37 +4439,17 @@ func (dst *MACCommand_RxTimingSetupReq) SetFields(src *MACCommand_RxTimingSetupR return nil } -func (dst *MACCommand_TxParamSetupReq) SetFields(src *MACCommand_TxParamSetupReq, paths ...string) error { +func (dst *MACCommand_DeviceModeConf) SetFields(src *MACCommand_DeviceModeConf, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "max_eirp_index": - if len(subs) > 0 { - return fmt.Errorf("'max_eirp_index' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.MaxEirpIndex = src.MaxEirpIndex - } else { - dst.MaxEirpIndex = 0 - } - case "uplink_dwell_time": - if len(subs) > 0 { - return fmt.Errorf("'uplink_dwell_time' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.UplinkDwellTime = src.UplinkDwellTime - } else { - var zero bool - dst.UplinkDwellTime = zero - } - case "downlink_dwell_time": + case "class": if len(subs) > 0 { - return fmt.Errorf("'downlink_dwell_time' has no subfields, but %s were specified", subs) + return fmt.Errorf("'class' has no subfields, but %s were specified", subs) } if src != nil { - dst.DownlinkDwellTime = src.DownlinkDwellTime + dst.Class = src.Class } else { - var zero bool - dst.DownlinkDwellTime = zero + dst.Class = 0 } default: @@ -3390,17 +4459,33 @@ func (dst *MACCommand_TxParamSetupReq) SetFields(src *MACCommand_TxParamSetupReq return nil } -func (dst *MACCommand_RekeyInd) SetFields(src *MACCommand_RekeyInd, paths ...string) error { +func (dst *MACCommand_RelayConfReq) SetFields(src *MACCommand_RelayConfReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "minor_version": + case "configuration": if len(subs) > 0 { - return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.MinorVersion = src.MinorVersion + var newDst, newSrc *MACCommand_RelayConfReq_Configuration + if (src == nil || src.Configuration == nil) && dst.Configuration == nil { + continue + } + if src != nil { + newSrc = src.Configuration + } + if dst.Configuration != nil { + newDst = dst.Configuration + } else { + newDst = &MACCommand_RelayConfReq_Configuration{} + dst.Configuration = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } } else { - dst.MinorVersion = 0 + if src != nil { + dst.Configuration = src.Configuration + } else { + dst.Configuration = nil + } } default: @@ -3410,46 +4495,68 @@ func (dst *MACCommand_RekeyInd) SetFields(src *MACCommand_RekeyInd, paths ...str return nil } -func (dst *MACCommand_RekeyConf) SetFields(src *MACCommand_RekeyConf, paths ...string) error { +func (dst *MACCommand_RelayConfAns) SetFields(src *MACCommand_RelayConfAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "minor_version": + case "second_channel_frequency_ack": if len(subs) > 0 { - return fmt.Errorf("'minor_version' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_frequency_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.MinorVersion = src.MinorVersion + dst.SecondChannelFrequencyAck = src.SecondChannelFrequencyAck } else { - dst.MinorVersion = 0 + var zero bool + dst.SecondChannelFrequencyAck = zero } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *MACCommand_ADRParamSetupReq) SetFields(src *MACCommand_ADRParamSetupReq, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "adr_ack_limit_exponent": + case "second_channel_ack_offset_ack": if len(subs) > 0 { - return fmt.Errorf("'adr_ack_limit_exponent' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_ack_offset_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.AdrAckLimitExponent = src.AdrAckLimitExponent + dst.SecondChannelAckOffsetAck = src.SecondChannelAckOffsetAck } else { - dst.AdrAckLimitExponent = 0 + var zero bool + dst.SecondChannelAckOffsetAck = zero } - case "adr_ack_delay_exponent": + case "second_channel_data_rate_index_ack": if len(subs) > 0 { - return fmt.Errorf("'adr_ack_delay_exponent' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_data_rate_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.AdrAckDelayExponent = src.AdrAckDelayExponent + dst.SecondChannelDataRateIndexAck = src.SecondChannelDataRateIndexAck } else { - dst.AdrAckDelayExponent = 0 + var zero bool + dst.SecondChannelDataRateIndexAck = zero + } + case "second_channel_index_ack": + if len(subs) > 0 { + return fmt.Errorf("'second_channel_index_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.SecondChannelIndexAck = src.SecondChannelIndexAck + } else { + var zero bool + dst.SecondChannelIndexAck = zero + } + case "default_channel_index_ack": + if len(subs) > 0 { + return fmt.Errorf("'default_channel_index_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DefaultChannelIndexAck = src.DefaultChannelIndexAck + } else { + var zero bool + dst.DefaultChannelIndexAck = zero + } + case "cad_periodicity_ack": + if len(subs) > 0 { + return fmt.Errorf("'cad_periodicity_ack' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.CadPeriodicityAck = src.CadPeriodicityAck + } else { + var zero bool + dst.CadPeriodicityAck = zero } default: @@ -3459,17 +4566,33 @@ func (dst *MACCommand_ADRParamSetupReq) SetFields(src *MACCommand_ADRParamSetupR return nil } -func (dst *MACCommand_DeviceTimeAns) SetFields(src *MACCommand_DeviceTimeAns, paths ...string) error { +func (dst *MACCommand_RelayEndDeviceConfReq) SetFields(src *MACCommand_RelayEndDeviceConfReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "time": + case "configuration": if len(subs) > 0 { - return fmt.Errorf("'time' has no subfields, but %s were specified", subs) - } - if src != nil { - dst.Time = src.Time + var newDst, newSrc *MACCommand_RelayEndDeviceConfReq_Configuration + if (src == nil || src.Configuration == nil) && dst.Configuration == nil { + continue + } + if src != nil { + newSrc = src.Configuration + } + if dst.Configuration != nil { + newDst = dst.Configuration + } else { + newDst = &MACCommand_RelayEndDeviceConfReq_Configuration{} + dst.Configuration = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } } else { - dst.Time = nil + if src != nil { + dst.Configuration = src.Configuration + } else { + dst.Configuration = nil + } } default: @@ -3479,45 +4602,48 @@ func (dst *MACCommand_DeviceTimeAns) SetFields(src *MACCommand_DeviceTimeAns, pa return nil } -func (dst *MACCommand_ForceRejoinReq) SetFields(src *MACCommand_ForceRejoinReq, paths ...string) error { +func (dst *MACCommand_RelayEndDeviceConfAns) SetFields(src *MACCommand_RelayEndDeviceConfAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "rejoin_type": + case "second_channel_frequency_ack": if len(subs) > 0 { - return fmt.Errorf("'rejoin_type' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_frequency_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.RejoinType = src.RejoinType + dst.SecondChannelFrequencyAck = src.SecondChannelFrequencyAck } else { - dst.RejoinType = 0 + var zero bool + dst.SecondChannelFrequencyAck = zero } - case "data_rate_index": + case "second_channel_data_rate_index_ack": if len(subs) > 0 { - return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_data_rate_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateIndex = src.DataRateIndex + dst.SecondChannelDataRateIndexAck = src.SecondChannelDataRateIndexAck } else { - dst.DataRateIndex = 0 + var zero bool + dst.SecondChannelDataRateIndexAck = zero } - case "max_retries": + case "second_channel_index_ack": if len(subs) > 0 { - return fmt.Errorf("'max_retries' has no subfields, but %s were specified", subs) + return fmt.Errorf("'second_channel_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxRetries = src.MaxRetries + dst.SecondChannelIndexAck = src.SecondChannelIndexAck } else { - var zero uint32 - dst.MaxRetries = zero + var zero bool + dst.SecondChannelIndexAck = zero } - case "period_exponent": + case "backoff_ack": if len(subs) > 0 { - return fmt.Errorf("'period_exponent' has no subfields, but %s were specified", subs) + return fmt.Errorf("'backoff_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.PeriodExponent = src.PeriodExponent + dst.BackoffAck = src.BackoffAck } else { - dst.PeriodExponent = 0 + var zero bool + dst.BackoffAck = zero } default: @@ -3527,97 +4653,90 @@ func (dst *MACCommand_ForceRejoinReq) SetFields(src *MACCommand_ForceRejoinReq, return nil } -func (dst *MACCommand_RejoinParamSetupReq) SetFields(src *MACCommand_RejoinParamSetupReq, paths ...string) error { +func (dst *MACCommand_RelayUpdateUplinkListReq) SetFields(src *MACCommand_RelayUpdateUplinkListReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "max_count_exponent": + case "rule_index": if len(subs) > 0 { - return fmt.Errorf("'max_count_exponent' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rule_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxCountExponent = src.MaxCountExponent + dst.RuleIndex = src.RuleIndex } else { - dst.MaxCountExponent = 0 + var zero uint32 + dst.RuleIndex = zero } - case "max_time_exponent": + case "forward_limits": if len(subs) > 0 { - return fmt.Errorf("'max_time_exponent' has no subfields, but %s were specified", subs) + var newDst, newSrc *RelayUplinkForwardLimits + if (src == nil || src.ForwardLimits == nil) && dst.ForwardLimits == nil { + continue + } + if src != nil { + newSrc = src.ForwardLimits + } + if dst.ForwardLimits != nil { + newDst = dst.ForwardLimits + } else { + newDst = &RelayUplinkForwardLimits{} + dst.ForwardLimits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.ForwardLimits = src.ForwardLimits + } else { + dst.ForwardLimits = nil + } + } + case "dev_addr": + if len(subs) > 0 { + return fmt.Errorf("'dev_addr' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxTimeExponent = src.MaxTimeExponent + dst.DevAddr = src.DevAddr } else { - dst.MaxTimeExponent = 0 + dst.DevAddr = nil } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *MACCommand_RejoinParamSetupAns) SetFields(src *MACCommand_RejoinParamSetupAns, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "max_time_exponent_ack": + case "w_f_cnt": if len(subs) > 0 { - return fmt.Errorf("'max_time_exponent_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'w_f_cnt' has no subfields, but %s were specified", subs) } if src != nil { - dst.MaxTimeExponentAck = src.MaxTimeExponentAck + dst.WFCnt = src.WFCnt } else { - var zero bool - dst.MaxTimeExponentAck = zero + var zero uint32 + dst.WFCnt = zero } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *MACCommand_PingSlotInfoReq) SetFields(src *MACCommand_PingSlotInfoReq, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "period": + case "root_wor_s_key": if len(subs) > 0 { - return fmt.Errorf("'period' has no subfields, but %s were specified", subs) + return fmt.Errorf("'root_wor_s_key' has no subfields, but %s were specified", subs) } if src != nil { - dst.Period = src.Period + dst.RootWorSKey = src.RootWorSKey } else { - dst.Period = 0 + dst.RootWorSKey = nil } - - default: - return fmt.Errorf("invalid field: '%s'", name) - } - } - return nil -} - -func (dst *MACCommand_PingSlotChannelReq) SetFields(src *MACCommand_PingSlotChannelReq, paths ...string) error { - for name, subs := range _processPaths(paths) { - switch name { - case "frequency": + case "device_id": if len(subs) > 0 { - return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + return fmt.Errorf("'device_id' has no subfields, but %s were specified", subs) } if src != nil { - dst.Frequency = src.Frequency + dst.DeviceId = src.DeviceId } else { - var zero uint64 - dst.Frequency = zero + var zero string + dst.DeviceId = zero } - case "data_rate_index": + case "session_key_id": if len(subs) > 0 { - return fmt.Errorf("'data_rate_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'session_key_id' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateIndex = src.DataRateIndex + dst.SessionKeyId = src.SessionKeyId } else { - dst.DataRateIndex = 0 + dst.SessionKeyId = nil } default: @@ -3627,28 +4746,34 @@ func (dst *MACCommand_PingSlotChannelReq) SetFields(src *MACCommand_PingSlotChan return nil } -func (dst *MACCommand_PingSlotChannelAns) SetFields(src *MACCommand_PingSlotChannelAns, paths ...string) error { +func (dst *MACCommand_RelayUpdateUplinkListAns) SetFields(src *MACCommand_RelayUpdateUplinkListAns, paths ...string) error { + if len(paths) != 0 { + return fmt.Errorf("message MACCommand_RelayUpdateUplinkListAns has no fields, but paths %s were specified", paths) + } + return nil +} + +func (dst *MACCommand_RelayCtrlUplinkListReq) SetFields(src *MACCommand_RelayCtrlUplinkListReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "frequency_ack": + case "rule_index": if len(subs) > 0 { - return fmt.Errorf("'frequency_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rule_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.FrequencyAck = src.FrequencyAck + dst.RuleIndex = src.RuleIndex } else { - var zero bool - dst.FrequencyAck = zero + var zero uint32 + dst.RuleIndex = zero } - case "data_rate_index_ack": + case "action": if len(subs) > 0 { - return fmt.Errorf("'data_rate_index_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'action' has no subfields, but %s were specified", subs) } if src != nil { - dst.DataRateIndexAck = src.DataRateIndexAck + dst.Action = src.Action } else { - var zero bool - dst.DataRateIndexAck = zero + dst.Action = 0 } default: @@ -3658,28 +4783,28 @@ func (dst *MACCommand_PingSlotChannelAns) SetFields(src *MACCommand_PingSlotChan return nil } -func (dst *MACCommand_BeaconTimingAns) SetFields(src *MACCommand_BeaconTimingAns, paths ...string) error { +func (dst *MACCommand_RelayCtrlUplinkListAns) SetFields(src *MACCommand_RelayCtrlUplinkListAns, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "delay": + case "rule_index_ack": if len(subs) > 0 { - return fmt.Errorf("'delay' has no subfields, but %s were specified", subs) + return fmt.Errorf("'rule_index_ack' has no subfields, but %s were specified", subs) } if src != nil { - dst.Delay = src.Delay + dst.RuleIndexAck = src.RuleIndexAck } else { - var zero uint32 - dst.Delay = zero + var zero bool + dst.RuleIndexAck = zero } - case "channel_index": + case "w_f_cnt": if len(subs) > 0 { - return fmt.Errorf("'channel_index' has no subfields, but %s were specified", subs) + return fmt.Errorf("'w_f_cnt' has no subfields, but %s were specified", subs) } if src != nil { - dst.ChannelIndex = src.ChannelIndex + dst.WFCnt = src.WFCnt } else { var zero uint32 - dst.ChannelIndex = zero + dst.WFCnt = zero } default: @@ -3689,18 +4814,117 @@ func (dst *MACCommand_BeaconTimingAns) SetFields(src *MACCommand_BeaconTimingAns return nil } -func (dst *MACCommand_BeaconFreqReq) SetFields(src *MACCommand_BeaconFreqReq, paths ...string) error { +func (dst *MACCommand_RelayConfigureFwdLimitReq) SetFields(src *MACCommand_RelayConfigureFwdLimitReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "frequency": + case "reset_limit_counter": if len(subs) > 0 { - return fmt.Errorf("'frequency' has no subfields, but %s were specified", subs) + return fmt.Errorf("'reset_limit_counter' has no subfields, but %s were specified", subs) } if src != nil { - dst.Frequency = src.Frequency + dst.ResetLimitCounter = src.ResetLimitCounter } else { - var zero uint64 - dst.Frequency = zero + dst.ResetLimitCounter = 0 + } + case "join_request_limits": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.JoinRequestLimits == nil) && dst.JoinRequestLimits == nil { + continue + } + if src != nil { + newSrc = src.JoinRequestLimits + } + if dst.JoinRequestLimits != nil { + newDst = dst.JoinRequestLimits + } else { + newDst = &RelayForwardLimits{} + dst.JoinRequestLimits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.JoinRequestLimits = src.JoinRequestLimits + } else { + dst.JoinRequestLimits = nil + } + } + case "notify_limits": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.NotifyLimits == nil) && dst.NotifyLimits == nil { + continue + } + if src != nil { + newSrc = src.NotifyLimits + } + if dst.NotifyLimits != nil { + newDst = dst.NotifyLimits + } else { + newDst = &RelayForwardLimits{} + dst.NotifyLimits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.NotifyLimits = src.NotifyLimits + } else { + dst.NotifyLimits = nil + } + } + case "global_uplink_limits": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.GlobalUplinkLimits == nil) && dst.GlobalUplinkLimits == nil { + continue + } + if src != nil { + newSrc = src.GlobalUplinkLimits + } + if dst.GlobalUplinkLimits != nil { + newDst = dst.GlobalUplinkLimits + } else { + newDst = &RelayForwardLimits{} + dst.GlobalUplinkLimits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.GlobalUplinkLimits = src.GlobalUplinkLimits + } else { + dst.GlobalUplinkLimits = nil + } + } + case "overall_limits": + if len(subs) > 0 { + var newDst, newSrc *RelayForwardLimits + if (src == nil || src.OverallLimits == nil) && dst.OverallLimits == nil { + continue + } + if src != nil { + newSrc = src.OverallLimits + } + if dst.OverallLimits != nil { + newDst = dst.OverallLimits + } else { + newDst = &RelayForwardLimits{} + dst.OverallLimits = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.OverallLimits = src.OverallLimits + } else { + dst.OverallLimits = nil + } } default: @@ -3710,18 +4934,44 @@ func (dst *MACCommand_BeaconFreqReq) SetFields(src *MACCommand_BeaconFreqReq, pa return nil } -func (dst *MACCommand_BeaconFreqAns) SetFields(src *MACCommand_BeaconFreqAns, paths ...string) error { +func (dst *MACCommand_RelayConfigureFwdLimitAns) SetFields(src *MACCommand_RelayConfigureFwdLimitAns, paths ...string) error { + if len(paths) != 0 { + return fmt.Errorf("message MACCommand_RelayConfigureFwdLimitAns has no fields, but paths %s were specified", paths) + } + return nil +} + +func (dst *MACCommand_RelayNotifyNewEndDeviceReq) SetFields(src *MACCommand_RelayNotifyNewEndDeviceReq, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "frequency_ack": + case "dev_addr": if len(subs) > 0 { - return fmt.Errorf("'frequency_ack' has no subfields, but %s were specified", subs) + return fmt.Errorf("'dev_addr' has no subfields, but %s were specified", subs) } if src != nil { - dst.FrequencyAck = src.FrequencyAck + dst.DevAddr = src.DevAddr } else { - var zero bool - dst.FrequencyAck = zero + dst.DevAddr = nil + } + case "snr": + if len(subs) > 0 { + return fmt.Errorf("'snr' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Snr = src.Snr + } else { + var zero int32 + dst.Snr = zero + } + case "rssi": + if len(subs) > 0 { + return fmt.Errorf("'rssi' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.Rssi = src.Rssi + } else { + var zero int32 + dst.Rssi = zero } default: @@ -3731,17 +4981,52 @@ func (dst *MACCommand_BeaconFreqAns) SetFields(src *MACCommand_BeaconFreqAns, pa return nil } -func (dst *MACCommand_DeviceModeInd) SetFields(src *MACCommand_DeviceModeInd, paths ...string) error { +func (dst *MACCommand_RelayConfReq_Configuration) SetFields(src *MACCommand_RelayConfReq_Configuration, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "class": + case "second_channel": if len(subs) > 0 { - return fmt.Errorf("'class' has no subfields, but %s were specified", subs) + var newDst, newSrc *RelaySecondChannel + if (src == nil || src.SecondChannel == nil) && dst.SecondChannel == nil { + continue + } + if src != nil { + newSrc = src.SecondChannel + } + if dst.SecondChannel != nil { + newDst = dst.SecondChannel + } else { + newDst = &RelaySecondChannel{} + dst.SecondChannel = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.SecondChannel = src.SecondChannel + } else { + dst.SecondChannel = nil + } + } + case "default_channel_index": + if len(subs) > 0 { + return fmt.Errorf("'default_channel_index' has no subfields, but %s were specified", subs) } if src != nil { - dst.Class = src.Class + dst.DefaultChannelIndex = src.DefaultChannelIndex } else { - dst.Class = 0 + var zero uint32 + dst.DefaultChannelIndex = zero + } + case "cad_periodicity": + if len(subs) > 0 { + return fmt.Errorf("'cad_periodicity' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.CadPeriodicity = src.CadPeriodicity + } else { + dst.CadPeriodicity = 0 } default: @@ -3751,17 +5036,182 @@ func (dst *MACCommand_DeviceModeInd) SetFields(src *MACCommand_DeviceModeInd, pa return nil } -func (dst *MACCommand_DeviceModeConf) SetFields(src *MACCommand_DeviceModeConf, paths ...string) error { +func (dst *MACCommand_RelayEndDeviceConfReq_Configuration) SetFields(src *MACCommand_RelayEndDeviceConfReq_Configuration, paths ...string) error { for name, subs := range _processPaths(paths) { switch name { - case "class": + case "backoff": if len(subs) > 0 { - return fmt.Errorf("'class' has no subfields, but %s were specified", subs) + return fmt.Errorf("'backoff' has no subfields, but %s were specified", subs) } if src != nil { - dst.Class = src.Class + dst.Backoff = src.Backoff } else { - dst.Class = 0 + var zero uint32 + dst.Backoff = zero + } + case "second_channel": + if len(subs) > 0 { + var newDst, newSrc *RelaySecondChannel + if (src == nil || src.SecondChannel == nil) && dst.SecondChannel == nil { + continue + } + if src != nil { + newSrc = src.SecondChannel + } + if dst.SecondChannel != nil { + newDst = dst.SecondChannel + } else { + newDst = &RelaySecondChannel{} + dst.SecondChannel = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.SecondChannel = src.SecondChannel + } else { + dst.SecondChannel = nil + } + } + case "serving_device_id": + if len(subs) > 0 { + return fmt.Errorf("'serving_device_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.ServingDeviceId = src.ServingDeviceId + } else { + var zero string + dst.ServingDeviceId = zero + } + + case "mode": + if len(subs) == 0 && src == nil { + dst.Mode = nil + continue + } else if len(subs) == 0 { + dst.Mode = src.Mode + continue + } + + subPathMap := _processPaths(subs) + if len(subPathMap) > 1 { + return fmt.Errorf("more than one field specified for oneof field '%s'", name) + } + for oneofName, oneofSubs := range subPathMap { + switch oneofName { + case "always": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Always) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'always', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Always) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'always', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceAlwaysMode + if srcTypeOk { + newSrc = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Always).Always + } + if dstTypeOk { + newDst = dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Always).Always + } else if srcTypeOk { + newDst = &RelayEndDeviceAlwaysMode{} + dst.Mode = &MACCommand_RelayEndDeviceConfReq_Configuration_Always{Always: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + case "dynamic": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'dynamic', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'dynamic', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceDynamicMode + if srcTypeOk { + newSrc = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic).Dynamic + } + if dstTypeOk { + newDst = dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic).Dynamic + } else if srcTypeOk { + newDst = &RelayEndDeviceDynamicMode{} + dst.Mode = &MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic{Dynamic: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + case "end_device_controlled": + var srcTypeOk bool + if src != nil { + _, srcTypeOk = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled) + } + if srcValid := srcTypeOk || src == nil || src.Mode == nil || len(oneofSubs) == 0; !srcValid { + return fmt.Errorf("attempt to set oneof 'end_device_controlled', while different oneof is set in source") + } + _, dstTypeOk := dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled) + if dstValid := dstTypeOk || dst.Mode == nil || len(oneofSubs) == 0; !dstValid { + return fmt.Errorf("attempt to set oneof 'end_device_controlled', while different oneof is set in destination") + } + if len(oneofSubs) > 0 { + var newDst, newSrc *RelayEndDeviceControlledMode + if srcTypeOk { + newSrc = src.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled).EndDeviceControlled + } + if dstTypeOk { + newDst = dst.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled).EndDeviceControlled + } else if srcTypeOk { + newDst = &RelayEndDeviceControlledMode{} + dst.Mode = &MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled{EndDeviceControlled: newDst} + } else { + dst.Mode = nil + continue + } + if err := newDst.SetFields(newSrc, oneofSubs...); err != nil { + return err + } + } else { + if srcTypeOk { + dst.Mode = src.Mode + } else { + dst.Mode = nil + } + } + + default: + return fmt.Errorf("invalid oneof field: '%s.%s'", name, oneofName) + } } default: diff --git a/pkg/ttnpb/lorawan.pb.validate.go b/pkg/ttnpb/lorawan.pb.validate.go index cb1ee3b620..637c773803 100644 --- a/pkg/ttnpb/lorawan.pb.validate.go +++ b/pkg/ttnpb/lorawan.pb.validate.go @@ -2421,536 +2421,2649 @@ var _ interface { ErrorName() string } = TxRequestValidationError{} -// ValidateFields checks the field values on MACCommand with the rules defined -// in the proto definition for this message. If any rules are violated, an -// error is returned. -func (m *MACCommand) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on RelaySecondChannel with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelaySecondChannel) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommandFieldPathsNested + paths = RelaySecondChannelFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "cid": + case "ack_offset": - if _, ok := _MACCommand_Cid_NotInLookup[m.GetCid()]; ok { - return MACCommandValidationError{ - field: "cid", - reason: "value must not be in list [0]", + if _, ok := RelaySecondChAckOffset_name[int32(m.GetAckOffset())]; !ok { + return RelaySecondChannelValidationError{ + field: "ack_offset", + reason: "value must be one of the defined enum values", } } - if _, ok := MACCommandIdentifier_name[int32(m.GetCid())]; !ok { - return MACCommandValidationError{ - field: "cid", + case "data_rate_index": + + if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { + return RelaySecondChannelValidationError{ + field: "data_rate_index", reason: "value must be one of the defined enum values", } } - case "payload": - if len(subs) == 0 { - subs = []string{ - "raw_payload", "reset_ind", "reset_conf", "link_check_ans", "link_adr_req", "link_adr_ans", "duty_cycle_req", "rx_param_setup_req", "rx_param_setup_ans", "dev_status_ans", "new_channel_req", "new_channel_ans", "dl_channel_req", "dl_channel_ans", "rx_timing_setup_req", "tx_param_setup_req", "rekey_ind", "rekey_conf", "adr_param_setup_req", "device_time_ans", "force_rejoin_req", "rejoin_param_setup_req", "rejoin_param_setup_ans", "ping_slot_info_req", "ping_slot_channel_req", "ping_slot_channel_ans", "beacon_timing_ans", "beacon_freq_req", "beacon_freq_ans", "device_mode_ind", "device_mode_conf", + case "frequency": + + if m.GetFrequency() < 100000 { + return RelaySecondChannelValidationError{ + field: "frequency", + reason: "value must be greater than or equal to 100000", } } - for name, subs := range _processPaths(subs) { - _ = subs - switch name { - case "raw_payload": - w, ok := m.Payload.(*MACCommand_RawPayload) - if !ok || w == nil { - continue - } - // no validation rules for RawPayload - case "reset_ind": - w, ok := m.Payload.(*MACCommand_ResetInd_) - if !ok || w == nil { - continue - } - if v, ok := interface{}(m.GetResetInd()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "reset_ind", - reason: "embedded message failed validation", - cause: err, - } - } - } + default: + return RelaySecondChannelValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} - case "reset_conf": - w, ok := m.Payload.(*MACCommand_ResetConf_) - if !ok || w == nil { - continue - } +// RelaySecondChannelValidationError is the validation error returned by +// RelaySecondChannel.ValidateFields if the designated constraints aren't met. +type RelaySecondChannelValidationError struct { + field string + reason string + cause error + key bool +} - if v, ok := interface{}(m.GetResetConf()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "reset_conf", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Field function returns field value. +func (e RelaySecondChannelValidationError) Field() string { return e.field } - case "link_check_ans": - w, ok := m.Payload.(*MACCommand_LinkCheckAns_) - if !ok || w == nil { - continue - } +// Reason function returns reason value. +func (e RelaySecondChannelValidationError) Reason() string { return e.reason } - if v, ok := interface{}(m.GetLinkCheckAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "link_check_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Cause function returns cause value. +func (e RelaySecondChannelValidationError) Cause() error { return e.cause } - case "link_adr_req": - w, ok := m.Payload.(*MACCommand_LinkAdrReq) - if !ok || w == nil { - continue - } +// Key function returns key value. +func (e RelaySecondChannelValidationError) Key() bool { return e.key } - if v, ok := interface{}(m.GetLinkAdrReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "link_adr_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ErrorName returns error name. +func (e RelaySecondChannelValidationError) ErrorName() string { + return "RelaySecondChannelValidationError" +} - case "link_adr_ans": - w, ok := m.Payload.(*MACCommand_LinkAdrAns) - if !ok || w == nil { - continue - } +// Error satisfies the builtin error interface +func (e RelaySecondChannelValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } - if v, ok := interface{}(m.GetLinkAdrAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "link_adr_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } + key := "" + if e.key { + key = "key for " + } - case "duty_cycle_req": - w, ok := m.Payload.(*MACCommand_DutyCycleReq_) - if !ok || w == nil { - continue - } + return fmt.Sprintf( + "invalid %sRelaySecondChannel.%s: %s%s", + key, + e.field, + e.reason, + cause) +} - if v, ok := interface{}(m.GetDutyCycleReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "duty_cycle_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +var _ error = RelaySecondChannelValidationError{} - case "rx_param_setup_req": - w, ok := m.Payload.(*MACCommand_RxParamSetupReq_) - if !ok || w == nil { - continue - } +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelaySecondChannelValidationError{} - if v, ok := interface{}(m.GetRxParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rx_param_setup_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ValidateFields checks the field values on RelayUplinkForwardLimits with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayUplinkForwardLimits) ValidateFields(paths ...string) error { + if m == nil { + return nil + } - case "rx_param_setup_ans": - w, ok := m.Payload.(*MACCommand_RxParamSetupAns_) - if !ok || w == nil { - continue - } + if len(paths) == 0 { + paths = RelayUplinkForwardLimitsFieldPathsNested + } - if v, ok := interface{}(m.GetRxParamSetupAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rx_param_setup_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "bucket_size": - case "dev_status_ans": - w, ok := m.Payload.(*MACCommand_DevStatusAns_) - if !ok || w == nil { - continue - } + if _, ok := RelayLimitBucketSize_name[int32(m.GetBucketSize())]; !ok { + return RelayUplinkForwardLimitsValidationError{ + field: "bucket_size", + reason: "value must be one of the defined enum values", + } + } - if v, ok := interface{}(m.GetDevStatusAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "dev_status_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } + case "reload_rate": - case "new_channel_req": - w, ok := m.Payload.(*MACCommand_NewChannelReq_) - if !ok || w == nil { - continue - } + if m.GetReloadRate() > 62 { + return RelayUplinkForwardLimitsValidationError{ + field: "reload_rate", + reason: "value must be less than or equal to 62", + } + } - if v, ok := interface{}(m.GetNewChannelReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "new_channel_req", - reason: "embedded message failed validation", - cause: err, - } - } - } + default: + return RelayUplinkForwardLimitsValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} - case "new_channel_ans": - w, ok := m.Payload.(*MACCommand_NewChannelAns_) - if !ok || w == nil { - continue - } +// RelayUplinkForwardLimitsValidationError is the validation error returned by +// RelayUplinkForwardLimits.ValidateFields if the designated constraints +// aren't met. +type RelayUplinkForwardLimitsValidationError struct { + field string + reason string + cause error + key bool +} - if v, ok := interface{}(m.GetNewChannelAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "new_channel_ans", - reason: "embedded message failed validation", +// Field function returns field value. +func (e RelayUplinkForwardLimitsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayUplinkForwardLimitsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayUplinkForwardLimitsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayUplinkForwardLimitsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayUplinkForwardLimitsValidationError) ErrorName() string { + return "RelayUplinkForwardLimitsValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayUplinkForwardLimitsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayUplinkForwardLimits.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayUplinkForwardLimitsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayUplinkForwardLimitsValidationError{} + +// ValidateFields checks the field values on RelayForwardLimits with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayForwardLimits) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayForwardLimitsFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "bucket_size": + + if _, ok := RelayLimitBucketSize_name[int32(m.GetBucketSize())]; !ok { + return RelayForwardLimitsValidationError{ + field: "bucket_size", + reason: "value must be one of the defined enum values", + } + } + + case "reload_rate": + + if m.GetReloadRate() > 126 { + return RelayForwardLimitsValidationError{ + field: "reload_rate", + reason: "value must be less than or equal to 126", + } + } + + default: + return RelayForwardLimitsValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayForwardLimitsValidationError is the validation error returned by +// RelayForwardLimits.ValidateFields if the designated constraints aren't met. +type RelayForwardLimitsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayForwardLimitsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayForwardLimitsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayForwardLimitsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayForwardLimitsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayForwardLimitsValidationError) ErrorName() string { + return "RelayForwardLimitsValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayForwardLimitsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayForwardLimits.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayForwardLimitsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayForwardLimitsValidationError{} + +// ValidateFields checks the field values on RelayEndDeviceAlwaysMode with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayEndDeviceAlwaysMode) ValidateFields(paths ...string) error { + if len(paths) > 0 { + return fmt.Errorf("message RelayEndDeviceAlwaysMode has no fields, but paths %s were specified", paths) + } + return nil +} + +// RelayEndDeviceAlwaysModeValidationError is the validation error returned by +// RelayEndDeviceAlwaysMode.ValidateFields if the designated constraints +// aren't met. +type RelayEndDeviceAlwaysModeValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayEndDeviceAlwaysModeValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayEndDeviceAlwaysModeValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayEndDeviceAlwaysModeValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayEndDeviceAlwaysModeValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayEndDeviceAlwaysModeValidationError) ErrorName() string { + return "RelayEndDeviceAlwaysModeValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayEndDeviceAlwaysModeValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayEndDeviceAlwaysMode.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayEndDeviceAlwaysModeValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayEndDeviceAlwaysModeValidationError{} + +// ValidateFields checks the field values on RelayEndDeviceDynamicMode with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayEndDeviceDynamicMode) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayEndDeviceDynamicModeFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "smart_enable_level": + + if _, ok := RelaySmartEnableLevel_name[int32(m.GetSmartEnableLevel())]; !ok { + return RelayEndDeviceDynamicModeValidationError{ + field: "smart_enable_level", + reason: "value must be one of the defined enum values", + } + } + + default: + return RelayEndDeviceDynamicModeValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayEndDeviceDynamicModeValidationError is the validation error returned by +// RelayEndDeviceDynamicMode.ValidateFields if the designated constraints +// aren't met. +type RelayEndDeviceDynamicModeValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayEndDeviceDynamicModeValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayEndDeviceDynamicModeValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayEndDeviceDynamicModeValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayEndDeviceDynamicModeValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayEndDeviceDynamicModeValidationError) ErrorName() string { + return "RelayEndDeviceDynamicModeValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayEndDeviceDynamicModeValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayEndDeviceDynamicMode.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayEndDeviceDynamicModeValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayEndDeviceDynamicModeValidationError{} + +// ValidateFields checks the field values on RelayEndDeviceControlledMode with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *RelayEndDeviceControlledMode) ValidateFields(paths ...string) error { + if len(paths) > 0 { + return fmt.Errorf("message RelayEndDeviceControlledMode has no fields, but paths %s were specified", paths) + } + return nil +} + +// RelayEndDeviceControlledModeValidationError is the validation error returned +// by RelayEndDeviceControlledMode.ValidateFields if the designated +// constraints aren't met. +type RelayEndDeviceControlledModeValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayEndDeviceControlledModeValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayEndDeviceControlledModeValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayEndDeviceControlledModeValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayEndDeviceControlledModeValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayEndDeviceControlledModeValidationError) ErrorName() string { + return "RelayEndDeviceControlledModeValidationError" +} + +// Error satisfies the builtin error interface +func (e RelayEndDeviceControlledModeValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayEndDeviceControlledMode.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayEndDeviceControlledModeValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayEndDeviceControlledModeValidationError{} + +// ValidateFields checks the field values on MACCommand with the rules defined +// in the proto definition for this message. If any rules are violated, an +// error is returned. +func (m *MACCommand) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = MACCommandFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "cid": + + if _, ok := _MACCommand_Cid_NotInLookup[m.GetCid()]; ok { + return MACCommandValidationError{ + field: "cid", + reason: "value must not be in list [0]", + } + } + + if _, ok := MACCommandIdentifier_name[int32(m.GetCid())]; !ok { + return MACCommandValidationError{ + field: "cid", + reason: "value must be one of the defined enum values", + } + } + + case "payload": + if len(subs) == 0 { + subs = []string{ + "raw_payload", "reset_ind", "reset_conf", "link_check_ans", "link_adr_req", "link_adr_ans", "duty_cycle_req", "rx_param_setup_req", "rx_param_setup_ans", "dev_status_ans", "new_channel_req", "new_channel_ans", "dl_channel_req", "dl_channel_ans", "rx_timing_setup_req", "tx_param_setup_req", "rekey_ind", "rekey_conf", "adr_param_setup_req", "device_time_ans", "force_rejoin_req", "rejoin_param_setup_req", "rejoin_param_setup_ans", "ping_slot_info_req", "ping_slot_channel_req", "ping_slot_channel_ans", "beacon_timing_ans", "beacon_freq_req", "beacon_freq_ans", "device_mode_ind", "device_mode_conf", "relay_conf_req", "relay_conf_ans", "relay_end_device_conf_req", "relay_end_device_conf_ans", "relay_update_uplink_list_req", "relay_update_uplink_list_ans", "relay_ctrl_uplink_list_req", "relay_ctrl_uplink_list_ans", "relay_configure_fwd_limit_req", "relay_configure_fwd_limit_ans", "relay_notify_new_end_device_req", + } + } + for name, subs := range _processPaths(subs) { + _ = subs + switch name { + case "raw_payload": + w, ok := m.Payload.(*MACCommand_RawPayload) + if !ok || w == nil { + continue + } + // no validation rules for RawPayload + case "reset_ind": + w, ok := m.Payload.(*MACCommand_ResetInd_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetResetInd()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "reset_ind", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "reset_conf": + w, ok := m.Payload.(*MACCommand_ResetConf_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetResetConf()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "reset_conf", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "link_check_ans": + w, ok := m.Payload.(*MACCommand_LinkCheckAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetLinkCheckAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "link_check_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "link_adr_req": + w, ok := m.Payload.(*MACCommand_LinkAdrReq) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetLinkAdrReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "link_adr_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "link_adr_ans": + w, ok := m.Payload.(*MACCommand_LinkAdrAns) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetLinkAdrAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "link_adr_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "duty_cycle_req": + w, ok := m.Payload.(*MACCommand_DutyCycleReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDutyCycleReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "duty_cycle_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rx_param_setup_req": + w, ok := m.Payload.(*MACCommand_RxParamSetupReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRxParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rx_param_setup_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rx_param_setup_ans": + w, ok := m.Payload.(*MACCommand_RxParamSetupAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRxParamSetupAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rx_param_setup_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dev_status_ans": + w, ok := m.Payload.(*MACCommand_DevStatusAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDevStatusAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "dev_status_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "new_channel_req": + w, ok := m.Payload.(*MACCommand_NewChannelReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetNewChannelReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "new_channel_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "new_channel_ans": + w, ok := m.Payload.(*MACCommand_NewChannelAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetNewChannelAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "new_channel_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dl_channel_req": + w, ok := m.Payload.(*MACCommand_DlChannelReq) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDlChannelReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "dl_channel_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dl_channel_ans": + w, ok := m.Payload.(*MACCommand_DlChannelAns) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDlChannelAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "dl_channel_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rx_timing_setup_req": + w, ok := m.Payload.(*MACCommand_RxTimingSetupReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRxTimingSetupReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rx_timing_setup_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "tx_param_setup_req": + w, ok := m.Payload.(*MACCommand_TxParamSetupReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetTxParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "tx_param_setup_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rekey_ind": + w, ok := m.Payload.(*MACCommand_RekeyInd_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRekeyInd()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rekey_ind", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rekey_conf": + w, ok := m.Payload.(*MACCommand_RekeyConf_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRekeyConf()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rekey_conf", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "adr_param_setup_req": + w, ok := m.Payload.(*MACCommand_AdrParamSetupReq) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetAdrParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "adr_param_setup_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "device_time_ans": + w, ok := m.Payload.(*MACCommand_DeviceTimeAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDeviceTimeAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "device_time_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "force_rejoin_req": + w, ok := m.Payload.(*MACCommand_ForceRejoinReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetForceRejoinReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "force_rejoin_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rejoin_param_setup_req": + w, ok := m.Payload.(*MACCommand_RejoinParamSetupReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRejoinParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rejoin_param_setup_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "rejoin_param_setup_ans": + w, ok := m.Payload.(*MACCommand_RejoinParamSetupAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRejoinParamSetupAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "rejoin_param_setup_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "ping_slot_info_req": + w, ok := m.Payload.(*MACCommand_PingSlotInfoReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetPingSlotInfoReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "ping_slot_info_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "ping_slot_channel_req": + w, ok := m.Payload.(*MACCommand_PingSlotChannelReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetPingSlotChannelReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "ping_slot_channel_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "ping_slot_channel_ans": + w, ok := m.Payload.(*MACCommand_PingSlotChannelAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetPingSlotChannelAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "ping_slot_channel_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "beacon_timing_ans": + w, ok := m.Payload.(*MACCommand_BeaconTimingAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetBeaconTimingAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "beacon_timing_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "beacon_freq_req": + w, ok := m.Payload.(*MACCommand_BeaconFreqReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetBeaconFreqReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "beacon_freq_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "beacon_freq_ans": + w, ok := m.Payload.(*MACCommand_BeaconFreqAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetBeaconFreqAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "beacon_freq_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "device_mode_ind": + w, ok := m.Payload.(*MACCommand_DeviceModeInd_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDeviceModeInd()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "device_mode_ind", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "device_mode_conf": + w, ok := m.Payload.(*MACCommand_DeviceModeConf_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDeviceModeConf()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "device_mode_conf", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_conf_req": + w, ok := m.Payload.(*MACCommand_RelayConfReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayConfReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_conf_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_conf_ans": + w, ok := m.Payload.(*MACCommand_RelayConfAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayConfAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_conf_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_end_device_conf_req": + w, ok := m.Payload.(*MACCommand_RelayEndDeviceConfReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayEndDeviceConfReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_end_device_conf_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_end_device_conf_ans": + w, ok := m.Payload.(*MACCommand_RelayEndDeviceConfAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayEndDeviceConfAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_end_device_conf_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_update_uplink_list_req": + w, ok := m.Payload.(*MACCommand_RelayUpdateUplinkListReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayUpdateUplinkListReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_update_uplink_list_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_update_uplink_list_ans": + w, ok := m.Payload.(*MACCommand_RelayUpdateUplinkListAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayUpdateUplinkListAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_update_uplink_list_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_ctrl_uplink_list_req": + w, ok := m.Payload.(*MACCommand_RelayCtrlUplinkListReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayCtrlUplinkListReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_ctrl_uplink_list_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_ctrl_uplink_list_ans": + w, ok := m.Payload.(*MACCommand_RelayCtrlUplinkListAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayCtrlUplinkListAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_ctrl_uplink_list_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_configure_fwd_limit_req": + w, ok := m.Payload.(*MACCommand_RelayConfigureFwdLimitReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayConfigureFwdLimitReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_configure_fwd_limit_req", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_configure_fwd_limit_ans": + w, ok := m.Payload.(*MACCommand_RelayConfigureFwdLimitAns_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayConfigureFwdLimitAns()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_configure_fwd_limit_ans", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "relay_notify_new_end_device_req": + w, ok := m.Payload.(*MACCommand_RelayNotifyNewEndDeviceReq_) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetRelayNotifyNewEndDeviceReq()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandValidationError{ + field: "relay_notify_new_end_device_req", + reason: "embedded message failed validation", cause: err, } } } - case "dl_channel_req": - w, ok := m.Payload.(*MACCommand_DlChannelReq) - if !ok || w == nil { - continue - } + } + } + default: + return MACCommandValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// MACCommandValidationError is the validation error returned by +// MACCommand.ValidateFields if the designated constraints aren't met. +type MACCommandValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MACCommandValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e MACCommandValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e MACCommandValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MACCommandValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MACCommandValidationError) ErrorName() string { return "MACCommandValidationError" } + +// Error satisfies the builtin error interface +func (e MACCommandValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMACCommand.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = MACCommandValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MACCommandValidationError{} + +var _MACCommand_Cid_NotInLookup = map[MACCommandIdentifier]struct{}{ + 0: {}, +} + +// ValidateFields checks the field values on MACCommands with the rules defined +// in the proto definition for this message. If any rules are violated, an +// error is returned. +func (m *MACCommands) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = MACCommandsFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "commands": + + for idx, item := range m.GetCommands() { + _, _ = idx, item + + if v, ok := interface{}(item).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommandsValidationError{ + field: fmt.Sprintf("commands[%v]", idx), + reason: "embedded message failed validation", + cause: err, + } + } + } + + } + + default: + return MACCommandsValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// MACCommandsValidationError is the validation error returned by +// MACCommands.ValidateFields if the designated constraints aren't met. +type MACCommandsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MACCommandsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e MACCommandsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e MACCommandsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MACCommandsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MACCommandsValidationError) ErrorName() string { return "MACCommandsValidationError" } + +// Error satisfies the builtin error interface +func (e MACCommandsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMACCommands.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = MACCommandsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MACCommandsValidationError{} + +// ValidateFields checks the field values on FrequencyValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *FrequencyValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = FrequencyValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if m.GetValue() < 100000 { + return FrequencyValueValidationError{ + field: "value", + reason: "value must be greater than or equal to 100000", + } + } + + default: + return FrequencyValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// FrequencyValueValidationError is the validation error returned by +// FrequencyValue.ValidateFields if the designated constraints aren't met. +type FrequencyValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e FrequencyValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e FrequencyValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e FrequencyValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e FrequencyValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e FrequencyValueValidationError) ErrorName() string { return "FrequencyValueValidationError" } + +// Error satisfies the builtin error interface +func (e FrequencyValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sFrequencyValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = FrequencyValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = FrequencyValueValidationError{} + +// ValidateFields checks the field values on ZeroableFrequencyValue with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *ZeroableFrequencyValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ZeroableFrequencyValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if val := m.GetValue(); val > 0 && val < 100000 { + return ZeroableFrequencyValueValidationError{ + field: "value", + reason: "value must be outside range (0, 100000)", + } + } + + default: + return ZeroableFrequencyValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ZeroableFrequencyValueValidationError is the validation error returned by +// ZeroableFrequencyValue.ValidateFields if the designated constraints aren't met. +type ZeroableFrequencyValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ZeroableFrequencyValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ZeroableFrequencyValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ZeroableFrequencyValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ZeroableFrequencyValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ZeroableFrequencyValueValidationError) ErrorName() string { + return "ZeroableFrequencyValueValidationError" +} + +// Error satisfies the builtin error interface +func (e ZeroableFrequencyValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sZeroableFrequencyValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ZeroableFrequencyValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ZeroableFrequencyValueValidationError{} + +// ValidateFields checks the field values on DataRateOffsetValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *DataRateOffsetValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = DataRateOffsetValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := DataRateOffset_name[int32(m.GetValue())]; !ok { + return DataRateOffsetValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return DataRateOffsetValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// DataRateOffsetValueValidationError is the validation error returned by +// DataRateOffsetValue.ValidateFields if the designated constraints aren't met. +type DataRateOffsetValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DataRateOffsetValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DataRateOffsetValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DataRateOffsetValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DataRateOffsetValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DataRateOffsetValueValidationError) ErrorName() string { + return "DataRateOffsetValueValidationError" +} + +// Error satisfies the builtin error interface +func (e DataRateOffsetValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDataRateOffsetValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = DataRateOffsetValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DataRateOffsetValueValidationError{} + +// ValidateFields checks the field values on DataRateIndexValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *DataRateIndexValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = DataRateIndexValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := DataRateIndex_name[int32(m.GetValue())]; !ok { + return DataRateIndexValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return DataRateIndexValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// DataRateIndexValueValidationError is the validation error returned by +// DataRateIndexValue.ValidateFields if the designated constraints aren't met. +type DataRateIndexValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DataRateIndexValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DataRateIndexValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DataRateIndexValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DataRateIndexValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DataRateIndexValueValidationError) ErrorName() string { + return "DataRateIndexValueValidationError" +} + +// Error satisfies the builtin error interface +func (e DataRateIndexValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDataRateIndexValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = DataRateIndexValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DataRateIndexValueValidationError{} + +// ValidateFields checks the field values on PingSlotPeriodValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *PingSlotPeriodValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = PingSlotPeriodValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := PingSlotPeriod_name[int32(m.GetValue())]; !ok { + return PingSlotPeriodValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return PingSlotPeriodValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// PingSlotPeriodValueValidationError is the validation error returned by +// PingSlotPeriodValue.ValidateFields if the designated constraints aren't met. +type PingSlotPeriodValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e PingSlotPeriodValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e PingSlotPeriodValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e PingSlotPeriodValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e PingSlotPeriodValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e PingSlotPeriodValueValidationError) ErrorName() string { + return "PingSlotPeriodValueValidationError" +} + +// Error satisfies the builtin error interface +func (e PingSlotPeriodValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sPingSlotPeriodValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = PingSlotPeriodValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = PingSlotPeriodValueValidationError{} + +// ValidateFields checks the field values on AggregatedDutyCycleValue with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *AggregatedDutyCycleValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = AggregatedDutyCycleValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := AggregatedDutyCycle_name[int32(m.GetValue())]; !ok { + return AggregatedDutyCycleValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return AggregatedDutyCycleValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// AggregatedDutyCycleValueValidationError is the validation error returned by +// AggregatedDutyCycleValue.ValidateFields if the designated constraints +// aren't met. +type AggregatedDutyCycleValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e AggregatedDutyCycleValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e AggregatedDutyCycleValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e AggregatedDutyCycleValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e AggregatedDutyCycleValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e AggregatedDutyCycleValueValidationError) ErrorName() string { + return "AggregatedDutyCycleValueValidationError" +} + +// Error satisfies the builtin error interface +func (e AggregatedDutyCycleValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sAggregatedDutyCycleValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = AggregatedDutyCycleValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = AggregatedDutyCycleValueValidationError{} + +// ValidateFields checks the field values on RxDelayValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RxDelayValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RxDelayValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := RxDelay_name[int32(m.GetValue())]; !ok { + return RxDelayValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return RxDelayValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RxDelayValueValidationError is the validation error returned by +// RxDelayValue.ValidateFields if the designated constraints aren't met. +type RxDelayValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RxDelayValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RxDelayValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RxDelayValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RxDelayValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RxDelayValueValidationError) ErrorName() string { return "RxDelayValueValidationError" } + +// Error satisfies the builtin error interface +func (e RxDelayValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRxDelayValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RxDelayValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RxDelayValueValidationError{} + +// ValidateFields checks the field values on ADRAckLimitExponentValue with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *ADRAckLimitExponentValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ADRAckLimitExponentValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := ADRAckLimitExponent_name[int32(m.GetValue())]; !ok { + return ADRAckLimitExponentValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return ADRAckLimitExponentValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ADRAckLimitExponentValueValidationError is the validation error returned by +// ADRAckLimitExponentValue.ValidateFields if the designated constraints +// aren't met. +type ADRAckLimitExponentValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ADRAckLimitExponentValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ADRAckLimitExponentValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ADRAckLimitExponentValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ADRAckLimitExponentValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ADRAckLimitExponentValueValidationError) ErrorName() string { + return "ADRAckLimitExponentValueValidationError" +} + +// Error satisfies the builtin error interface +func (e ADRAckLimitExponentValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sADRAckLimitExponentValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ADRAckLimitExponentValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ADRAckLimitExponentValueValidationError{} + +// ValidateFields checks the field values on ADRAckDelayExponentValue with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *ADRAckDelayExponentValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = ADRAckDelayExponentValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := ADRAckDelayExponent_name[int32(m.GetValue())]; !ok { + return ADRAckDelayExponentValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return ADRAckDelayExponentValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// ADRAckDelayExponentValueValidationError is the validation error returned by +// ADRAckDelayExponentValue.ValidateFields if the designated constraints +// aren't met. +type ADRAckDelayExponentValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e ADRAckDelayExponentValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e ADRAckDelayExponentValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e ADRAckDelayExponentValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e ADRAckDelayExponentValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e ADRAckDelayExponentValueValidationError) ErrorName() string { + return "ADRAckDelayExponentValueValidationError" +} + +// Error satisfies the builtin error interface +func (e ADRAckDelayExponentValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sADRAckDelayExponentValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = ADRAckDelayExponentValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = ADRAckDelayExponentValueValidationError{} + +// ValidateFields checks the field values on DeviceEIRPValue with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *DeviceEIRPValue) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = DeviceEIRPValueFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "value": + + if _, ok := DeviceEIRP_name[int32(m.GetValue())]; !ok { + return DeviceEIRPValueValidationError{ + field: "value", + reason: "value must be one of the defined enum values", + } + } + + default: + return DeviceEIRPValueValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// DeviceEIRPValueValidationError is the validation error returned by +// DeviceEIRPValue.ValidateFields if the designated constraints aren't met. +type DeviceEIRPValueValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e DeviceEIRPValueValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e DeviceEIRPValueValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e DeviceEIRPValueValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e DeviceEIRPValueValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e DeviceEIRPValueValidationError) ErrorName() string { return "DeviceEIRPValueValidationError" } + +// Error satisfies the builtin error interface +func (e DeviceEIRPValueValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sDeviceEIRPValue.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = DeviceEIRPValueValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = DeviceEIRPValueValidationError{} + +// ValidateFields checks the field values on RelayForwardUplinkReq with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayForwardUplinkReq) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayForwardUplinkReqFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "data_rate": + + if m.GetDataRate() == nil { + return RelayForwardUplinkReqValidationError{ + field: "data_rate", + reason: "value is required", + } + } + + if v, ok := interface{}(m.GetDataRate()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RelayForwardUplinkReqValidationError{ + field: "data_rate", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "snr": + + if val := m.GetSnr(); val < -20 || val > 11 { + return RelayForwardUplinkReqValidationError{ + field: "snr", + reason: "value must be inside range [-20, 11]", + } + } + + case "rssi": + + if val := m.GetRssi(); val < -142 || val > -15 { + return RelayForwardUplinkReqValidationError{ + field: "rssi", + reason: "value must be inside range [-142, -15]", + } + } + + case "wor_channel": + + if _, ok := RelayWORChannel_name[int32(m.GetWorChannel())]; !ok { + return RelayForwardUplinkReqValidationError{ + field: "wor_channel", + reason: "value must be one of the defined enum values", + } + } + + case "frequency": + + if m.GetFrequency() < 100000 { + return RelayForwardUplinkReqValidationError{ + field: "frequency", + reason: "value must be greater than or equal to 100000", + } + } + + case "raw_payload": + // no validation rules for RawPayload + default: + return RelayForwardUplinkReqValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayForwardUplinkReqValidationError is the validation error returned by +// RelayForwardUplinkReq.ValidateFields if the designated constraints aren't met. +type RelayForwardUplinkReqValidationError struct { + field string + reason string + cause error + key bool +} - if v, ok := interface{}(m.GetDlChannelReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "dl_channel_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Field function returns field value. +func (e RelayForwardUplinkReqValidationError) Field() string { return e.field } - case "dl_channel_ans": - w, ok := m.Payload.(*MACCommand_DlChannelAns) - if !ok || w == nil { - continue - } +// Reason function returns reason value. +func (e RelayForwardUplinkReqValidationError) Reason() string { return e.reason } - if v, ok := interface{}(m.GetDlChannelAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "dl_channel_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Cause function returns cause value. +func (e RelayForwardUplinkReqValidationError) Cause() error { return e.cause } - case "rx_timing_setup_req": - w, ok := m.Payload.(*MACCommand_RxTimingSetupReq_) - if !ok || w == nil { - continue - } +// Key function returns key value. +func (e RelayForwardUplinkReqValidationError) Key() bool { return e.key } - if v, ok := interface{}(m.GetRxTimingSetupReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rx_timing_setup_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ErrorName returns error name. +func (e RelayForwardUplinkReqValidationError) ErrorName() string { + return "RelayForwardUplinkReqValidationError" +} - case "tx_param_setup_req": - w, ok := m.Payload.(*MACCommand_TxParamSetupReq_) - if !ok || w == nil { - continue - } +// Error satisfies the builtin error interface +func (e RelayForwardUplinkReqValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } - if v, ok := interface{}(m.GetTxParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "tx_param_setup_req", - reason: "embedded message failed validation", - cause: err, - } - } - } + key := "" + if e.key { + key = "key for " + } - case "rekey_ind": - w, ok := m.Payload.(*MACCommand_RekeyInd_) - if !ok || w == nil { - continue - } + return fmt.Sprintf( + "invalid %sRelayForwardUplinkReq.%s: %s%s", + key, + e.field, + e.reason, + cause) +} - if v, ok := interface{}(m.GetRekeyInd()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rekey_ind", - reason: "embedded message failed validation", - cause: err, - } - } - } +var _ error = RelayForwardUplinkReqValidationError{} - case "rekey_conf": - w, ok := m.Payload.(*MACCommand_RekeyConf_) - if !ok || w == nil { - continue - } +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayForwardUplinkReqValidationError{} - if v, ok := interface{}(m.GetRekeyConf()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rekey_conf", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ValidateFields checks the field values on RelayForwardDownlinkReq with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayForwardDownlinkReq) ValidateFields(paths ...string) error { + if m == nil { + return nil + } - case "adr_param_setup_req": - w, ok := m.Payload.(*MACCommand_AdrParamSetupReq) - if !ok || w == nil { - continue - } + if len(paths) == 0 { + paths = RelayForwardDownlinkReqFieldPathsNested + } - if v, ok := interface{}(m.GetAdrParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "adr_param_setup_req", - reason: "embedded message failed validation", - cause: err, - } - } - } + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "raw_payload": + // no validation rules for RawPayload + default: + return RelayForwardDownlinkReqValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} - case "device_time_ans": - w, ok := m.Payload.(*MACCommand_DeviceTimeAns_) - if !ok || w == nil { - continue - } +// RelayForwardDownlinkReqValidationError is the validation error returned by +// RelayForwardDownlinkReq.ValidateFields if the designated constraints aren't met. +type RelayForwardDownlinkReqValidationError struct { + field string + reason string + cause error + key bool +} - if v, ok := interface{}(m.GetDeviceTimeAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "device_time_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Field function returns field value. +func (e RelayForwardDownlinkReqValidationError) Field() string { return e.field } - case "force_rejoin_req": - w, ok := m.Payload.(*MACCommand_ForceRejoinReq_) - if !ok || w == nil { - continue - } +// Reason function returns reason value. +func (e RelayForwardDownlinkReqValidationError) Reason() string { return e.reason } - if v, ok := interface{}(m.GetForceRejoinReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "force_rejoin_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Cause function returns cause value. +func (e RelayForwardDownlinkReqValidationError) Cause() error { return e.cause } - case "rejoin_param_setup_req": - w, ok := m.Payload.(*MACCommand_RejoinParamSetupReq_) - if !ok || w == nil { - continue - } +// Key function returns key value. +func (e RelayForwardDownlinkReqValidationError) Key() bool { return e.key } - if v, ok := interface{}(m.GetRejoinParamSetupReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rejoin_param_setup_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ErrorName returns error name. +func (e RelayForwardDownlinkReqValidationError) ErrorName() string { + return "RelayForwardDownlinkReqValidationError" +} - case "rejoin_param_setup_ans": - w, ok := m.Payload.(*MACCommand_RejoinParamSetupAns_) - if !ok || w == nil { - continue - } +// Error satisfies the builtin error interface +func (e RelayForwardDownlinkReqValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } - if v, ok := interface{}(m.GetRejoinParamSetupAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "rejoin_param_setup_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } + key := "" + if e.key { + key = "key for " + } - case "ping_slot_info_req": - w, ok := m.Payload.(*MACCommand_PingSlotInfoReq_) - if !ok || w == nil { - continue - } + return fmt.Sprintf( + "invalid %sRelayForwardDownlinkReq.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayForwardDownlinkReqValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayForwardDownlinkReqValidationError{} + +// ValidateFields checks the field values on RelayUplinkToken with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayUplinkToken) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayUplinkTokenFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "ids": - if v, ok := interface{}(m.GetPingSlotInfoReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "ping_slot_info_req", - reason: "embedded message failed validation", - cause: err, - } - } - } + if m.GetIds() == nil { + return RelayUplinkTokenValidationError{ + field: "ids", + reason: "value is required", + } + } - case "ping_slot_channel_req": - w, ok := m.Payload.(*MACCommand_PingSlotChannelReq_) - if !ok || w == nil { - continue + if v, ok := interface{}(m.GetIds()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RelayUplinkTokenValidationError{ + field: "ids", + reason: "embedded message failed validation", + cause: err, } + } + } - if v, ok := interface{}(m.GetPingSlotChannelReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "ping_slot_channel_req", - reason: "embedded message failed validation", - cause: err, - } - } - } + case "session_key_id": + // no validation rules for SessionKeyId + case "full_f_cnt": + // no validation rules for FullFCnt + default: + return RelayUplinkTokenValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} - case "ping_slot_channel_ans": - w, ok := m.Payload.(*MACCommand_PingSlotChannelAns_) - if !ok || w == nil { - continue - } +// RelayUplinkTokenValidationError is the validation error returned by +// RelayUplinkToken.ValidateFields if the designated constraints aren't met. +type RelayUplinkTokenValidationError struct { + field string + reason string + cause error + key bool +} - if v, ok := interface{}(m.GetPingSlotChannelAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "ping_slot_channel_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Field function returns field value. +func (e RelayUplinkTokenValidationError) Field() string { return e.field } - case "beacon_timing_ans": - w, ok := m.Payload.(*MACCommand_BeaconTimingAns_) - if !ok || w == nil { - continue - } +// Reason function returns reason value. +func (e RelayUplinkTokenValidationError) Reason() string { return e.reason } - if v, ok := interface{}(m.GetBeaconTimingAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "beacon_timing_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } +// Cause function returns cause value. +func (e RelayUplinkTokenValidationError) Cause() error { return e.cause } - case "beacon_freq_req": - w, ok := m.Payload.(*MACCommand_BeaconFreqReq_) - if !ok || w == nil { - continue - } +// Key function returns key value. +func (e RelayUplinkTokenValidationError) Key() bool { return e.key } - if v, ok := interface{}(m.GetBeaconFreqReq()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "beacon_freq_req", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ErrorName returns error name. +func (e RelayUplinkTokenValidationError) ErrorName() string { return "RelayUplinkTokenValidationError" } - case "beacon_freq_ans": - w, ok := m.Payload.(*MACCommand_BeaconFreqAns_) - if !ok || w == nil { - continue - } +// Error satisfies the builtin error interface +func (e RelayUplinkTokenValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } - if v, ok := interface{}(m.GetBeaconFreqAns()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "beacon_freq_ans", - reason: "embedded message failed validation", - cause: err, - } - } - } + key := "" + if e.key { + key = "key for " + } - case "device_mode_ind": - w, ok := m.Payload.(*MACCommand_DeviceModeInd_) - if !ok || w == nil { - continue - } + return fmt.Sprintf( + "invalid %sRelayUplinkToken.%s: %s%s", + key, + e.field, + e.reason, + cause) +} - if v, ok := interface{}(m.GetDeviceModeInd()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "device_mode_ind", - reason: "embedded message failed validation", - cause: err, - } - } - } +var _ error = RelayUplinkTokenValidationError{} - case "device_mode_conf": - w, ok := m.Payload.(*MACCommand_DeviceModeConf_) - if !ok || w == nil { - continue - } +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayUplinkTokenValidationError{} - if v, ok := interface{}(m.GetDeviceModeConf()).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandValidationError{ - field: "device_mode_conf", - reason: "embedded message failed validation", - cause: err, - } - } - } +// ValidateFields checks the field values on TxSettings_Downlink with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *TxSettings_Downlink) ValidateFields(paths ...string) error { + if m == nil { + return nil + } - } - } + if len(paths) == 0 { + paths = TxSettings_DownlinkFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "antenna_index": + // no validation rules for AntennaIndex + case "tx_power": + // no validation rules for TxPower + case "invert_polarization": + // no validation rules for InvertPolarization default: - return MACCommandValidationError{ + return TxSettings_DownlinkValidationError{ field: name, reason: "invalid field path", } @@ -2959,9 +5072,9 @@ func (m *MACCommand) ValidateFields(paths ...string) error { return nil } -// MACCommandValidationError is the validation error returned by -// MACCommand.ValidateFields if the designated constraints aren't met. -type MACCommandValidationError struct { +// TxSettings_DownlinkValidationError is the validation error returned by +// TxSettings_Downlink.ValidateFields if the designated constraints aren't met. +type TxSettings_DownlinkValidationError struct { field string reason string cause error @@ -2969,22 +5082,24 @@ type MACCommandValidationError struct { } // Field function returns field value. -func (e MACCommandValidationError) Field() string { return e.field } +func (e TxSettings_DownlinkValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommandValidationError) Reason() string { return e.reason } +func (e TxSettings_DownlinkValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommandValidationError) Cause() error { return e.cause } +func (e TxSettings_DownlinkValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommandValidationError) Key() bool { return e.key } +func (e TxSettings_DownlinkValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommandValidationError) ErrorName() string { return "MACCommandValidationError" } +func (e TxSettings_DownlinkValidationError) ErrorName() string { + return "TxSettings_DownlinkValidationError" +} // Error satisfies the builtin error interface -func (e MACCommandValidationError) Error() string { +func (e TxSettings_DownlinkValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -2996,14 +5111,14 @@ func (e MACCommandValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand.%s: %s%s", + "invalid %sTxSettings_Downlink.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommandValidationError{} +var _ error = TxSettings_DownlinkValidationError{} var _ interface { Field() string @@ -3011,46 +5126,41 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommandValidationError{} - -var _MACCommand_Cid_NotInLookup = map[MACCommandIdentifier]struct{}{ - 0: {}, -} +} = TxSettings_DownlinkValidationError{} -// ValidateFields checks the field values on MACCommands with the rules defined -// in the proto definition for this message. If any rules are violated, an -// error is returned. -func (m *MACCommands) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_ResetInd with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *MACCommand_ResetInd) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommandsFieldPathsNested + paths = MACCommand_ResetIndFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "commands": - - for idx, item := range m.GetCommands() { - _, _ = idx, item + case "minor_version": - if v, ok := interface{}(item).(interface{ ValidateFields(...string) error }); ok { - if err := v.ValidateFields(subs...); err != nil { - return MACCommandsValidationError{ - field: fmt.Sprintf("commands[%v]", idx), - reason: "embedded message failed validation", - cause: err, - } - } + if _, ok := _MACCommand_ResetInd_MinorVersion_InLookup[m.GetMinorVersion()]; !ok { + return MACCommand_ResetIndValidationError{ + field: "minor_version", + reason: "value must be in list [1]", } + } + if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { + return MACCommand_ResetIndValidationError{ + field: "minor_version", + reason: "value must be one of the defined enum values", + } } default: - return MACCommandsValidationError{ + return MACCommand_ResetIndValidationError{ field: name, reason: "invalid field path", } @@ -3059,9 +5169,9 @@ func (m *MACCommands) ValidateFields(paths ...string) error { return nil } -// MACCommandsValidationError is the validation error returned by -// MACCommands.ValidateFields if the designated constraints aren't met. -type MACCommandsValidationError struct { +// MACCommand_ResetIndValidationError is the validation error returned by +// MACCommand_ResetInd.ValidateFields if the designated constraints aren't met. +type MACCommand_ResetIndValidationError struct { field string reason string cause error @@ -3069,22 +5179,24 @@ type MACCommandsValidationError struct { } // Field function returns field value. -func (e MACCommandsValidationError) Field() string { return e.field } +func (e MACCommand_ResetIndValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommandsValidationError) Reason() string { return e.reason } +func (e MACCommand_ResetIndValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommandsValidationError) Cause() error { return e.cause } +func (e MACCommand_ResetIndValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommandsValidationError) Key() bool { return e.key } +func (e MACCommand_ResetIndValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommandsValidationError) ErrorName() string { return "MACCommandsValidationError" } +func (e MACCommand_ResetIndValidationError) ErrorName() string { + return "MACCommand_ResetIndValidationError" +} // Error satisfies the builtin error interface -func (e MACCommandsValidationError) Error() string { +func (e MACCommand_ResetIndValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3096,14 +5208,14 @@ func (e MACCommandsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommands.%s: %s%s", + "invalid %sMACCommand_ResetInd.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommandsValidationError{} +var _ error = MACCommand_ResetIndValidationError{} var _ interface { Field() string @@ -3111,34 +5223,45 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommandsValidationError{} +} = MACCommand_ResetIndValidationError{} -// ValidateFields checks the field values on FrequencyValue with the rules -// defined in the proto definition for this message. If any rules are +var _MACCommand_ResetInd_MinorVersion_InLookup = map[Minor]struct{}{ + 1: {}, +} + +// ValidateFields checks the field values on MACCommand_ResetConf with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *FrequencyValue) ValidateFields(paths ...string) error { +func (m *MACCommand_ResetConf) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = FrequencyValueFieldPathsNested + paths = MACCommand_ResetConfFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "minor_version": - if m.GetValue() < 100000 { - return FrequencyValueValidationError{ - field: "value", - reason: "value must be greater than or equal to 100000", + if _, ok := _MACCommand_ResetConf_MinorVersion_InLookup[m.GetMinorVersion()]; !ok { + return MACCommand_ResetConfValidationError{ + field: "minor_version", + reason: "value must be in list [1]", + } + } + + if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { + return MACCommand_ResetConfValidationError{ + field: "minor_version", + reason: "value must be one of the defined enum values", } } default: - return FrequencyValueValidationError{ + return MACCommand_ResetConfValidationError{ field: name, reason: "invalid field path", } @@ -3147,9 +5270,9 @@ func (m *FrequencyValue) ValidateFields(paths ...string) error { return nil } -// FrequencyValueValidationError is the validation error returned by -// FrequencyValue.ValidateFields if the designated constraints aren't met. -type FrequencyValueValidationError struct { +// MACCommand_ResetConfValidationError is the validation error returned by +// MACCommand_ResetConf.ValidateFields if the designated constraints aren't met. +type MACCommand_ResetConfValidationError struct { field string reason string cause error @@ -3157,22 +5280,24 @@ type FrequencyValueValidationError struct { } // Field function returns field value. -func (e FrequencyValueValidationError) Field() string { return e.field } +func (e MACCommand_ResetConfValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e FrequencyValueValidationError) Reason() string { return e.reason } +func (e MACCommand_ResetConfValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e FrequencyValueValidationError) Cause() error { return e.cause } +func (e MACCommand_ResetConfValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e FrequencyValueValidationError) Key() bool { return e.key } +func (e MACCommand_ResetConfValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e FrequencyValueValidationError) ErrorName() string { return "FrequencyValueValidationError" } +func (e MACCommand_ResetConfValidationError) ErrorName() string { + return "MACCommand_ResetConfValidationError" +} // Error satisfies the builtin error interface -func (e FrequencyValueValidationError) Error() string { +func (e MACCommand_ResetConfValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3184,14 +5309,14 @@ func (e FrequencyValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sFrequencyValue.%s: %s%s", + "invalid %sMACCommand_ResetConf.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = FrequencyValueValidationError{} +var _ error = MACCommand_ResetConfValidationError{} var _ interface { Field() string @@ -3199,34 +5324,47 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = FrequencyValueValidationError{} +} = MACCommand_ResetConfValidationError{} -// ValidateFields checks the field values on ZeroableFrequencyValue with the +var _MACCommand_ResetConf_MinorVersion_InLookup = map[Minor]struct{}{ + 1: {}, +} + +// ValidateFields checks the field values on MACCommand_LinkCheckAns with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *ZeroableFrequencyValue) ValidateFields(paths ...string) error { +func (m *MACCommand_LinkCheckAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = ZeroableFrequencyValueFieldPathsNested + paths = MACCommand_LinkCheckAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "margin": - if val := m.GetValue(); val > 0 && val < 100000 { - return ZeroableFrequencyValueValidationError{ - field: "value", - reason: "value must be outside range (0, 100000)", + if m.GetMargin() > 254 { + return MACCommand_LinkCheckAnsValidationError{ + field: "margin", + reason: "value must be less than or equal to 254", + } + } + + case "gateway_count": + + if m.GetGatewayCount() > 255 { + return MACCommand_LinkCheckAnsValidationError{ + field: "gateway_count", + reason: "value must be less than or equal to 255", } } default: - return ZeroableFrequencyValueValidationError{ + return MACCommand_LinkCheckAnsValidationError{ field: name, reason: "invalid field path", } @@ -3235,9 +5373,9 @@ func (m *ZeroableFrequencyValue) ValidateFields(paths ...string) error { return nil } -// ZeroableFrequencyValueValidationError is the validation error returned by -// ZeroableFrequencyValue.ValidateFields if the designated constraints aren't met. -type ZeroableFrequencyValueValidationError struct { +// MACCommand_LinkCheckAnsValidationError is the validation error returned by +// MACCommand_LinkCheckAns.ValidateFields if the designated constraints aren't met. +type MACCommand_LinkCheckAnsValidationError struct { field string reason string cause error @@ -3245,24 +5383,24 @@ type ZeroableFrequencyValueValidationError struct { } // Field function returns field value. -func (e ZeroableFrequencyValueValidationError) Field() string { return e.field } +func (e MACCommand_LinkCheckAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e ZeroableFrequencyValueValidationError) Reason() string { return e.reason } +func (e MACCommand_LinkCheckAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e ZeroableFrequencyValueValidationError) Cause() error { return e.cause } +func (e MACCommand_LinkCheckAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e ZeroableFrequencyValueValidationError) Key() bool { return e.key } +func (e MACCommand_LinkCheckAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e ZeroableFrequencyValueValidationError) ErrorName() string { - return "ZeroableFrequencyValueValidationError" +func (e MACCommand_LinkCheckAnsValidationError) ErrorName() string { + return "MACCommand_LinkCheckAnsValidationError" } // Error satisfies the builtin error interface -func (e ZeroableFrequencyValueValidationError) Error() string { +func (e MACCommand_LinkCheckAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3274,14 +5412,14 @@ func (e ZeroableFrequencyValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sZeroableFrequencyValue.%s: %s%s", + "invalid %sMACCommand_LinkCheckAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = ZeroableFrequencyValueValidationError{} +var _ error = MACCommand_LinkCheckAnsValidationError{} var _ interface { Field() string @@ -3289,34 +5427,70 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = ZeroableFrequencyValueValidationError{} +} = MACCommand_LinkCheckAnsValidationError{} -// ValidateFields checks the field values on DataRateOffsetValue with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_LinkADRReq with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *DataRateOffsetValue) ValidateFields(paths ...string) error { +func (m *MACCommand_LinkADRReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = DataRateOffsetValueFieldPathsNested + paths = MACCommand_LinkADRReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "data_rate_index": - if _, ok := DataRateOffset_name[int32(m.GetValue())]; !ok { - return DataRateOffsetValueValidationError{ - field: "value", + if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { + return MACCommand_LinkADRReqValidationError{ + field: "data_rate_index", reason: "value must be one of the defined enum values", } } + case "tx_power_index": + + if m.GetTxPowerIndex() > 15 { + return MACCommand_LinkADRReqValidationError{ + field: "tx_power_index", + reason: "value must be less than or equal to 15", + } + } + + case "channel_mask": + + if len(m.GetChannelMask()) > 16 { + return MACCommand_LinkADRReqValidationError{ + field: "channel_mask", + reason: "value must contain no more than 16 item(s)", + } + } + + case "channel_mask_control": + + if m.GetChannelMaskControl() > 7 { + return MACCommand_LinkADRReqValidationError{ + field: "channel_mask_control", + reason: "value must be less than or equal to 7", + } + } + + case "nb_trans": + + if m.GetNbTrans() > 15 { + return MACCommand_LinkADRReqValidationError{ + field: "nb_trans", + reason: "value must be less than or equal to 15", + } + } + default: - return DataRateOffsetValueValidationError{ + return MACCommand_LinkADRReqValidationError{ field: name, reason: "invalid field path", } @@ -3325,9 +5499,9 @@ func (m *DataRateOffsetValue) ValidateFields(paths ...string) error { return nil } -// DataRateOffsetValueValidationError is the validation error returned by -// DataRateOffsetValue.ValidateFields if the designated constraints aren't met. -type DataRateOffsetValueValidationError struct { +// MACCommand_LinkADRReqValidationError is the validation error returned by +// MACCommand_LinkADRReq.ValidateFields if the designated constraints aren't met. +type MACCommand_LinkADRReqValidationError struct { field string reason string cause error @@ -3335,24 +5509,24 @@ type DataRateOffsetValueValidationError struct { } // Field function returns field value. -func (e DataRateOffsetValueValidationError) Field() string { return e.field } +func (e MACCommand_LinkADRReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e DataRateOffsetValueValidationError) Reason() string { return e.reason } +func (e MACCommand_LinkADRReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e DataRateOffsetValueValidationError) Cause() error { return e.cause } +func (e MACCommand_LinkADRReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e DataRateOffsetValueValidationError) Key() bool { return e.key } +func (e MACCommand_LinkADRReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e DataRateOffsetValueValidationError) ErrorName() string { - return "DataRateOffsetValueValidationError" +func (e MACCommand_LinkADRReqValidationError) ErrorName() string { + return "MACCommand_LinkADRReqValidationError" } // Error satisfies the builtin error interface -func (e DataRateOffsetValueValidationError) Error() string { +func (e MACCommand_LinkADRReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3364,14 +5538,14 @@ func (e DataRateOffsetValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sDataRateOffsetValue.%s: %s%s", + "invalid %sMACCommand_LinkADRReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = DataRateOffsetValueValidationError{} +var _ error = MACCommand_LinkADRReqValidationError{} var _ interface { Field() string @@ -3379,34 +5553,31 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = DataRateOffsetValueValidationError{} +} = MACCommand_LinkADRReqValidationError{} -// ValidateFields checks the field values on DataRateIndexValue with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_LinkADRAns with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *DataRateIndexValue) ValidateFields(paths ...string) error { +func (m *MACCommand_LinkADRAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = DataRateIndexValueFieldPathsNested + paths = MACCommand_LinkADRAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": - - if _, ok := DataRateIndex_name[int32(m.GetValue())]; !ok { - return DataRateIndexValueValidationError{ - field: "value", - reason: "value must be one of the defined enum values", - } - } - + case "channel_mask_ack": + // no validation rules for ChannelMaskAck + case "data_rate_index_ack": + // no validation rules for DataRateIndexAck + case "tx_power_index_ack": + // no validation rules for TxPowerIndexAck default: - return DataRateIndexValueValidationError{ + return MACCommand_LinkADRAnsValidationError{ field: name, reason: "invalid field path", } @@ -3415,9 +5586,9 @@ func (m *DataRateIndexValue) ValidateFields(paths ...string) error { return nil } -// DataRateIndexValueValidationError is the validation error returned by -// DataRateIndexValue.ValidateFields if the designated constraints aren't met. -type DataRateIndexValueValidationError struct { +// MACCommand_LinkADRAnsValidationError is the validation error returned by +// MACCommand_LinkADRAns.ValidateFields if the designated constraints aren't met. +type MACCommand_LinkADRAnsValidationError struct { field string reason string cause error @@ -3425,24 +5596,24 @@ type DataRateIndexValueValidationError struct { } // Field function returns field value. -func (e DataRateIndexValueValidationError) Field() string { return e.field } +func (e MACCommand_LinkADRAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e DataRateIndexValueValidationError) Reason() string { return e.reason } +func (e MACCommand_LinkADRAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e DataRateIndexValueValidationError) Cause() error { return e.cause } +func (e MACCommand_LinkADRAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e DataRateIndexValueValidationError) Key() bool { return e.key } +func (e MACCommand_LinkADRAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e DataRateIndexValueValidationError) ErrorName() string { - return "DataRateIndexValueValidationError" +func (e MACCommand_LinkADRAnsValidationError) ErrorName() string { + return "MACCommand_LinkADRAnsValidationError" } // Error satisfies the builtin error interface -func (e DataRateIndexValueValidationError) Error() string { +func (e MACCommand_LinkADRAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3454,14 +5625,14 @@ func (e DataRateIndexValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sDataRateIndexValue.%s: %s%s", + "invalid %sMACCommand_LinkADRAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = DataRateIndexValueValidationError{} +var _ error = MACCommand_LinkADRAnsValidationError{} var _ interface { Field() string @@ -3469,34 +5640,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = DataRateIndexValueValidationError{} +} = MACCommand_LinkADRAnsValidationError{} -// ValidateFields checks the field values on PingSlotPeriodValue with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_DutyCycleReq with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *PingSlotPeriodValue) ValidateFields(paths ...string) error { +func (m *MACCommand_DutyCycleReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = PingSlotPeriodValueFieldPathsNested + paths = MACCommand_DutyCycleReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "max_duty_cycle": - if _, ok := PingSlotPeriod_name[int32(m.GetValue())]; !ok { - return PingSlotPeriodValueValidationError{ - field: "value", + if _, ok := AggregatedDutyCycle_name[int32(m.GetMaxDutyCycle())]; !ok { + return MACCommand_DutyCycleReqValidationError{ + field: "max_duty_cycle", reason: "value must be one of the defined enum values", } } default: - return PingSlotPeriodValueValidationError{ + return MACCommand_DutyCycleReqValidationError{ field: name, reason: "invalid field path", } @@ -3505,9 +5676,9 @@ func (m *PingSlotPeriodValue) ValidateFields(paths ...string) error { return nil } -// PingSlotPeriodValueValidationError is the validation error returned by -// PingSlotPeriodValue.ValidateFields if the designated constraints aren't met. -type PingSlotPeriodValueValidationError struct { +// MACCommand_DutyCycleReqValidationError is the validation error returned by +// MACCommand_DutyCycleReq.ValidateFields if the designated constraints aren't met. +type MACCommand_DutyCycleReqValidationError struct { field string reason string cause error @@ -3515,24 +5686,24 @@ type PingSlotPeriodValueValidationError struct { } // Field function returns field value. -func (e PingSlotPeriodValueValidationError) Field() string { return e.field } +func (e MACCommand_DutyCycleReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e PingSlotPeriodValueValidationError) Reason() string { return e.reason } +func (e MACCommand_DutyCycleReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e PingSlotPeriodValueValidationError) Cause() error { return e.cause } +func (e MACCommand_DutyCycleReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e PingSlotPeriodValueValidationError) Key() bool { return e.key } +func (e MACCommand_DutyCycleReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e PingSlotPeriodValueValidationError) ErrorName() string { - return "PingSlotPeriodValueValidationError" +func (e MACCommand_DutyCycleReqValidationError) ErrorName() string { + return "MACCommand_DutyCycleReqValidationError" } // Error satisfies the builtin error interface -func (e PingSlotPeriodValueValidationError) Error() string { +func (e MACCommand_DutyCycleReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3544,14 +5715,14 @@ func (e PingSlotPeriodValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sPingSlotPeriodValue.%s: %s%s", + "invalid %sMACCommand_DutyCycleReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = PingSlotPeriodValueValidationError{} +var _ error = MACCommand_DutyCycleReqValidationError{} var _ interface { Field() string @@ -3559,34 +5730,52 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = PingSlotPeriodValueValidationError{} +} = MACCommand_DutyCycleReqValidationError{} -// ValidateFields checks the field values on AggregatedDutyCycleValue with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *AggregatedDutyCycleValue) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RxParamSetupReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_RxParamSetupReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = AggregatedDutyCycleValueFieldPathsNested + paths = MACCommand_RxParamSetupReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "rx2_data_rate_index": - if _, ok := AggregatedDutyCycle_name[int32(m.GetValue())]; !ok { - return AggregatedDutyCycleValueValidationError{ - field: "value", + if _, ok := DataRateIndex_name[int32(m.GetRx2DataRateIndex())]; !ok { + return MACCommand_RxParamSetupReqValidationError{ + field: "rx2_data_rate_index", + reason: "value must be one of the defined enum values", + } + } + + case "rx1_data_rate_offset": + + if _, ok := DataRateOffset_name[int32(m.GetRx1DataRateOffset())]; !ok { + return MACCommand_RxParamSetupReqValidationError{ + field: "rx1_data_rate_offset", reason: "value must be one of the defined enum values", } } + case "rx2_frequency": + + if m.GetRx2Frequency() < 100000 { + return MACCommand_RxParamSetupReqValidationError{ + field: "rx2_frequency", + reason: "value must be greater than or equal to 100000", + } + } + default: - return AggregatedDutyCycleValueValidationError{ + return MACCommand_RxParamSetupReqValidationError{ field: name, reason: "invalid field path", } @@ -3595,10 +5784,10 @@ func (m *AggregatedDutyCycleValue) ValidateFields(paths ...string) error { return nil } -// AggregatedDutyCycleValueValidationError is the validation error returned by -// AggregatedDutyCycleValue.ValidateFields if the designated constraints +// MACCommand_RxParamSetupReqValidationError is the validation error returned +// by MACCommand_RxParamSetupReq.ValidateFields if the designated constraints // aren't met. -type AggregatedDutyCycleValueValidationError struct { +type MACCommand_RxParamSetupReqValidationError struct { field string reason string cause error @@ -3606,24 +5795,24 @@ type AggregatedDutyCycleValueValidationError struct { } // Field function returns field value. -func (e AggregatedDutyCycleValueValidationError) Field() string { return e.field } +func (e MACCommand_RxParamSetupReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e AggregatedDutyCycleValueValidationError) Reason() string { return e.reason } +func (e MACCommand_RxParamSetupReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e AggregatedDutyCycleValueValidationError) Cause() error { return e.cause } +func (e MACCommand_RxParamSetupReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e AggregatedDutyCycleValueValidationError) Key() bool { return e.key } +func (e MACCommand_RxParamSetupReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e AggregatedDutyCycleValueValidationError) ErrorName() string { - return "AggregatedDutyCycleValueValidationError" +func (e MACCommand_RxParamSetupReqValidationError) ErrorName() string { + return "MACCommand_RxParamSetupReqValidationError" } // Error satisfies the builtin error interface -func (e AggregatedDutyCycleValueValidationError) Error() string { +func (e MACCommand_RxParamSetupReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3635,14 +5824,14 @@ func (e AggregatedDutyCycleValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sAggregatedDutyCycleValue.%s: %s%s", + "invalid %sMACCommand_RxParamSetupReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = AggregatedDutyCycleValueValidationError{} +var _ error = MACCommand_RxParamSetupReqValidationError{} var _ interface { Field() string @@ -3650,34 +5839,31 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = AggregatedDutyCycleValueValidationError{} +} = MACCommand_RxParamSetupReqValidationError{} -// ValidateFields checks the field values on RxDelayValue with the rules -// defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *RxDelayValue) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RxParamSetupAns with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_RxParamSetupAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = RxDelayValueFieldPathsNested + paths = MACCommand_RxParamSetupAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": - - if _, ok := RxDelay_name[int32(m.GetValue())]; !ok { - return RxDelayValueValidationError{ - field: "value", - reason: "value must be one of the defined enum values", - } - } - + case "rx2_data_rate_index_ack": + // no validation rules for Rx2DataRateIndexAck + case "rx1_data_rate_offset_ack": + // no validation rules for Rx1DataRateOffsetAck + case "rx2_frequency_ack": + // no validation rules for Rx2FrequencyAck default: - return RxDelayValueValidationError{ + return MACCommand_RxParamSetupAnsValidationError{ field: name, reason: "invalid field path", } @@ -3686,9 +5872,10 @@ func (m *RxDelayValue) ValidateFields(paths ...string) error { return nil } -// RxDelayValueValidationError is the validation error returned by -// RxDelayValue.ValidateFields if the designated constraints aren't met. -type RxDelayValueValidationError struct { +// MACCommand_RxParamSetupAnsValidationError is the validation error returned +// by MACCommand_RxParamSetupAns.ValidateFields if the designated constraints +// aren't met. +type MACCommand_RxParamSetupAnsValidationError struct { field string reason string cause error @@ -3696,22 +5883,24 @@ type RxDelayValueValidationError struct { } // Field function returns field value. -func (e RxDelayValueValidationError) Field() string { return e.field } +func (e MACCommand_RxParamSetupAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e RxDelayValueValidationError) Reason() string { return e.reason } +func (e MACCommand_RxParamSetupAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e RxDelayValueValidationError) Cause() error { return e.cause } +func (e MACCommand_RxParamSetupAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e RxDelayValueValidationError) Key() bool { return e.key } +func (e MACCommand_RxParamSetupAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e RxDelayValueValidationError) ErrorName() string { return "RxDelayValueValidationError" } +func (e MACCommand_RxParamSetupAnsValidationError) ErrorName() string { + return "MACCommand_RxParamSetupAnsValidationError" +} // Error satisfies the builtin error interface -func (e RxDelayValueValidationError) Error() string { +func (e MACCommand_RxParamSetupAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3723,14 +5912,14 @@ func (e RxDelayValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sRxDelayValue.%s: %s%s", + "invalid %sMACCommand_RxParamSetupAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = RxDelayValueValidationError{} +var _ error = MACCommand_RxParamSetupAnsValidationError{} var _ interface { Field() string @@ -3738,34 +5927,43 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = RxDelayValueValidationError{} +} = MACCommand_RxParamSetupAnsValidationError{} -// ValidateFields checks the field values on ADRAckLimitExponentValue with the +// ValidateFields checks the field values on MACCommand_DevStatusAns with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *ADRAckLimitExponentValue) ValidateFields(paths ...string) error { +func (m *MACCommand_DevStatusAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = ADRAckLimitExponentValueFieldPathsNested + paths = MACCommand_DevStatusAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "battery": - if _, ok := ADRAckLimitExponent_name[int32(m.GetValue())]; !ok { - return ADRAckLimitExponentValueValidationError{ - field: "value", - reason: "value must be one of the defined enum values", + if m.GetBattery() > 255 { + return MACCommand_DevStatusAnsValidationError{ + field: "battery", + reason: "value must be less than or equal to 255", + } + } + + case "margin": + + if val := m.GetMargin(); val < -32 || val > 31 { + return MACCommand_DevStatusAnsValidationError{ + field: "margin", + reason: "value must be inside range [-32, 31]", } } default: - return ADRAckLimitExponentValueValidationError{ + return MACCommand_DevStatusAnsValidationError{ field: name, reason: "invalid field path", } @@ -3774,10 +5972,9 @@ func (m *ADRAckLimitExponentValue) ValidateFields(paths ...string) error { return nil } -// ADRAckLimitExponentValueValidationError is the validation error returned by -// ADRAckLimitExponentValue.ValidateFields if the designated constraints -// aren't met. -type ADRAckLimitExponentValueValidationError struct { +// MACCommand_DevStatusAnsValidationError is the validation error returned by +// MACCommand_DevStatusAns.ValidateFields if the designated constraints aren't met. +type MACCommand_DevStatusAnsValidationError struct { field string reason string cause error @@ -3785,24 +5982,24 @@ type ADRAckLimitExponentValueValidationError struct { } // Field function returns field value. -func (e ADRAckLimitExponentValueValidationError) Field() string { return e.field } +func (e MACCommand_DevStatusAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e ADRAckLimitExponentValueValidationError) Reason() string { return e.reason } +func (e MACCommand_DevStatusAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e ADRAckLimitExponentValueValidationError) Cause() error { return e.cause } +func (e MACCommand_DevStatusAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e ADRAckLimitExponentValueValidationError) Key() bool { return e.key } +func (e MACCommand_DevStatusAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e ADRAckLimitExponentValueValidationError) ErrorName() string { - return "ADRAckLimitExponentValueValidationError" +func (e MACCommand_DevStatusAnsValidationError) ErrorName() string { + return "MACCommand_DevStatusAnsValidationError" } // Error satisfies the builtin error interface -func (e ADRAckLimitExponentValueValidationError) Error() string { +func (e MACCommand_DevStatusAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3814,14 +6011,14 @@ func (e ADRAckLimitExponentValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sADRAckLimitExponentValue.%s: %s%s", + "invalid %sMACCommand_DevStatusAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = ADRAckLimitExponentValueValidationError{} +var _ error = MACCommand_DevStatusAnsValidationError{} var _ interface { Field() string @@ -3829,34 +6026,61 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = ADRAckLimitExponentValueValidationError{} +} = MACCommand_DevStatusAnsValidationError{} -// ValidateFields checks the field values on ADRAckDelayExponentValue with the +// ValidateFields checks the field values on MACCommand_NewChannelReq with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *ADRAckDelayExponentValue) ValidateFields(paths ...string) error { +func (m *MACCommand_NewChannelReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = ADRAckDelayExponentValueFieldPathsNested + paths = MACCommand_NewChannelReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": + case "channel_index": + + if m.GetChannelIndex() > 255 { + return MACCommand_NewChannelReqValidationError{ + field: "channel_index", + reason: "value must be less than or equal to 255", + } + } + + case "frequency": + + if val := m.GetFrequency(); val > 0 && val < 100000 { + return MACCommand_NewChannelReqValidationError{ + field: "frequency", + reason: "value must be outside range (0, 100000)", + } + } + + case "min_data_rate_index": + + if _, ok := DataRateIndex_name[int32(m.GetMinDataRateIndex())]; !ok { + return MACCommand_NewChannelReqValidationError{ + field: "min_data_rate_index", + reason: "value must be one of the defined enum values", + } + } - if _, ok := ADRAckDelayExponent_name[int32(m.GetValue())]; !ok { - return ADRAckDelayExponentValueValidationError{ - field: "value", + case "max_data_rate_index": + + if _, ok := DataRateIndex_name[int32(m.GetMaxDataRateIndex())]; !ok { + return MACCommand_NewChannelReqValidationError{ + field: "max_data_rate_index", reason: "value must be one of the defined enum values", } } default: - return ADRAckDelayExponentValueValidationError{ + return MACCommand_NewChannelReqValidationError{ field: name, reason: "invalid field path", } @@ -3865,10 +6089,10 @@ func (m *ADRAckDelayExponentValue) ValidateFields(paths ...string) error { return nil } -// ADRAckDelayExponentValueValidationError is the validation error returned by -// ADRAckDelayExponentValue.ValidateFields if the designated constraints +// MACCommand_NewChannelReqValidationError is the validation error returned by +// MACCommand_NewChannelReq.ValidateFields if the designated constraints // aren't met. -type ADRAckDelayExponentValueValidationError struct { +type MACCommand_NewChannelReqValidationError struct { field string reason string cause error @@ -3876,24 +6100,24 @@ type ADRAckDelayExponentValueValidationError struct { } // Field function returns field value. -func (e ADRAckDelayExponentValueValidationError) Field() string { return e.field } +func (e MACCommand_NewChannelReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e ADRAckDelayExponentValueValidationError) Reason() string { return e.reason } +func (e MACCommand_NewChannelReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e ADRAckDelayExponentValueValidationError) Cause() error { return e.cause } +func (e MACCommand_NewChannelReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e ADRAckDelayExponentValueValidationError) Key() bool { return e.key } +func (e MACCommand_NewChannelReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e ADRAckDelayExponentValueValidationError) ErrorName() string { - return "ADRAckDelayExponentValueValidationError" +func (e MACCommand_NewChannelReqValidationError) ErrorName() string { + return "MACCommand_NewChannelReqValidationError" } // Error satisfies the builtin error interface -func (e ADRAckDelayExponentValueValidationError) Error() string { +func (e MACCommand_NewChannelReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3905,14 +6129,14 @@ func (e ADRAckDelayExponentValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sADRAckDelayExponentValue.%s: %s%s", + "invalid %sMACCommand_NewChannelReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = ADRAckDelayExponentValueValidationError{} +var _ error = MACCommand_NewChannelReqValidationError{} var _ interface { Field() string @@ -3920,34 +6144,29 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = ADRAckDelayExponentValueValidationError{} +} = MACCommand_NewChannelReqValidationError{} -// ValidateFields checks the field values on DeviceEIRPValue with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_NewChannelAns with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *DeviceEIRPValue) ValidateFields(paths ...string) error { +func (m *MACCommand_NewChannelAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = DeviceEIRPValueFieldPathsNested + paths = MACCommand_NewChannelAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "value": - - if _, ok := DeviceEIRP_name[int32(m.GetValue())]; !ok { - return DeviceEIRPValueValidationError{ - field: "value", - reason: "value must be one of the defined enum values", - } - } - + case "frequency_ack": + // no validation rules for FrequencyAck + case "data_rate_ack": + // no validation rules for DataRateAck default: - return DeviceEIRPValueValidationError{ + return MACCommand_NewChannelAnsValidationError{ field: name, reason: "invalid field path", } @@ -3956,9 +6175,10 @@ func (m *DeviceEIRPValue) ValidateFields(paths ...string) error { return nil } -// DeviceEIRPValueValidationError is the validation error returned by -// DeviceEIRPValue.ValidateFields if the designated constraints aren't met. -type DeviceEIRPValueValidationError struct { +// MACCommand_NewChannelAnsValidationError is the validation error returned by +// MACCommand_NewChannelAns.ValidateFields if the designated constraints +// aren't met. +type MACCommand_NewChannelAnsValidationError struct { field string reason string cause error @@ -3966,22 +6186,24 @@ type DeviceEIRPValueValidationError struct { } // Field function returns field value. -func (e DeviceEIRPValueValidationError) Field() string { return e.field } +func (e MACCommand_NewChannelAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e DeviceEIRPValueValidationError) Reason() string { return e.reason } +func (e MACCommand_NewChannelAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e DeviceEIRPValueValidationError) Cause() error { return e.cause } +func (e MACCommand_NewChannelAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e DeviceEIRPValueValidationError) Key() bool { return e.key } +func (e MACCommand_NewChannelAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e DeviceEIRPValueValidationError) ErrorName() string { return "DeviceEIRPValueValidationError" } +func (e MACCommand_NewChannelAnsValidationError) ErrorName() string { + return "MACCommand_NewChannelAnsValidationError" +} // Error satisfies the builtin error interface -func (e DeviceEIRPValueValidationError) Error() string { +func (e MACCommand_NewChannelAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -3993,14 +6215,14 @@ func (e DeviceEIRPValueValidationError) Error() string { } return fmt.Sprintf( - "invalid %sDeviceEIRPValue.%s: %s%s", + "invalid %sMACCommand_NewChannelAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = DeviceEIRPValueValidationError{} +var _ error = MACCommand_NewChannelAnsValidationError{} var _ interface { Field() string @@ -4008,31 +6230,43 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = DeviceEIRPValueValidationError{} +} = MACCommand_NewChannelAnsValidationError{} -// ValidateFields checks the field values on TxSettings_Downlink with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_DLChannelReq with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *TxSettings_Downlink) ValidateFields(paths ...string) error { +func (m *MACCommand_DLChannelReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = TxSettings_DownlinkFieldPathsNested + paths = MACCommand_DLChannelReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "antenna_index": - // no validation rules for AntennaIndex - case "tx_power": - // no validation rules for TxPower - case "invert_polarization": - // no validation rules for InvertPolarization + case "channel_index": + + if m.GetChannelIndex() > 255 { + return MACCommand_DLChannelReqValidationError{ + field: "channel_index", + reason: "value must be less than or equal to 255", + } + } + + case "frequency": + + if m.GetFrequency() < 100000 { + return MACCommand_DLChannelReqValidationError{ + field: "frequency", + reason: "value must be greater than or equal to 100000", + } + } + default: - return TxSettings_DownlinkValidationError{ + return MACCommand_DLChannelReqValidationError{ field: name, reason: "invalid field path", } @@ -4041,9 +6275,9 @@ func (m *TxSettings_Downlink) ValidateFields(paths ...string) error { return nil } -// TxSettings_DownlinkValidationError is the validation error returned by -// TxSettings_Downlink.ValidateFields if the designated constraints aren't met. -type TxSettings_DownlinkValidationError struct { +// MACCommand_DLChannelReqValidationError is the validation error returned by +// MACCommand_DLChannelReq.ValidateFields if the designated constraints aren't met. +type MACCommand_DLChannelReqValidationError struct { field string reason string cause error @@ -4051,24 +6285,24 @@ type TxSettings_DownlinkValidationError struct { } // Field function returns field value. -func (e TxSettings_DownlinkValidationError) Field() string { return e.field } +func (e MACCommand_DLChannelReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e TxSettings_DownlinkValidationError) Reason() string { return e.reason } +func (e MACCommand_DLChannelReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e TxSettings_DownlinkValidationError) Cause() error { return e.cause } +func (e MACCommand_DLChannelReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e TxSettings_DownlinkValidationError) Key() bool { return e.key } +func (e MACCommand_DLChannelReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e TxSettings_DownlinkValidationError) ErrorName() string { - return "TxSettings_DownlinkValidationError" +func (e MACCommand_DLChannelReqValidationError) ErrorName() string { + return "MACCommand_DLChannelReqValidationError" } // Error satisfies the builtin error interface -func (e TxSettings_DownlinkValidationError) Error() string { +func (e MACCommand_DLChannelReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4080,14 +6314,14 @@ func (e TxSettings_DownlinkValidationError) Error() string { } return fmt.Sprintf( - "invalid %sTxSettings_Downlink.%s: %s%s", + "invalid %sMACCommand_DLChannelReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = TxSettings_DownlinkValidationError{} +var _ error = MACCommand_DLChannelReqValidationError{} var _ interface { Field() string @@ -4095,41 +6329,29 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = TxSettings_DownlinkValidationError{} +} = MACCommand_DLChannelReqValidationError{} -// ValidateFields checks the field values on MACCommand_ResetInd with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_DLChannelAns with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_ResetInd) ValidateFields(paths ...string) error { +func (m *MACCommand_DLChannelAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_ResetIndFieldPathsNested + paths = MACCommand_DLChannelAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "minor_version": - - if _, ok := _MACCommand_ResetInd_MinorVersion_InLookup[m.GetMinorVersion()]; !ok { - return MACCommand_ResetIndValidationError{ - field: "minor_version", - reason: "value must be in list [1]", - } - } - - if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { - return MACCommand_ResetIndValidationError{ - field: "minor_version", - reason: "value must be one of the defined enum values", - } - } - + case "channel_index_ack": + // no validation rules for ChannelIndexAck + case "frequency_ack": + // no validation rules for FrequencyAck default: - return MACCommand_ResetIndValidationError{ + return MACCommand_DLChannelAnsValidationError{ field: name, reason: "invalid field path", } @@ -4138,9 +6360,9 @@ func (m *MACCommand_ResetInd) ValidateFields(paths ...string) error { return nil } -// MACCommand_ResetIndValidationError is the validation error returned by -// MACCommand_ResetInd.ValidateFields if the designated constraints aren't met. -type MACCommand_ResetIndValidationError struct { +// MACCommand_DLChannelAnsValidationError is the validation error returned by +// MACCommand_DLChannelAns.ValidateFields if the designated constraints aren't met. +type MACCommand_DLChannelAnsValidationError struct { field string reason string cause error @@ -4148,24 +6370,24 @@ type MACCommand_ResetIndValidationError struct { } // Field function returns field value. -func (e MACCommand_ResetIndValidationError) Field() string { return e.field } +func (e MACCommand_DLChannelAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_ResetIndValidationError) Reason() string { return e.reason } +func (e MACCommand_DLChannelAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_ResetIndValidationError) Cause() error { return e.cause } +func (e MACCommand_DLChannelAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_ResetIndValidationError) Key() bool { return e.key } +func (e MACCommand_DLChannelAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_ResetIndValidationError) ErrorName() string { - return "MACCommand_ResetIndValidationError" +func (e MACCommand_DLChannelAnsValidationError) ErrorName() string { + return "MACCommand_DLChannelAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_ResetIndValidationError) Error() string { +func (e MACCommand_DLChannelAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4177,14 +6399,14 @@ func (e MACCommand_ResetIndValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_ResetInd.%s: %s%s", + "invalid %sMACCommand_DLChannelAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_ResetIndValidationError{} +var _ error = MACCommand_DLChannelAnsValidationError{} var _ interface { Field() string @@ -4192,45 +6414,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_ResetIndValidationError{} - -var _MACCommand_ResetInd_MinorVersion_InLookup = map[Minor]struct{}{ - 1: {}, -} +} = MACCommand_DLChannelAnsValidationError{} -// ValidateFields checks the field values on MACCommand_ResetConf with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_ResetConf) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RxTimingSetupReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_RxTimingSetupReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_ResetConfFieldPathsNested + paths = MACCommand_RxTimingSetupReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "minor_version": - - if _, ok := _MACCommand_ResetConf_MinorVersion_InLookup[m.GetMinorVersion()]; !ok { - return MACCommand_ResetConfValidationError{ - field: "minor_version", - reason: "value must be in list [1]", - } - } + case "delay": - if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { - return MACCommand_ResetConfValidationError{ - field: "minor_version", + if _, ok := RxDelay_name[int32(m.GetDelay())]; !ok { + return MACCommand_RxTimingSetupReqValidationError{ + field: "delay", reason: "value must be one of the defined enum values", } } default: - return MACCommand_ResetConfValidationError{ + return MACCommand_RxTimingSetupReqValidationError{ field: name, reason: "invalid field path", } @@ -4239,9 +6450,10 @@ func (m *MACCommand_ResetConf) ValidateFields(paths ...string) error { return nil } -// MACCommand_ResetConfValidationError is the validation error returned by -// MACCommand_ResetConf.ValidateFields if the designated constraints aren't met. -type MACCommand_ResetConfValidationError struct { +// MACCommand_RxTimingSetupReqValidationError is the validation error returned +// by MACCommand_RxTimingSetupReq.ValidateFields if the designated constraints +// aren't met. +type MACCommand_RxTimingSetupReqValidationError struct { field string reason string cause error @@ -4249,24 +6461,24 @@ type MACCommand_ResetConfValidationError struct { } // Field function returns field value. -func (e MACCommand_ResetConfValidationError) Field() string { return e.field } +func (e MACCommand_RxTimingSetupReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_ResetConfValidationError) Reason() string { return e.reason } +func (e MACCommand_RxTimingSetupReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_ResetConfValidationError) Cause() error { return e.cause } +func (e MACCommand_RxTimingSetupReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_ResetConfValidationError) Key() bool { return e.key } +func (e MACCommand_RxTimingSetupReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_ResetConfValidationError) ErrorName() string { - return "MACCommand_ResetConfValidationError" +func (e MACCommand_RxTimingSetupReqValidationError) ErrorName() string { + return "MACCommand_RxTimingSetupReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_ResetConfValidationError) Error() string { +func (e MACCommand_RxTimingSetupReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4278,14 +6490,14 @@ func (e MACCommand_ResetConfValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_ResetConf.%s: %s%s", + "invalid %sMACCommand_RxTimingSetupReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_ResetConfValidationError{} +var _ error = MACCommand_RxTimingSetupReqValidationError{} var _ interface { Field() string @@ -4293,47 +6505,38 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_ResetConfValidationError{} - -var _MACCommand_ResetConf_MinorVersion_InLookup = map[Minor]struct{}{ - 1: {}, -} +} = MACCommand_RxTimingSetupReqValidationError{} -// ValidateFields checks the field values on MACCommand_LinkCheckAns with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_LinkCheckAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_TxParamSetupReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_TxParamSetupReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_LinkCheckAnsFieldPathsNested + paths = MACCommand_TxParamSetupReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "margin": - - if m.GetMargin() > 254 { - return MACCommand_LinkCheckAnsValidationError{ - field: "margin", - reason: "value must be less than or equal to 254", - } - } - - case "gateway_count": + case "max_eirp_index": - if m.GetGatewayCount() > 255 { - return MACCommand_LinkCheckAnsValidationError{ - field: "gateway_count", - reason: "value must be less than or equal to 255", + if _, ok := DeviceEIRP_name[int32(m.GetMaxEirpIndex())]; !ok { + return MACCommand_TxParamSetupReqValidationError{ + field: "max_eirp_index", + reason: "value must be one of the defined enum values", } } + case "uplink_dwell_time": + // no validation rules for UplinkDwellTime + case "downlink_dwell_time": + // no validation rules for DownlinkDwellTime default: - return MACCommand_LinkCheckAnsValidationError{ + return MACCommand_TxParamSetupReqValidationError{ field: name, reason: "invalid field path", } @@ -4342,9 +6545,10 @@ func (m *MACCommand_LinkCheckAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_LinkCheckAnsValidationError is the validation error returned by -// MACCommand_LinkCheckAns.ValidateFields if the designated constraints aren't met. -type MACCommand_LinkCheckAnsValidationError struct { +// MACCommand_TxParamSetupReqValidationError is the validation error returned +// by MACCommand_TxParamSetupReq.ValidateFields if the designated constraints +// aren't met. +type MACCommand_TxParamSetupReqValidationError struct { field string reason string cause error @@ -4352,24 +6556,24 @@ type MACCommand_LinkCheckAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_LinkCheckAnsValidationError) Field() string { return e.field } +func (e MACCommand_TxParamSetupReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_LinkCheckAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_TxParamSetupReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_LinkCheckAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_TxParamSetupReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_LinkCheckAnsValidationError) Key() bool { return e.key } +func (e MACCommand_TxParamSetupReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_LinkCheckAnsValidationError) ErrorName() string { - return "MACCommand_LinkCheckAnsValidationError" +func (e MACCommand_TxParamSetupReqValidationError) ErrorName() string { + return "MACCommand_TxParamSetupReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_LinkCheckAnsValidationError) Error() string { +func (e MACCommand_TxParamSetupReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4381,14 +6585,14 @@ func (e MACCommand_LinkCheckAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_LinkCheckAns.%s: %s%s", + "invalid %sMACCommand_TxParamSetupReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_LinkCheckAnsValidationError{} +var _ error = MACCommand_TxParamSetupReqValidationError{} var _ interface { Field() string @@ -4396,70 +6600,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_LinkCheckAnsValidationError{} +} = MACCommand_TxParamSetupReqValidationError{} -// ValidateFields checks the field values on MACCommand_LinkADRReq with the -// rules defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_RekeyInd with the rules +// defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_LinkADRReq) ValidateFields(paths ...string) error { +func (m *MACCommand_RekeyInd) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_LinkADRReqFieldPathsNested + paths = MACCommand_RekeyIndFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "data_rate_index": + case "minor_version": - if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { - return MACCommand_LinkADRReqValidationError{ - field: "data_rate_index", + if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { + return MACCommand_RekeyIndValidationError{ + field: "minor_version", reason: "value must be one of the defined enum values", } } - case "tx_power_index": - - if m.GetTxPowerIndex() > 15 { - return MACCommand_LinkADRReqValidationError{ - field: "tx_power_index", - reason: "value must be less than or equal to 15", - } - } - - case "channel_mask": - - if len(m.GetChannelMask()) > 16 { - return MACCommand_LinkADRReqValidationError{ - field: "channel_mask", - reason: "value must contain no more than 16 item(s)", - } - } - - case "channel_mask_control": - - if m.GetChannelMaskControl() > 7 { - return MACCommand_LinkADRReqValidationError{ - field: "channel_mask_control", - reason: "value must be less than or equal to 7", - } - } - - case "nb_trans": - - if m.GetNbTrans() > 15 { - return MACCommand_LinkADRReqValidationError{ - field: "nb_trans", - reason: "value must be less than or equal to 15", - } - } - default: - return MACCommand_LinkADRReqValidationError{ + return MACCommand_RekeyIndValidationError{ field: name, reason: "invalid field path", } @@ -4468,9 +6636,9 @@ func (m *MACCommand_LinkADRReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_LinkADRReqValidationError is the validation error returned by -// MACCommand_LinkADRReq.ValidateFields if the designated constraints aren't met. -type MACCommand_LinkADRReqValidationError struct { +// MACCommand_RekeyIndValidationError is the validation error returned by +// MACCommand_RekeyInd.ValidateFields if the designated constraints aren't met. +type MACCommand_RekeyIndValidationError struct { field string reason string cause error @@ -4478,24 +6646,24 @@ type MACCommand_LinkADRReqValidationError struct { } // Field function returns field value. -func (e MACCommand_LinkADRReqValidationError) Field() string { return e.field } +func (e MACCommand_RekeyIndValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_LinkADRReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RekeyIndValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_LinkADRReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RekeyIndValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_LinkADRReqValidationError) Key() bool { return e.key } +func (e MACCommand_RekeyIndValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_LinkADRReqValidationError) ErrorName() string { - return "MACCommand_LinkADRReqValidationError" +func (e MACCommand_RekeyIndValidationError) ErrorName() string { + return "MACCommand_RekeyIndValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_LinkADRReqValidationError) Error() string { +func (e MACCommand_RekeyIndValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4507,14 +6675,14 @@ func (e MACCommand_LinkADRReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_LinkADRReq.%s: %s%s", + "invalid %sMACCommand_RekeyInd.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_LinkADRReqValidationError{} +var _ error = MACCommand_RekeyIndValidationError{} var _ interface { Field() string @@ -4522,31 +6690,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_LinkADRReqValidationError{} +} = MACCommand_RekeyIndValidationError{} -// ValidateFields checks the field values on MACCommand_LinkADRAns with the +// ValidateFields checks the field values on MACCommand_RekeyConf with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_LinkADRAns) ValidateFields(paths ...string) error { +func (m *MACCommand_RekeyConf) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_LinkADRAnsFieldPathsNested + paths = MACCommand_RekeyConfFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "channel_mask_ack": - // no validation rules for ChannelMaskAck - case "data_rate_index_ack": - // no validation rules for DataRateIndexAck - case "tx_power_index_ack": - // no validation rules for TxPowerIndexAck + case "minor_version": + + if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { + return MACCommand_RekeyConfValidationError{ + field: "minor_version", + reason: "value must be one of the defined enum values", + } + } + default: - return MACCommand_LinkADRAnsValidationError{ + return MACCommand_RekeyConfValidationError{ field: name, reason: "invalid field path", } @@ -4555,9 +6726,9 @@ func (m *MACCommand_LinkADRAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_LinkADRAnsValidationError is the validation error returned by -// MACCommand_LinkADRAns.ValidateFields if the designated constraints aren't met. -type MACCommand_LinkADRAnsValidationError struct { +// MACCommand_RekeyConfValidationError is the validation error returned by +// MACCommand_RekeyConf.ValidateFields if the designated constraints aren't met. +type MACCommand_RekeyConfValidationError struct { field string reason string cause error @@ -4565,24 +6736,24 @@ type MACCommand_LinkADRAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_LinkADRAnsValidationError) Field() string { return e.field } +func (e MACCommand_RekeyConfValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_LinkADRAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RekeyConfValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_LinkADRAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RekeyConfValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_LinkADRAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RekeyConfValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_LinkADRAnsValidationError) ErrorName() string { - return "MACCommand_LinkADRAnsValidationError" +func (e MACCommand_RekeyConfValidationError) ErrorName() string { + return "MACCommand_RekeyConfValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_LinkADRAnsValidationError) Error() string { +func (e MACCommand_RekeyConfValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4594,14 +6765,14 @@ func (e MACCommand_LinkADRAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_LinkADRAns.%s: %s%s", + "invalid %sMACCommand_RekeyConf.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_LinkADRAnsValidationError{} +var _ error = MACCommand_RekeyConfValidationError{} var _ interface { Field() string @@ -4609,34 +6780,43 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_LinkADRAnsValidationError{} +} = MACCommand_RekeyConfValidationError{} -// ValidateFields checks the field values on MACCommand_DutyCycleReq with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DutyCycleReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_ADRParamSetupReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_ADRParamSetupReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DutyCycleReqFieldPathsNested + paths = MACCommand_ADRParamSetupReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "max_duty_cycle": + case "adr_ack_limit_exponent": - if _, ok := AggregatedDutyCycle_name[int32(m.GetMaxDutyCycle())]; !ok { - return MACCommand_DutyCycleReqValidationError{ - field: "max_duty_cycle", + if _, ok := ADRAckLimitExponent_name[int32(m.GetAdrAckLimitExponent())]; !ok { + return MACCommand_ADRParamSetupReqValidationError{ + field: "adr_ack_limit_exponent", + reason: "value must be one of the defined enum values", + } + } + + case "adr_ack_delay_exponent": + + if _, ok := ADRAckDelayExponent_name[int32(m.GetAdrAckDelayExponent())]; !ok { + return MACCommand_ADRParamSetupReqValidationError{ + field: "adr_ack_delay_exponent", reason: "value must be one of the defined enum values", } } default: - return MACCommand_DutyCycleReqValidationError{ + return MACCommand_ADRParamSetupReqValidationError{ field: name, reason: "invalid field path", } @@ -4645,9 +6825,10 @@ func (m *MACCommand_DutyCycleReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_DutyCycleReqValidationError is the validation error returned by -// MACCommand_DutyCycleReq.ValidateFields if the designated constraints aren't met. -type MACCommand_DutyCycleReqValidationError struct { +// MACCommand_ADRParamSetupReqValidationError is the validation error returned +// by MACCommand_ADRParamSetupReq.ValidateFields if the designated constraints +// aren't met. +type MACCommand_ADRParamSetupReqValidationError struct { field string reason string cause error @@ -4655,24 +6836,24 @@ type MACCommand_DutyCycleReqValidationError struct { } // Field function returns field value. -func (e MACCommand_DutyCycleReqValidationError) Field() string { return e.field } +func (e MACCommand_ADRParamSetupReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DutyCycleReqValidationError) Reason() string { return e.reason } +func (e MACCommand_ADRParamSetupReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DutyCycleReqValidationError) Cause() error { return e.cause } +func (e MACCommand_ADRParamSetupReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DutyCycleReqValidationError) Key() bool { return e.key } +func (e MACCommand_ADRParamSetupReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DutyCycleReqValidationError) ErrorName() string { - return "MACCommand_DutyCycleReqValidationError" +func (e MACCommand_ADRParamSetupReqValidationError) ErrorName() string { + return "MACCommand_ADRParamSetupReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DutyCycleReqValidationError) Error() string { +func (e MACCommand_ADRParamSetupReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4684,14 +6865,14 @@ func (e MACCommand_DutyCycleReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DutyCycleReq.%s: %s%s", + "invalid %sMACCommand_ADRParamSetupReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DutyCycleReqValidationError{} +var _ error = MACCommand_ADRParamSetupReqValidationError{} var _ interface { Field() string @@ -4699,52 +6880,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DutyCycleReqValidationError{} +} = MACCommand_ADRParamSetupReqValidationError{} -// ValidateFields checks the field values on MACCommand_RxParamSetupReq with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_RxParamSetupReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_DeviceTimeAns with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *MACCommand_DeviceTimeAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RxParamSetupReqFieldPathsNested + paths = MACCommand_DeviceTimeAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "rx2_data_rate_index": - - if _, ok := DataRateIndex_name[int32(m.GetRx2DataRateIndex())]; !ok { - return MACCommand_RxParamSetupReqValidationError{ - field: "rx2_data_rate_index", - reason: "value must be one of the defined enum values", - } - } - - case "rx1_data_rate_offset": - - if _, ok := DataRateOffset_name[int32(m.GetRx1DataRateOffset())]; !ok { - return MACCommand_RxParamSetupReqValidationError{ - field: "rx1_data_rate_offset", - reason: "value must be one of the defined enum values", - } - } - - case "rx2_frequency": + case "time": - if m.GetRx2Frequency() < 100000 { - return MACCommand_RxParamSetupReqValidationError{ - field: "rx2_frequency", - reason: "value must be greater than or equal to 100000", + if m.GetTime() == nil { + return MACCommand_DeviceTimeAnsValidationError{ + field: "time", + reason: "value is required", } } default: - return MACCommand_RxParamSetupReqValidationError{ + return MACCommand_DeviceTimeAnsValidationError{ field: name, reason: "invalid field path", } @@ -4753,10 +6916,10 @@ func (m *MACCommand_RxParamSetupReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_RxParamSetupReqValidationError is the validation error returned -// by MACCommand_RxParamSetupReq.ValidateFields if the designated constraints +// MACCommand_DeviceTimeAnsValidationError is the validation error returned by +// MACCommand_DeviceTimeAns.ValidateFields if the designated constraints // aren't met. -type MACCommand_RxParamSetupReqValidationError struct { +type MACCommand_DeviceTimeAnsValidationError struct { field string reason string cause error @@ -4764,24 +6927,24 @@ type MACCommand_RxParamSetupReqValidationError struct { } // Field function returns field value. -func (e MACCommand_RxParamSetupReqValidationError) Field() string { return e.field } +func (e MACCommand_DeviceTimeAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RxParamSetupReqValidationError) Reason() string { return e.reason } +func (e MACCommand_DeviceTimeAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RxParamSetupReqValidationError) Cause() error { return e.cause } +func (e MACCommand_DeviceTimeAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RxParamSetupReqValidationError) Key() bool { return e.key } +func (e MACCommand_DeviceTimeAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RxParamSetupReqValidationError) ErrorName() string { - return "MACCommand_RxParamSetupReqValidationError" +func (e MACCommand_DeviceTimeAnsValidationError) ErrorName() string { + return "MACCommand_DeviceTimeAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RxParamSetupReqValidationError) Error() string { +func (e MACCommand_DeviceTimeAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4793,14 +6956,14 @@ func (e MACCommand_RxParamSetupReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RxParamSetupReq.%s: %s%s", + "invalid %sMACCommand_DeviceTimeAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RxParamSetupReqValidationError{} +var _ error = MACCommand_DeviceTimeAnsValidationError{} var _ interface { Field() string @@ -4808,31 +6971,61 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RxParamSetupReqValidationError{} +} = MACCommand_DeviceTimeAnsValidationError{} -// ValidateFields checks the field values on MACCommand_RxParamSetupAns with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_RxParamSetupAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_ForceRejoinReq with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *MACCommand_ForceRejoinReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RxParamSetupAnsFieldPathsNested + paths = MACCommand_ForceRejoinReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "rx2_data_rate_index_ack": - // no validation rules for Rx2DataRateIndexAck - case "rx1_data_rate_offset_ack": - // no validation rules for Rx1DataRateOffsetAck - case "rx2_frequency_ack": - // no validation rules for Rx2FrequencyAck + case "rejoin_type": + + if _, ok := RejoinRequestType_name[int32(m.GetRejoinType())]; !ok { + return MACCommand_ForceRejoinReqValidationError{ + field: "rejoin_type", + reason: "value must be one of the defined enum values", + } + } + + case "data_rate_index": + + if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { + return MACCommand_ForceRejoinReqValidationError{ + field: "data_rate_index", + reason: "value must be one of the defined enum values", + } + } + + case "max_retries": + + if m.GetMaxRetries() > 7 { + return MACCommand_ForceRejoinReqValidationError{ + field: "max_retries", + reason: "value must be less than or equal to 7", + } + } + + case "period_exponent": + + if _, ok := RejoinPeriodExponent_name[int32(m.GetPeriodExponent())]; !ok { + return MACCommand_ForceRejoinReqValidationError{ + field: "period_exponent", + reason: "value must be one of the defined enum values", + } + } + default: - return MACCommand_RxParamSetupAnsValidationError{ + return MACCommand_ForceRejoinReqValidationError{ field: name, reason: "invalid field path", } @@ -4841,10 +7034,10 @@ func (m *MACCommand_RxParamSetupAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_RxParamSetupAnsValidationError is the validation error returned -// by MACCommand_RxParamSetupAns.ValidateFields if the designated constraints +// MACCommand_ForceRejoinReqValidationError is the validation error returned by +// MACCommand_ForceRejoinReq.ValidateFields if the designated constraints // aren't met. -type MACCommand_RxParamSetupAnsValidationError struct { +type MACCommand_ForceRejoinReqValidationError struct { field string reason string cause error @@ -4852,24 +7045,24 @@ type MACCommand_RxParamSetupAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_RxParamSetupAnsValidationError) Field() string { return e.field } +func (e MACCommand_ForceRejoinReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RxParamSetupAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_ForceRejoinReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RxParamSetupAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_ForceRejoinReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RxParamSetupAnsValidationError) Key() bool { return e.key } +func (e MACCommand_ForceRejoinReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RxParamSetupAnsValidationError) ErrorName() string { - return "MACCommand_RxParamSetupAnsValidationError" +func (e MACCommand_ForceRejoinReqValidationError) ErrorName() string { + return "MACCommand_ForceRejoinReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RxParamSetupAnsValidationError) Error() string { +func (e MACCommand_ForceRejoinReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4881,14 +7074,14 @@ func (e MACCommand_RxParamSetupAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RxParamSetupAns.%s: %s%s", + "invalid %sMACCommand_ForceRejoinReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RxParamSetupAnsValidationError{} +var _ error = MACCommand_ForceRejoinReqValidationError{} var _ interface { Field() string @@ -4896,43 +7089,43 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RxParamSetupAnsValidationError{} +} = MACCommand_ForceRejoinReqValidationError{} -// ValidateFields checks the field values on MACCommand_DevStatusAns with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DevStatusAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RejoinParamSetupReq +// with the rules defined in the proto definition for this message. If any +// rules are violated, an error is returned. +func (m *MACCommand_RejoinParamSetupReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DevStatusAnsFieldPathsNested + paths = MACCommand_RejoinParamSetupReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "battery": + case "max_count_exponent": - if m.GetBattery() > 255 { - return MACCommand_DevStatusAnsValidationError{ - field: "battery", - reason: "value must be less than or equal to 255", + if _, ok := RejoinCountExponent_name[int32(m.GetMaxCountExponent())]; !ok { + return MACCommand_RejoinParamSetupReqValidationError{ + field: "max_count_exponent", + reason: "value must be one of the defined enum values", } } - case "margin": + case "max_time_exponent": - if val := m.GetMargin(); val < -32 || val > 31 { - return MACCommand_DevStatusAnsValidationError{ - field: "margin", - reason: "value must be inside range [-32, 31]", + if _, ok := RejoinTimeExponent_name[int32(m.GetMaxTimeExponent())]; !ok { + return MACCommand_RejoinParamSetupReqValidationError{ + field: "max_time_exponent", + reason: "value must be one of the defined enum values", } } default: - return MACCommand_DevStatusAnsValidationError{ + return MACCommand_RejoinParamSetupReqValidationError{ field: name, reason: "invalid field path", } @@ -4941,9 +7134,10 @@ func (m *MACCommand_DevStatusAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_DevStatusAnsValidationError is the validation error returned by -// MACCommand_DevStatusAns.ValidateFields if the designated constraints aren't met. -type MACCommand_DevStatusAnsValidationError struct { +// MACCommand_RejoinParamSetupReqValidationError is the validation error +// returned by MACCommand_RejoinParamSetupReq.ValidateFields if the designated +// constraints aren't met. +type MACCommand_RejoinParamSetupReqValidationError struct { field string reason string cause error @@ -4951,24 +7145,24 @@ type MACCommand_DevStatusAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_DevStatusAnsValidationError) Field() string { return e.field } +func (e MACCommand_RejoinParamSetupReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DevStatusAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RejoinParamSetupReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DevStatusAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RejoinParamSetupReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DevStatusAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RejoinParamSetupReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DevStatusAnsValidationError) ErrorName() string { - return "MACCommand_DevStatusAnsValidationError" +func (e MACCommand_RejoinParamSetupReqValidationError) ErrorName() string { + return "MACCommand_RejoinParamSetupReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DevStatusAnsValidationError) Error() string { +func (e MACCommand_RejoinParamSetupReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -4980,14 +7174,14 @@ func (e MACCommand_DevStatusAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DevStatusAns.%s: %s%s", + "invalid %sMACCommand_RejoinParamSetupReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DevStatusAnsValidationError{} +var _ error = MACCommand_RejoinParamSetupReqValidationError{} var _ interface { Field() string @@ -4995,61 +7189,27 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DevStatusAnsValidationError{} +} = MACCommand_RejoinParamSetupReqValidationError{} -// ValidateFields checks the field values on MACCommand_NewChannelReq with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_NewChannelReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RejoinParamSetupAns +// with the rules defined in the proto definition for this message. If any +// rules are violated, an error is returned. +func (m *MACCommand_RejoinParamSetupAns) ValidateFields(paths ...string) error { if m == nil { return nil } - if len(paths) == 0 { - paths = MACCommand_NewChannelReqFieldPathsNested - } - - for name, subs := range _processPaths(append(paths[:0:0], paths...)) { - _ = subs - switch name { - case "channel_index": - - if m.GetChannelIndex() > 255 { - return MACCommand_NewChannelReqValidationError{ - field: "channel_index", - reason: "value must be less than or equal to 255", - } - } - - case "frequency": - - if val := m.GetFrequency(); val > 0 && val < 100000 { - return MACCommand_NewChannelReqValidationError{ - field: "frequency", - reason: "value must be outside range (0, 100000)", - } - } - - case "min_data_rate_index": - - if _, ok := DataRateIndex_name[int32(m.GetMinDataRateIndex())]; !ok { - return MACCommand_NewChannelReqValidationError{ - field: "min_data_rate_index", - reason: "value must be one of the defined enum values", - } - } - - case "max_data_rate_index": - - if _, ok := DataRateIndex_name[int32(m.GetMaxDataRateIndex())]; !ok { - return MACCommand_NewChannelReqValidationError{ - field: "max_data_rate_index", - reason: "value must be one of the defined enum values", - } - } + if len(paths) == 0 { + paths = MACCommand_RejoinParamSetupAnsFieldPathsNested + } + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "max_time_exponent_ack": + // no validation rules for MaxTimeExponentAck default: - return MACCommand_NewChannelReqValidationError{ + return MACCommand_RejoinParamSetupAnsValidationError{ field: name, reason: "invalid field path", } @@ -5058,10 +7218,10 @@ func (m *MACCommand_NewChannelReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_NewChannelReqValidationError is the validation error returned by -// MACCommand_NewChannelReq.ValidateFields if the designated constraints -// aren't met. -type MACCommand_NewChannelReqValidationError struct { +// MACCommand_RejoinParamSetupAnsValidationError is the validation error +// returned by MACCommand_RejoinParamSetupAns.ValidateFields if the designated +// constraints aren't met. +type MACCommand_RejoinParamSetupAnsValidationError struct { field string reason string cause error @@ -5069,24 +7229,24 @@ type MACCommand_NewChannelReqValidationError struct { } // Field function returns field value. -func (e MACCommand_NewChannelReqValidationError) Field() string { return e.field } +func (e MACCommand_RejoinParamSetupAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_NewChannelReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RejoinParamSetupAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_NewChannelReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RejoinParamSetupAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_NewChannelReqValidationError) Key() bool { return e.key } +func (e MACCommand_RejoinParamSetupAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_NewChannelReqValidationError) ErrorName() string { - return "MACCommand_NewChannelReqValidationError" +func (e MACCommand_RejoinParamSetupAnsValidationError) ErrorName() string { + return "MACCommand_RejoinParamSetupAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_NewChannelReqValidationError) Error() string { +func (e MACCommand_RejoinParamSetupAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5098,14 +7258,14 @@ func (e MACCommand_NewChannelReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_NewChannelReq.%s: %s%s", + "invalid %sMACCommand_RejoinParamSetupAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_NewChannelReqValidationError{} +var _ error = MACCommand_RejoinParamSetupAnsValidationError{} var _ interface { Field() string @@ -5113,29 +7273,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_NewChannelReqValidationError{} +} = MACCommand_RejoinParamSetupAnsValidationError{} -// ValidateFields checks the field values on MACCommand_NewChannelAns with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_NewChannelAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_PingSlotInfoReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_PingSlotInfoReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_NewChannelAnsFieldPathsNested + paths = MACCommand_PingSlotInfoReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "frequency_ack": - // no validation rules for FrequencyAck - case "data_rate_ack": - // no validation rules for DataRateAck + case "period": + + if _, ok := PingSlotPeriod_name[int32(m.GetPeriod())]; !ok { + return MACCommand_PingSlotInfoReqValidationError{ + field: "period", + reason: "value must be one of the defined enum values", + } + } + default: - return MACCommand_NewChannelAnsValidationError{ + return MACCommand_PingSlotInfoReqValidationError{ field: name, reason: "invalid field path", } @@ -5144,10 +7309,10 @@ func (m *MACCommand_NewChannelAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_NewChannelAnsValidationError is the validation error returned by -// MACCommand_NewChannelAns.ValidateFields if the designated constraints +// MACCommand_PingSlotInfoReqValidationError is the validation error returned +// by MACCommand_PingSlotInfoReq.ValidateFields if the designated constraints // aren't met. -type MACCommand_NewChannelAnsValidationError struct { +type MACCommand_PingSlotInfoReqValidationError struct { field string reason string cause error @@ -5155,24 +7320,24 @@ type MACCommand_NewChannelAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_NewChannelAnsValidationError) Field() string { return e.field } +func (e MACCommand_PingSlotInfoReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_NewChannelAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_PingSlotInfoReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_NewChannelAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_PingSlotInfoReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_NewChannelAnsValidationError) Key() bool { return e.key } +func (e MACCommand_PingSlotInfoReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_NewChannelAnsValidationError) ErrorName() string { - return "MACCommand_NewChannelAnsValidationError" +func (e MACCommand_PingSlotInfoReqValidationError) ErrorName() string { + return "MACCommand_PingSlotInfoReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_NewChannelAnsValidationError) Error() string { +func (e MACCommand_PingSlotInfoReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5184,14 +7349,14 @@ func (e MACCommand_NewChannelAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_NewChannelAns.%s: %s%s", + "invalid %sMACCommand_PingSlotInfoReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_NewChannelAnsValidationError{} +var _ error = MACCommand_PingSlotInfoReqValidationError{} var _ interface { Field() string @@ -5199,43 +7364,43 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_NewChannelAnsValidationError{} +} = MACCommand_PingSlotInfoReqValidationError{} -// ValidateFields checks the field values on MACCommand_DLChannelReq with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DLChannelReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_PingSlotChannelReq with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_PingSlotChannelReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DLChannelReqFieldPathsNested + paths = MACCommand_PingSlotChannelReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "channel_index": + case "frequency": - if m.GetChannelIndex() > 255 { - return MACCommand_DLChannelReqValidationError{ - field: "channel_index", - reason: "value must be less than or equal to 255", + if val := m.GetFrequency(); val > 0 && val < 100000 { + return MACCommand_PingSlotChannelReqValidationError{ + field: "frequency", + reason: "value must be outside range (0, 100000)", } } - case "frequency": + case "data_rate_index": - if m.GetFrequency() < 100000 { - return MACCommand_DLChannelReqValidationError{ - field: "frequency", - reason: "value must be greater than or equal to 100000", + if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { + return MACCommand_PingSlotChannelReqValidationError{ + field: "data_rate_index", + reason: "value must be one of the defined enum values", } } default: - return MACCommand_DLChannelReqValidationError{ + return MACCommand_PingSlotChannelReqValidationError{ field: name, reason: "invalid field path", } @@ -5244,9 +7409,10 @@ func (m *MACCommand_DLChannelReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_DLChannelReqValidationError is the validation error returned by -// MACCommand_DLChannelReq.ValidateFields if the designated constraints aren't met. -type MACCommand_DLChannelReqValidationError struct { +// MACCommand_PingSlotChannelReqValidationError is the validation error +// returned by MACCommand_PingSlotChannelReq.ValidateFields if the designated +// constraints aren't met. +type MACCommand_PingSlotChannelReqValidationError struct { field string reason string cause error @@ -5254,24 +7420,24 @@ type MACCommand_DLChannelReqValidationError struct { } // Field function returns field value. -func (e MACCommand_DLChannelReqValidationError) Field() string { return e.field } +func (e MACCommand_PingSlotChannelReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DLChannelReqValidationError) Reason() string { return e.reason } +func (e MACCommand_PingSlotChannelReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DLChannelReqValidationError) Cause() error { return e.cause } +func (e MACCommand_PingSlotChannelReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DLChannelReqValidationError) Key() bool { return e.key } +func (e MACCommand_PingSlotChannelReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DLChannelReqValidationError) ErrorName() string { - return "MACCommand_DLChannelReqValidationError" +func (e MACCommand_PingSlotChannelReqValidationError) ErrorName() string { + return "MACCommand_PingSlotChannelReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DLChannelReqValidationError) Error() string { +func (e MACCommand_PingSlotChannelReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5283,14 +7449,14 @@ func (e MACCommand_DLChannelReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DLChannelReq.%s: %s%s", + "invalid %sMACCommand_PingSlotChannelReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DLChannelReqValidationError{} +var _ error = MACCommand_PingSlotChannelReqValidationError{} var _ interface { Field() string @@ -5298,29 +7464,29 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DLChannelReqValidationError{} +} = MACCommand_PingSlotChannelReqValidationError{} -// ValidateFields checks the field values on MACCommand_DLChannelAns with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DLChannelAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_PingSlotChannelAns with +// the rules defined in the proto definition for this message. If any rules +// are violated, an error is returned. +func (m *MACCommand_PingSlotChannelAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DLChannelAnsFieldPathsNested + paths = MACCommand_PingSlotChannelAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "channel_index_ack": - // no validation rules for ChannelIndexAck case "frequency_ack": // no validation rules for FrequencyAck + case "data_rate_index_ack": + // no validation rules for DataRateIndexAck default: - return MACCommand_DLChannelAnsValidationError{ + return MACCommand_PingSlotChannelAnsValidationError{ field: name, reason: "invalid field path", } @@ -5329,9 +7495,10 @@ func (m *MACCommand_DLChannelAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_DLChannelAnsValidationError is the validation error returned by -// MACCommand_DLChannelAns.ValidateFields if the designated constraints aren't met. -type MACCommand_DLChannelAnsValidationError struct { +// MACCommand_PingSlotChannelAnsValidationError is the validation error +// returned by MACCommand_PingSlotChannelAns.ValidateFields if the designated +// constraints aren't met. +type MACCommand_PingSlotChannelAnsValidationError struct { field string reason string cause error @@ -5339,24 +7506,24 @@ type MACCommand_DLChannelAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_DLChannelAnsValidationError) Field() string { return e.field } +func (e MACCommand_PingSlotChannelAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DLChannelAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_PingSlotChannelAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DLChannelAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_PingSlotChannelAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DLChannelAnsValidationError) Key() bool { return e.key } +func (e MACCommand_PingSlotChannelAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DLChannelAnsValidationError) ErrorName() string { - return "MACCommand_DLChannelAnsValidationError" +func (e MACCommand_PingSlotChannelAnsValidationError) ErrorName() string { + return "MACCommand_PingSlotChannelAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DLChannelAnsValidationError) Error() string { +func (e MACCommand_PingSlotChannelAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5368,14 +7535,14 @@ func (e MACCommand_DLChannelAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DLChannelAns.%s: %s%s", + "invalid %sMACCommand_PingSlotChannelAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DLChannelAnsValidationError{} +var _ error = MACCommand_PingSlotChannelAnsValidationError{} var _ interface { Field() string @@ -5383,18 +7550,18 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DLChannelAnsValidationError{} +} = MACCommand_PingSlotChannelAnsValidationError{} -// ValidateFields checks the field values on MACCommand_RxTimingSetupReq with +// ValidateFields checks the field values on MACCommand_BeaconTimingAns with // the rules defined in the proto definition for this message. If any rules // are violated, an error is returned. -func (m *MACCommand_RxTimingSetupReq) ValidateFields(paths ...string) error { +func (m *MACCommand_BeaconTimingAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RxTimingSetupReqFieldPathsNested + paths = MACCommand_BeaconTimingAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { @@ -5402,15 +7569,24 @@ func (m *MACCommand_RxTimingSetupReq) ValidateFields(paths ...string) error { switch name { case "delay": - if _, ok := RxDelay_name[int32(m.GetDelay())]; !ok { - return MACCommand_RxTimingSetupReqValidationError{ + if m.GetDelay() > 65535 { + return MACCommand_BeaconTimingAnsValidationError{ field: "delay", - reason: "value must be one of the defined enum values", + reason: "value must be less than or equal to 65535", + } + } + + case "channel_index": + + if m.GetChannelIndex() > 255 { + return MACCommand_BeaconTimingAnsValidationError{ + field: "channel_index", + reason: "value must be less than or equal to 255", } } default: - return MACCommand_RxTimingSetupReqValidationError{ + return MACCommand_BeaconTimingAnsValidationError{ field: name, reason: "invalid field path", } @@ -5419,10 +7595,10 @@ func (m *MACCommand_RxTimingSetupReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_RxTimingSetupReqValidationError is the validation error returned -// by MACCommand_RxTimingSetupReq.ValidateFields if the designated constraints +// MACCommand_BeaconTimingAnsValidationError is the validation error returned +// by MACCommand_BeaconTimingAns.ValidateFields if the designated constraints // aren't met. -type MACCommand_RxTimingSetupReqValidationError struct { +type MACCommand_BeaconTimingAnsValidationError struct { field string reason string cause error @@ -5430,24 +7606,24 @@ type MACCommand_RxTimingSetupReqValidationError struct { } // Field function returns field value. -func (e MACCommand_RxTimingSetupReqValidationError) Field() string { return e.field } +func (e MACCommand_BeaconTimingAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RxTimingSetupReqValidationError) Reason() string { return e.reason } +func (e MACCommand_BeaconTimingAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RxTimingSetupReqValidationError) Cause() error { return e.cause } +func (e MACCommand_BeaconTimingAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RxTimingSetupReqValidationError) Key() bool { return e.key } +func (e MACCommand_BeaconTimingAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RxTimingSetupReqValidationError) ErrorName() string { - return "MACCommand_RxTimingSetupReqValidationError" +func (e MACCommand_BeaconTimingAnsValidationError) ErrorName() string { + return "MACCommand_BeaconTimingAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RxTimingSetupReqValidationError) Error() string { +func (e MACCommand_BeaconTimingAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5459,14 +7635,14 @@ func (e MACCommand_RxTimingSetupReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RxTimingSetupReq.%s: %s%s", + "invalid %sMACCommand_BeaconTimingAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RxTimingSetupReqValidationError{} +var _ error = MACCommand_BeaconTimingAnsValidationError{} var _ interface { Field() string @@ -5474,38 +7650,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RxTimingSetupReqValidationError{} +} = MACCommand_BeaconTimingAnsValidationError{} -// ValidateFields checks the field values on MACCommand_TxParamSetupReq with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_TxParamSetupReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_BeaconFreqReq with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *MACCommand_BeaconFreqReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_TxParamSetupReqFieldPathsNested + paths = MACCommand_BeaconFreqReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "max_eirp_index": + case "frequency": - if _, ok := DeviceEIRP_name[int32(m.GetMaxEirpIndex())]; !ok { - return MACCommand_TxParamSetupReqValidationError{ - field: "max_eirp_index", - reason: "value must be one of the defined enum values", + if val := m.GetFrequency(); val > 0 && val < 100000 { + return MACCommand_BeaconFreqReqValidationError{ + field: "frequency", + reason: "value must be outside range (0, 100000)", } } - case "uplink_dwell_time": - // no validation rules for UplinkDwellTime - case "downlink_dwell_time": - // no validation rules for DownlinkDwellTime default: - return MACCommand_TxParamSetupReqValidationError{ + return MACCommand_BeaconFreqReqValidationError{ field: name, reason: "invalid field path", } @@ -5514,10 +7686,10 @@ func (m *MACCommand_TxParamSetupReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_TxParamSetupReqValidationError is the validation error returned -// by MACCommand_TxParamSetupReq.ValidateFields if the designated constraints +// MACCommand_BeaconFreqReqValidationError is the validation error returned by +// MACCommand_BeaconFreqReq.ValidateFields if the designated constraints // aren't met. -type MACCommand_TxParamSetupReqValidationError struct { +type MACCommand_BeaconFreqReqValidationError struct { field string reason string cause error @@ -5525,24 +7697,24 @@ type MACCommand_TxParamSetupReqValidationError struct { } // Field function returns field value. -func (e MACCommand_TxParamSetupReqValidationError) Field() string { return e.field } +func (e MACCommand_BeaconFreqReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_TxParamSetupReqValidationError) Reason() string { return e.reason } +func (e MACCommand_BeaconFreqReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_TxParamSetupReqValidationError) Cause() error { return e.cause } +func (e MACCommand_BeaconFreqReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_TxParamSetupReqValidationError) Key() bool { return e.key } +func (e MACCommand_BeaconFreqReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_TxParamSetupReqValidationError) ErrorName() string { - return "MACCommand_TxParamSetupReqValidationError" +func (e MACCommand_BeaconFreqReqValidationError) ErrorName() string { + return "MACCommand_BeaconFreqReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_TxParamSetupReqValidationError) Error() string { +func (e MACCommand_BeaconFreqReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5554,14 +7726,14 @@ func (e MACCommand_TxParamSetupReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_TxParamSetupReq.%s: %s%s", + "invalid %sMACCommand_BeaconFreqReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_TxParamSetupReqValidationError{} +var _ error = MACCommand_BeaconFreqReqValidationError{} var _ interface { Field() string @@ -5569,34 +7741,27 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_TxParamSetupReqValidationError{} +} = MACCommand_BeaconFreqReqValidationError{} -// ValidateFields checks the field values on MACCommand_RekeyInd with the rules -// defined in the proto definition for this message. If any rules are +// ValidateFields checks the field values on MACCommand_BeaconFreqAns with the +// rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_RekeyInd) ValidateFields(paths ...string) error { +func (m *MACCommand_BeaconFreqAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RekeyIndFieldPathsNested + paths = MACCommand_BeaconFreqAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "minor_version": - - if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { - return MACCommand_RekeyIndValidationError{ - field: "minor_version", - reason: "value must be one of the defined enum values", - } - } - + case "frequency_ack": + // no validation rules for FrequencyAck default: - return MACCommand_RekeyIndValidationError{ + return MACCommand_BeaconFreqAnsValidationError{ field: name, reason: "invalid field path", } @@ -5605,9 +7770,10 @@ func (m *MACCommand_RekeyInd) ValidateFields(paths ...string) error { return nil } -// MACCommand_RekeyIndValidationError is the validation error returned by -// MACCommand_RekeyInd.ValidateFields if the designated constraints aren't met. -type MACCommand_RekeyIndValidationError struct { +// MACCommand_BeaconFreqAnsValidationError is the validation error returned by +// MACCommand_BeaconFreqAns.ValidateFields if the designated constraints +// aren't met. +type MACCommand_BeaconFreqAnsValidationError struct { field string reason string cause error @@ -5615,24 +7781,24 @@ type MACCommand_RekeyIndValidationError struct { } // Field function returns field value. -func (e MACCommand_RekeyIndValidationError) Field() string { return e.field } +func (e MACCommand_BeaconFreqAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RekeyIndValidationError) Reason() string { return e.reason } +func (e MACCommand_BeaconFreqAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RekeyIndValidationError) Cause() error { return e.cause } +func (e MACCommand_BeaconFreqAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RekeyIndValidationError) Key() bool { return e.key } +func (e MACCommand_BeaconFreqAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RekeyIndValidationError) ErrorName() string { - return "MACCommand_RekeyIndValidationError" +func (e MACCommand_BeaconFreqAnsValidationError) ErrorName() string { + return "MACCommand_BeaconFreqAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RekeyIndValidationError) Error() string { +func (e MACCommand_BeaconFreqAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5644,14 +7810,14 @@ func (e MACCommand_RekeyIndValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RekeyInd.%s: %s%s", + "invalid %sMACCommand_BeaconFreqAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RekeyIndValidationError{} +var _ error = MACCommand_BeaconFreqAnsValidationError{} var _ interface { Field() string @@ -5659,34 +7825,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RekeyIndValidationError{} +} = MACCommand_BeaconFreqAnsValidationError{} -// ValidateFields checks the field values on MACCommand_RekeyConf with the +// ValidateFields checks the field values on MACCommand_DeviceModeInd with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_RekeyConf) ValidateFields(paths ...string) error { +func (m *MACCommand_DeviceModeInd) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RekeyConfFieldPathsNested + paths = MACCommand_DeviceModeIndFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "minor_version": + case "class": - if _, ok := Minor_name[int32(m.GetMinorVersion())]; !ok { - return MACCommand_RekeyConfValidationError{ - field: "minor_version", + if _, ok := Class_name[int32(m.GetClass())]; !ok { + return MACCommand_DeviceModeIndValidationError{ + field: "class", reason: "value must be one of the defined enum values", } } default: - return MACCommand_RekeyConfValidationError{ + return MACCommand_DeviceModeIndValidationError{ field: name, reason: "invalid field path", } @@ -5695,9 +7861,10 @@ func (m *MACCommand_RekeyConf) ValidateFields(paths ...string) error { return nil } -// MACCommand_RekeyConfValidationError is the validation error returned by -// MACCommand_RekeyConf.ValidateFields if the designated constraints aren't met. -type MACCommand_RekeyConfValidationError struct { +// MACCommand_DeviceModeIndValidationError is the validation error returned by +// MACCommand_DeviceModeInd.ValidateFields if the designated constraints +// aren't met. +type MACCommand_DeviceModeIndValidationError struct { field string reason string cause error @@ -5705,24 +7872,24 @@ type MACCommand_RekeyConfValidationError struct { } // Field function returns field value. -func (e MACCommand_RekeyConfValidationError) Field() string { return e.field } +func (e MACCommand_DeviceModeIndValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RekeyConfValidationError) Reason() string { return e.reason } +func (e MACCommand_DeviceModeIndValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RekeyConfValidationError) Cause() error { return e.cause } +func (e MACCommand_DeviceModeIndValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RekeyConfValidationError) Key() bool { return e.key } +func (e MACCommand_DeviceModeIndValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RekeyConfValidationError) ErrorName() string { - return "MACCommand_RekeyConfValidationError" +func (e MACCommand_DeviceModeIndValidationError) ErrorName() string { + return "MACCommand_DeviceModeIndValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RekeyConfValidationError) Error() string { +func (e MACCommand_DeviceModeIndValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5734,14 +7901,14 @@ func (e MACCommand_RekeyConfValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RekeyConf.%s: %s%s", + "invalid %sMACCommand_DeviceModeInd.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RekeyConfValidationError{} +var _ error = MACCommand_DeviceModeIndValidationError{} var _ interface { Field() string @@ -5749,43 +7916,34 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RekeyConfValidationError{} +} = MACCommand_DeviceModeIndValidationError{} -// ValidateFields checks the field values on MACCommand_ADRParamSetupReq with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_ADRParamSetupReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_DeviceModeConf with the +// rules defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *MACCommand_DeviceModeConf) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_ADRParamSetupReqFieldPathsNested + paths = MACCommand_DeviceModeConfFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "adr_ack_limit_exponent": - - if _, ok := ADRAckLimitExponent_name[int32(m.GetAdrAckLimitExponent())]; !ok { - return MACCommand_ADRParamSetupReqValidationError{ - field: "adr_ack_limit_exponent", - reason: "value must be one of the defined enum values", - } - } - - case "adr_ack_delay_exponent": + case "class": - if _, ok := ADRAckDelayExponent_name[int32(m.GetAdrAckDelayExponent())]; !ok { - return MACCommand_ADRParamSetupReqValidationError{ - field: "adr_ack_delay_exponent", + if _, ok := Class_name[int32(m.GetClass())]; !ok { + return MACCommand_DeviceModeConfValidationError{ + field: "class", reason: "value must be one of the defined enum values", } } default: - return MACCommand_ADRParamSetupReqValidationError{ + return MACCommand_DeviceModeConfValidationError{ field: name, reason: "invalid field path", } @@ -5794,10 +7952,10 @@ func (m *MACCommand_ADRParamSetupReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_ADRParamSetupReqValidationError is the validation error returned -// by MACCommand_ADRParamSetupReq.ValidateFields if the designated constraints +// MACCommand_DeviceModeConfValidationError is the validation error returned by +// MACCommand_DeviceModeConf.ValidateFields if the designated constraints // aren't met. -type MACCommand_ADRParamSetupReqValidationError struct { +type MACCommand_DeviceModeConfValidationError struct { field string reason string cause error @@ -5805,24 +7963,24 @@ type MACCommand_ADRParamSetupReqValidationError struct { } // Field function returns field value. -func (e MACCommand_ADRParamSetupReqValidationError) Field() string { return e.field } +func (e MACCommand_DeviceModeConfValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_ADRParamSetupReqValidationError) Reason() string { return e.reason } +func (e MACCommand_DeviceModeConfValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_ADRParamSetupReqValidationError) Cause() error { return e.cause } +func (e MACCommand_DeviceModeConfValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_ADRParamSetupReqValidationError) Key() bool { return e.key } +func (e MACCommand_DeviceModeConfValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_ADRParamSetupReqValidationError) ErrorName() string { - return "MACCommand_ADRParamSetupReqValidationError" +func (e MACCommand_DeviceModeConfValidationError) ErrorName() string { + return "MACCommand_DeviceModeConfValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_ADRParamSetupReqValidationError) Error() string { +func (e MACCommand_DeviceModeConfValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5834,14 +7992,14 @@ func (e MACCommand_ADRParamSetupReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_ADRParamSetupReq.%s: %s%s", + "invalid %sMACCommand_DeviceModeConf.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_ADRParamSetupReqValidationError{} +var _ error = MACCommand_DeviceModeConfValidationError{} var _ interface { Field() string @@ -5849,34 +8007,37 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_ADRParamSetupReqValidationError{} +} = MACCommand_DeviceModeConfValidationError{} -// ValidateFields checks the field values on MACCommand_DeviceTimeAns with the +// ValidateFields checks the field values on MACCommand_RelayConfReq with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_DeviceTimeAns) ValidateFields(paths ...string) error { +func (m *MACCommand_RelayConfReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DeviceTimeAnsFieldPathsNested + paths = MACCommand_RelayConfReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "time": + case "configuration": - if m.GetTime() == nil { - return MACCommand_DeviceTimeAnsValidationError{ - field: "time", - reason: "value is required", + if v, ok := interface{}(m.GetConfiguration()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfReqValidationError{ + field: "configuration", + reason: "embedded message failed validation", + cause: err, + } } } default: - return MACCommand_DeviceTimeAnsValidationError{ + return MACCommand_RelayConfReqValidationError{ field: name, reason: "invalid field path", } @@ -5885,10 +8046,9 @@ func (m *MACCommand_DeviceTimeAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_DeviceTimeAnsValidationError is the validation error returned by -// MACCommand_DeviceTimeAns.ValidateFields if the designated constraints -// aren't met. -type MACCommand_DeviceTimeAnsValidationError struct { +// MACCommand_RelayConfReqValidationError is the validation error returned by +// MACCommand_RelayConfReq.ValidateFields if the designated constraints aren't met. +type MACCommand_RelayConfReqValidationError struct { field string reason string cause error @@ -5896,24 +8056,24 @@ type MACCommand_DeviceTimeAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_DeviceTimeAnsValidationError) Field() string { return e.field } +func (e MACCommand_RelayConfReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DeviceTimeAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayConfReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DeviceTimeAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayConfReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DeviceTimeAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RelayConfReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DeviceTimeAnsValidationError) ErrorName() string { - return "MACCommand_DeviceTimeAnsValidationError" +func (e MACCommand_RelayConfReqValidationError) ErrorName() string { + return "MACCommand_RelayConfReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DeviceTimeAnsValidationError) Error() string { +func (e MACCommand_RelayConfReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -5925,14 +8085,14 @@ func (e MACCommand_DeviceTimeAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DeviceTimeAns.%s: %s%s", + "invalid %sMACCommand_RelayConfReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DeviceTimeAnsValidationError{} +var _ error = MACCommand_RelayConfReqValidationError{} var _ interface { Field() string @@ -5940,73 +8100,48 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DeviceTimeAnsValidationError{} +} = MACCommand_RelayConfReqValidationError{} -// ValidateFields checks the field values on MACCommand_ForceRejoinReq with the +// ValidateFields checks the field values on MACCommand_RelayConfAns with the // rules defined in the proto definition for this message. If any rules are // violated, an error is returned. -func (m *MACCommand_ForceRejoinReq) ValidateFields(paths ...string) error { +func (m *MACCommand_RelayConfAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_ForceRejoinReqFieldPathsNested + paths = MACCommand_RelayConfAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "rejoin_type": - - if _, ok := RejoinRequestType_name[int32(m.GetRejoinType())]; !ok { - return MACCommand_ForceRejoinReqValidationError{ - field: "rejoin_type", - reason: "value must be one of the defined enum values", - } - } - - case "data_rate_index": - - if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { - return MACCommand_ForceRejoinReqValidationError{ - field: "data_rate_index", - reason: "value must be one of the defined enum values", - } - } - - case "max_retries": - - if m.GetMaxRetries() > 7 { - return MACCommand_ForceRejoinReqValidationError{ - field: "max_retries", - reason: "value must be less than or equal to 7", - } - } - - case "period_exponent": - - if _, ok := RejoinPeriodExponent_name[int32(m.GetPeriodExponent())]; !ok { - return MACCommand_ForceRejoinReqValidationError{ - field: "period_exponent", - reason: "value must be one of the defined enum values", - } - } - + case "second_channel_frequency_ack": + // no validation rules for SecondChannelFrequencyAck + case "second_channel_ack_offset_ack": + // no validation rules for SecondChannelAckOffsetAck + case "second_channel_data_rate_index_ack": + // no validation rules for SecondChannelDataRateIndexAck + case "second_channel_index_ack": + // no validation rules for SecondChannelIndexAck + case "default_channel_index_ack": + // no validation rules for DefaultChannelIndexAck + case "cad_periodicity_ack": + // no validation rules for CadPeriodicityAck default: - return MACCommand_ForceRejoinReqValidationError{ + return MACCommand_RelayConfAnsValidationError{ field: name, reason: "invalid field path", } } } - return nil -} - -// MACCommand_ForceRejoinReqValidationError is the validation error returned by -// MACCommand_ForceRejoinReq.ValidateFields if the designated constraints -// aren't met. -type MACCommand_ForceRejoinReqValidationError struct { + return nil +} + +// MACCommand_RelayConfAnsValidationError is the validation error returned by +// MACCommand_RelayConfAns.ValidateFields if the designated constraints aren't met. +type MACCommand_RelayConfAnsValidationError struct { field string reason string cause error @@ -6014,24 +8149,24 @@ type MACCommand_ForceRejoinReqValidationError struct { } // Field function returns field value. -func (e MACCommand_ForceRejoinReqValidationError) Field() string { return e.field } +func (e MACCommand_RelayConfAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_ForceRejoinReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayConfAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_ForceRejoinReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayConfAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_ForceRejoinReqValidationError) Key() bool { return e.key } +func (e MACCommand_RelayConfAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_ForceRejoinReqValidationError) ErrorName() string { - return "MACCommand_ForceRejoinReqValidationError" +func (e MACCommand_RelayConfAnsValidationError) ErrorName() string { + return "MACCommand_RelayConfAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_ForceRejoinReqValidationError) Error() string { +func (e MACCommand_RelayConfAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6043,14 +8178,14 @@ func (e MACCommand_ForceRejoinReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_ForceRejoinReq.%s: %s%s", + "invalid %sMACCommand_RelayConfAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_ForceRejoinReqValidationError{} +var _ error = MACCommand_RelayConfAnsValidationError{} var _ interface { Field() string @@ -6058,43 +8193,37 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_ForceRejoinReqValidationError{} +} = MACCommand_RelayConfAnsValidationError{} -// ValidateFields checks the field values on MACCommand_RejoinParamSetupReq +// ValidateFields checks the field values on MACCommand_RelayEndDeviceConfReq // with the rules defined in the proto definition for this message. If any // rules are violated, an error is returned. -func (m *MACCommand_RejoinParamSetupReq) ValidateFields(paths ...string) error { +func (m *MACCommand_RelayEndDeviceConfReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RejoinParamSetupReqFieldPathsNested + paths = MACCommand_RelayEndDeviceConfReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "max_count_exponent": - - if _, ok := RejoinCountExponent_name[int32(m.GetMaxCountExponent())]; !ok { - return MACCommand_RejoinParamSetupReqValidationError{ - field: "max_count_exponent", - reason: "value must be one of the defined enum values", - } - } + case "configuration": - case "max_time_exponent": - - if _, ok := RejoinTimeExponent_name[int32(m.GetMaxTimeExponent())]; !ok { - return MACCommand_RejoinParamSetupReqValidationError{ - field: "max_time_exponent", - reason: "value must be one of the defined enum values", + if v, ok := interface{}(m.GetConfiguration()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayEndDeviceConfReqValidationError{ + field: "configuration", + reason: "embedded message failed validation", + cause: err, + } } } default: - return MACCommand_RejoinParamSetupReqValidationError{ + return MACCommand_RelayEndDeviceConfReqValidationError{ field: name, reason: "invalid field path", } @@ -6103,10 +8232,10 @@ func (m *MACCommand_RejoinParamSetupReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_RejoinParamSetupReqValidationError is the validation error -// returned by MACCommand_RejoinParamSetupReq.ValidateFields if the designated -// constraints aren't met. -type MACCommand_RejoinParamSetupReqValidationError struct { +// MACCommand_RelayEndDeviceConfReqValidationError is the validation error +// returned by MACCommand_RelayEndDeviceConfReq.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayEndDeviceConfReqValidationError struct { field string reason string cause error @@ -6114,24 +8243,24 @@ type MACCommand_RejoinParamSetupReqValidationError struct { } // Field function returns field value. -func (e MACCommand_RejoinParamSetupReqValidationError) Field() string { return e.field } +func (e MACCommand_RelayEndDeviceConfReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RejoinParamSetupReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayEndDeviceConfReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RejoinParamSetupReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayEndDeviceConfReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RejoinParamSetupReqValidationError) Key() bool { return e.key } +func (e MACCommand_RelayEndDeviceConfReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RejoinParamSetupReqValidationError) ErrorName() string { - return "MACCommand_RejoinParamSetupReqValidationError" +func (e MACCommand_RelayEndDeviceConfReqValidationError) ErrorName() string { + return "MACCommand_RelayEndDeviceConfReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RejoinParamSetupReqValidationError) Error() string { +func (e MACCommand_RelayEndDeviceConfReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6143,14 +8272,14 @@ func (e MACCommand_RejoinParamSetupReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RejoinParamSetupReq.%s: %s%s", + "invalid %sMACCommand_RelayEndDeviceConfReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RejoinParamSetupReqValidationError{} +var _ error = MACCommand_RelayEndDeviceConfReqValidationError{} var _ interface { Field() string @@ -6158,27 +8287,33 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RejoinParamSetupReqValidationError{} +} = MACCommand_RelayEndDeviceConfReqValidationError{} -// ValidateFields checks the field values on MACCommand_RejoinParamSetupAns +// ValidateFields checks the field values on MACCommand_RelayEndDeviceConfAns // with the rules defined in the proto definition for this message. If any // rules are violated, an error is returned. -func (m *MACCommand_RejoinParamSetupAns) ValidateFields(paths ...string) error { +func (m *MACCommand_RelayEndDeviceConfAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_RejoinParamSetupAnsFieldPathsNested + paths = MACCommand_RelayEndDeviceConfAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "max_time_exponent_ack": - // no validation rules for MaxTimeExponentAck + case "second_channel_frequency_ack": + // no validation rules for SecondChannelFrequencyAck + case "second_channel_data_rate_index_ack": + // no validation rules for SecondChannelDataRateIndexAck + case "second_channel_index_ack": + // no validation rules for SecondChannelIndexAck + case "backoff_ack": + // no validation rules for BackoffAck default: - return MACCommand_RejoinParamSetupAnsValidationError{ + return MACCommand_RelayEndDeviceConfAnsValidationError{ field: name, reason: "invalid field path", } @@ -6187,10 +8322,10 @@ func (m *MACCommand_RejoinParamSetupAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_RejoinParamSetupAnsValidationError is the validation error -// returned by MACCommand_RejoinParamSetupAns.ValidateFields if the designated -// constraints aren't met. -type MACCommand_RejoinParamSetupAnsValidationError struct { +// MACCommand_RelayEndDeviceConfAnsValidationError is the validation error +// returned by MACCommand_RelayEndDeviceConfAns.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayEndDeviceConfAnsValidationError struct { field string reason string cause error @@ -6198,24 +8333,24 @@ type MACCommand_RejoinParamSetupAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_RejoinParamSetupAnsValidationError) Field() string { return e.field } +func (e MACCommand_RelayEndDeviceConfAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_RejoinParamSetupAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayEndDeviceConfAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_RejoinParamSetupAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayEndDeviceConfAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_RejoinParamSetupAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RelayEndDeviceConfAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_RejoinParamSetupAnsValidationError) ErrorName() string { - return "MACCommand_RejoinParamSetupAnsValidationError" +func (e MACCommand_RelayEndDeviceConfAnsValidationError) ErrorName() string { + return "MACCommand_RelayEndDeviceConfAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_RejoinParamSetupAnsValidationError) Error() string { +func (e MACCommand_RelayEndDeviceConfAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6227,14 +8362,14 @@ func (e MACCommand_RejoinParamSetupAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_RejoinParamSetupAns.%s: %s%s", + "invalid %sMACCommand_RelayEndDeviceConfAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_RejoinParamSetupAnsValidationError{} +var _ error = MACCommand_RelayEndDeviceConfAnsValidationError{} var _ interface { Field() string @@ -6242,34 +8377,92 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_RejoinParamSetupAnsValidationError{} +} = MACCommand_RelayEndDeviceConfAnsValidationError{} -// ValidateFields checks the field values on MACCommand_PingSlotInfoReq with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_PingSlotInfoReq) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on +// MACCommand_RelayUpdateUplinkListReq with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayUpdateUplinkListReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_PingSlotInfoReqFieldPathsNested + paths = MACCommand_RelayUpdateUplinkListReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "period": + case "rule_index": - if _, ok := PingSlotPeriod_name[int32(m.GetPeriod())]; !ok { - return MACCommand_PingSlotInfoReqValidationError{ - field: "period", - reason: "value must be one of the defined enum values", + if m.GetRuleIndex() > 15 { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "rule_index", + reason: "value must be less than or equal to 15", + } + } + + case "forward_limits": + + if v, ok := interface{}(m.GetForwardLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "forward_limits", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dev_addr": + + if len(m.GetDevAddr()) > 0 { + + if len(m.GetDevAddr()) != 4 { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "dev_addr", + reason: "value length must be 4 bytes", + } + } + + } + + case "w_f_cnt": + // no validation rules for WFCnt + case "root_wor_s_key": + + if len(m.GetRootWorSKey()) > 0 { + + if len(m.GetRootWorSKey()) != 16 { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "root_wor_s_key", + reason: "value length must be 16 bytes", + } + } + + } + + case "device_id": + + if utf8.RuneCountInString(m.GetDeviceId()) > 36 { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "device_id", + reason: "value length must be at most 36 runes", + } + } + + if !_MACCommand_RelayUpdateUplinkListReq_DeviceId_Pattern.MatchString(m.GetDeviceId()) { + return MACCommand_RelayUpdateUplinkListReqValidationError{ + field: "device_id", + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", } } + case "session_key_id": + // no validation rules for SessionKeyId default: - return MACCommand_PingSlotInfoReqValidationError{ + return MACCommand_RelayUpdateUplinkListReqValidationError{ field: name, reason: "invalid field path", } @@ -6278,10 +8471,10 @@ func (m *MACCommand_PingSlotInfoReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_PingSlotInfoReqValidationError is the validation error returned -// by MACCommand_PingSlotInfoReq.ValidateFields if the designated constraints -// aren't met. -type MACCommand_PingSlotInfoReqValidationError struct { +// MACCommand_RelayUpdateUplinkListReqValidationError is the validation error +// returned by MACCommand_RelayUpdateUplinkListReq.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayUpdateUplinkListReqValidationError struct { field string reason string cause error @@ -6289,24 +8482,24 @@ type MACCommand_PingSlotInfoReqValidationError struct { } // Field function returns field value. -func (e MACCommand_PingSlotInfoReqValidationError) Field() string { return e.field } +func (e MACCommand_RelayUpdateUplinkListReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_PingSlotInfoReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayUpdateUplinkListReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_PingSlotInfoReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayUpdateUplinkListReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_PingSlotInfoReqValidationError) Key() bool { return e.key } +func (e MACCommand_RelayUpdateUplinkListReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_PingSlotInfoReqValidationError) ErrorName() string { - return "MACCommand_PingSlotInfoReqValidationError" +func (e MACCommand_RelayUpdateUplinkListReqValidationError) ErrorName() string { + return "MACCommand_RelayUpdateUplinkListReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_PingSlotInfoReqValidationError) Error() string { +func (e MACCommand_RelayUpdateUplinkListReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6318,14 +8511,14 @@ func (e MACCommand_PingSlotInfoReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_PingSlotInfoReq.%s: %s%s", + "invalid %sMACCommand_RelayUpdateUplinkListReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_PingSlotInfoReqValidationError{} +var _ error = MACCommand_RelayUpdateUplinkListReqValidationError{} var _ interface { Field() string @@ -6333,43 +8526,105 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_PingSlotInfoReqValidationError{} +} = MACCommand_RelayUpdateUplinkListReqValidationError{} -// ValidateFields checks the field values on MACCommand_PingSlotChannelReq with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_PingSlotChannelReq) ValidateFields(paths ...string) error { +var _MACCommand_RelayUpdateUplinkListReq_DeviceId_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") + +// ValidateFields checks the field values on +// MACCommand_RelayUpdateUplinkListAns with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayUpdateUplinkListAns) ValidateFields(paths ...string) error { + if len(paths) > 0 { + return fmt.Errorf("message MACCommand_RelayUpdateUplinkListAns has no fields, but paths %s were specified", paths) + } + return nil +} + +// MACCommand_RelayUpdateUplinkListAnsValidationError is the validation error +// returned by MACCommand_RelayUpdateUplinkListAns.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayUpdateUplinkListAnsValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) ErrorName() string { + return "MACCommand_RelayUpdateUplinkListAnsValidationError" +} + +// Error satisfies the builtin error interface +func (e MACCommand_RelayUpdateUplinkListAnsValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sMACCommand_RelayUpdateUplinkListAns.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = MACCommand_RelayUpdateUplinkListAnsValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = MACCommand_RelayUpdateUplinkListAnsValidationError{} + +// ValidateFields checks the field values on MACCommand_RelayCtrlUplinkListReq +// with the rules defined in the proto definition for this message. If any +// rules are violated, an error is returned. +func (m *MACCommand_RelayCtrlUplinkListReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_PingSlotChannelReqFieldPathsNested + paths = MACCommand_RelayCtrlUplinkListReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "frequency": - - if val := m.GetFrequency(); val > 0 && val < 100000 { - return MACCommand_PingSlotChannelReqValidationError{ - field: "frequency", - reason: "value must be outside range (0, 100000)", - } - } + case "rule_index": - case "data_rate_index": - - if _, ok := DataRateIndex_name[int32(m.GetDataRateIndex())]; !ok { - return MACCommand_PingSlotChannelReqValidationError{ - field: "data_rate_index", - reason: "value must be one of the defined enum values", + if m.GetRuleIndex() > 15 { + return MACCommand_RelayCtrlUplinkListReqValidationError{ + field: "rule_index", + reason: "value must be less than or equal to 15", } } + case "action": + // no validation rules for Action default: - return MACCommand_PingSlotChannelReqValidationError{ + return MACCommand_RelayCtrlUplinkListReqValidationError{ field: name, reason: "invalid field path", } @@ -6378,10 +8633,10 @@ func (m *MACCommand_PingSlotChannelReq) ValidateFields(paths ...string) error { return nil } -// MACCommand_PingSlotChannelReqValidationError is the validation error -// returned by MACCommand_PingSlotChannelReq.ValidateFields if the designated -// constraints aren't met. -type MACCommand_PingSlotChannelReqValidationError struct { +// MACCommand_RelayCtrlUplinkListReqValidationError is the validation error +// returned by MACCommand_RelayCtrlUplinkListReq.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayCtrlUplinkListReqValidationError struct { field string reason string cause error @@ -6389,24 +8644,24 @@ type MACCommand_PingSlotChannelReqValidationError struct { } // Field function returns field value. -func (e MACCommand_PingSlotChannelReqValidationError) Field() string { return e.field } +func (e MACCommand_RelayCtrlUplinkListReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_PingSlotChannelReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayCtrlUplinkListReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_PingSlotChannelReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayCtrlUplinkListReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_PingSlotChannelReqValidationError) Key() bool { return e.key } +func (e MACCommand_RelayCtrlUplinkListReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_PingSlotChannelReqValidationError) ErrorName() string { - return "MACCommand_PingSlotChannelReqValidationError" +func (e MACCommand_RelayCtrlUplinkListReqValidationError) ErrorName() string { + return "MACCommand_RelayCtrlUplinkListReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_PingSlotChannelReqValidationError) Error() string { +func (e MACCommand_RelayCtrlUplinkListReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6418,14 +8673,14 @@ func (e MACCommand_PingSlotChannelReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_PingSlotChannelReq.%s: %s%s", + "invalid %sMACCommand_RelayCtrlUplinkListReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_PingSlotChannelReqValidationError{} +var _ error = MACCommand_RelayCtrlUplinkListReqValidationError{} var _ interface { Field() string @@ -6433,29 +8688,29 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_PingSlotChannelReqValidationError{} +} = MACCommand_RelayCtrlUplinkListReqValidationError{} -// ValidateFields checks the field values on MACCommand_PingSlotChannelAns with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_PingSlotChannelAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on MACCommand_RelayCtrlUplinkListAns +// with the rules defined in the proto definition for this message. If any +// rules are violated, an error is returned. +func (m *MACCommand_RelayCtrlUplinkListAns) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_PingSlotChannelAnsFieldPathsNested + paths = MACCommand_RelayCtrlUplinkListAnsFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "frequency_ack": - // no validation rules for FrequencyAck - case "data_rate_index_ack": - // no validation rules for DataRateIndexAck + case "rule_index_ack": + // no validation rules for RuleIndexAck + case "w_f_cnt": + // no validation rules for WFCnt default: - return MACCommand_PingSlotChannelAnsValidationError{ + return MACCommand_RelayCtrlUplinkListAnsValidationError{ field: name, reason: "invalid field path", } @@ -6464,10 +8719,10 @@ func (m *MACCommand_PingSlotChannelAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_PingSlotChannelAnsValidationError is the validation error -// returned by MACCommand_PingSlotChannelAns.ValidateFields if the designated -// constraints aren't met. -type MACCommand_PingSlotChannelAnsValidationError struct { +// MACCommand_RelayCtrlUplinkListAnsValidationError is the validation error +// returned by MACCommand_RelayCtrlUplinkListAns.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayCtrlUplinkListAnsValidationError struct { field string reason string cause error @@ -6475,24 +8730,24 @@ type MACCommand_PingSlotChannelAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_PingSlotChannelAnsValidationError) Field() string { return e.field } +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_PingSlotChannelAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_PingSlotChannelAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_PingSlotChannelAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_PingSlotChannelAnsValidationError) ErrorName() string { - return "MACCommand_PingSlotChannelAnsValidationError" +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) ErrorName() string { + return "MACCommand_RelayCtrlUplinkListAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_PingSlotChannelAnsValidationError) Error() string { +func (e MACCommand_RelayCtrlUplinkListAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6504,14 +8759,14 @@ func (e MACCommand_PingSlotChannelAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_PingSlotChannelAns.%s: %s%s", + "invalid %sMACCommand_RelayCtrlUplinkListAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_PingSlotChannelAnsValidationError{} +var _ error = MACCommand_RelayCtrlUplinkListAnsValidationError{} var _ interface { Field() string @@ -6519,43 +8774,75 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_PingSlotChannelAnsValidationError{} +} = MACCommand_RelayCtrlUplinkListAnsValidationError{} -// ValidateFields checks the field values on MACCommand_BeaconTimingAns with -// the rules defined in the proto definition for this message. If any rules -// are violated, an error is returned. -func (m *MACCommand_BeaconTimingAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on +// MACCommand_RelayConfigureFwdLimitReq with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayConfigureFwdLimitReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_BeaconTimingAnsFieldPathsNested + paths = MACCommand_RelayConfigureFwdLimitReqFieldPathsNested } - for name, subs := range _processPaths(append(paths[:0:0], paths...)) { - _ = subs - switch name { - case "delay": + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "reset_limit_counter": + // no validation rules for ResetLimitCounter + case "join_request_limits": + + if v, ok := interface{}(m.GetJoinRequestLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfigureFwdLimitReqValidationError{ + field: "join_request_limits", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "notify_limits": - if m.GetDelay() > 65535 { - return MACCommand_BeaconTimingAnsValidationError{ - field: "delay", - reason: "value must be less than or equal to 65535", + if v, ok := interface{}(m.GetNotifyLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfigureFwdLimitReqValidationError{ + field: "notify_limits", + reason: "embedded message failed validation", + cause: err, + } } } - case "channel_index": + case "global_uplink_limits": - if m.GetChannelIndex() > 255 { - return MACCommand_BeaconTimingAnsValidationError{ - field: "channel_index", - reason: "value must be less than or equal to 255", + if v, ok := interface{}(m.GetGlobalUplinkLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfigureFwdLimitReqValidationError{ + field: "global_uplink_limits", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "overall_limits": + + if v, ok := interface{}(m.GetOverallLimits()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfigureFwdLimitReqValidationError{ + field: "overall_limits", + reason: "embedded message failed validation", + cause: err, + } } } default: - return MACCommand_BeaconTimingAnsValidationError{ + return MACCommand_RelayConfigureFwdLimitReqValidationError{ field: name, reason: "invalid field path", } @@ -6564,10 +8851,10 @@ func (m *MACCommand_BeaconTimingAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_BeaconTimingAnsValidationError is the validation error returned -// by MACCommand_BeaconTimingAns.ValidateFields if the designated constraints -// aren't met. -type MACCommand_BeaconTimingAnsValidationError struct { +// MACCommand_RelayConfigureFwdLimitReqValidationError is the validation error +// returned by MACCommand_RelayConfigureFwdLimitReq.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayConfigureFwdLimitReqValidationError struct { field string reason string cause error @@ -6575,24 +8862,24 @@ type MACCommand_BeaconTimingAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_BeaconTimingAnsValidationError) Field() string { return e.field } +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_BeaconTimingAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_BeaconTimingAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_BeaconTimingAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_BeaconTimingAnsValidationError) ErrorName() string { - return "MACCommand_BeaconTimingAnsValidationError" +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) ErrorName() string { + return "MACCommand_RelayConfigureFwdLimitReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_BeaconTimingAnsValidationError) Error() string { +func (e MACCommand_RelayConfigureFwdLimitReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6604,14 +8891,14 @@ func (e MACCommand_BeaconTimingAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_BeaconTimingAns.%s: %s%s", + "invalid %sMACCommand_RelayConfigureFwdLimitReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_BeaconTimingAnsValidationError{} +var _ error = MACCommand_RelayConfigureFwdLimitReqValidationError{} var _ interface { Field() string @@ -6619,46 +8906,22 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_BeaconTimingAnsValidationError{} - -// ValidateFields checks the field values on MACCommand_BeaconFreqReq with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_BeaconFreqReq) ValidateFields(paths ...string) error { - if m == nil { - return nil - } - - if len(paths) == 0 { - paths = MACCommand_BeaconFreqReqFieldPathsNested - } - - for name, subs := range _processPaths(append(paths[:0:0], paths...)) { - _ = subs - switch name { - case "frequency": - - if val := m.GetFrequency(); val > 0 && val < 100000 { - return MACCommand_BeaconFreqReqValidationError{ - field: "frequency", - reason: "value must be outside range (0, 100000)", - } - } +} = MACCommand_RelayConfigureFwdLimitReqValidationError{} - default: - return MACCommand_BeaconFreqReqValidationError{ - field: name, - reason: "invalid field path", - } - } +// ValidateFields checks the field values on +// MACCommand_RelayConfigureFwdLimitAns with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayConfigureFwdLimitAns) ValidateFields(paths ...string) error { + if len(paths) > 0 { + return fmt.Errorf("message MACCommand_RelayConfigureFwdLimitAns has no fields, but paths %s were specified", paths) } return nil } -// MACCommand_BeaconFreqReqValidationError is the validation error returned by -// MACCommand_BeaconFreqReq.ValidateFields if the designated constraints -// aren't met. -type MACCommand_BeaconFreqReqValidationError struct { +// MACCommand_RelayConfigureFwdLimitAnsValidationError is the validation error +// returned by MACCommand_RelayConfigureFwdLimitAns.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayConfigureFwdLimitAnsValidationError struct { field string reason string cause error @@ -6666,24 +8929,24 @@ type MACCommand_BeaconFreqReqValidationError struct { } // Field function returns field value. -func (e MACCommand_BeaconFreqReqValidationError) Field() string { return e.field } +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_BeaconFreqReqValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_BeaconFreqReqValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_BeaconFreqReqValidationError) Key() bool { return e.key } +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_BeaconFreqReqValidationError) ErrorName() string { - return "MACCommand_BeaconFreqReqValidationError" +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) ErrorName() string { + return "MACCommand_RelayConfigureFwdLimitAnsValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_BeaconFreqReqValidationError) Error() string { +func (e MACCommand_RelayConfigureFwdLimitAnsValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6695,14 +8958,14 @@ func (e MACCommand_BeaconFreqReqValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_BeaconFreqReq.%s: %s%s", + "invalid %sMACCommand_RelayConfigureFwdLimitAns.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_BeaconFreqReqValidationError{} +var _ error = MACCommand_RelayConfigureFwdLimitAnsValidationError{} var _ interface { Field() string @@ -6710,27 +8973,56 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_BeaconFreqReqValidationError{} +} = MACCommand_RelayConfigureFwdLimitAnsValidationError{} -// ValidateFields checks the field values on MACCommand_BeaconFreqAns with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_BeaconFreqAns) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on +// MACCommand_RelayNotifyNewEndDeviceReq with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayNotifyNewEndDeviceReq) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_BeaconFreqAnsFieldPathsNested + paths = MACCommand_RelayNotifyNewEndDeviceReqFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "frequency_ack": - // no validation rules for FrequencyAck + case "dev_addr": + + if len(m.GetDevAddr()) > 0 { + + if len(m.GetDevAddr()) != 4 { + return MACCommand_RelayNotifyNewEndDeviceReqValidationError{ + field: "dev_addr", + reason: "value length must be 4 bytes", + } + } + + } + + case "snr": + + if val := m.GetSnr(); val < -20 || val > 11 { + return MACCommand_RelayNotifyNewEndDeviceReqValidationError{ + field: "snr", + reason: "value must be inside range [-20, 11]", + } + } + + case "rssi": + + if val := m.GetRssi(); val < -142 || val > -15 { + return MACCommand_RelayNotifyNewEndDeviceReqValidationError{ + field: "rssi", + reason: "value must be inside range [-142, -15]", + } + } + default: - return MACCommand_BeaconFreqAnsValidationError{ + return MACCommand_RelayNotifyNewEndDeviceReqValidationError{ field: name, reason: "invalid field path", } @@ -6739,10 +9031,10 @@ func (m *MACCommand_BeaconFreqAns) ValidateFields(paths ...string) error { return nil } -// MACCommand_BeaconFreqAnsValidationError is the validation error returned by -// MACCommand_BeaconFreqAns.ValidateFields if the designated constraints -// aren't met. -type MACCommand_BeaconFreqAnsValidationError struct { +// MACCommand_RelayNotifyNewEndDeviceReqValidationError is the validation error +// returned by MACCommand_RelayNotifyNewEndDeviceReq.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayNotifyNewEndDeviceReqValidationError struct { field string reason string cause error @@ -6750,24 +9042,24 @@ type MACCommand_BeaconFreqAnsValidationError struct { } // Field function returns field value. -func (e MACCommand_BeaconFreqAnsValidationError) Field() string { return e.field } +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_BeaconFreqAnsValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_BeaconFreqAnsValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_BeaconFreqAnsValidationError) Key() bool { return e.key } +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_BeaconFreqAnsValidationError) ErrorName() string { - return "MACCommand_BeaconFreqAnsValidationError" +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) ErrorName() string { + return "MACCommand_RelayNotifyNewEndDeviceReqValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_BeaconFreqAnsValidationError) Error() string { +func (e MACCommand_RelayNotifyNewEndDeviceReqValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6779,14 +9071,14 @@ func (e MACCommand_BeaconFreqAnsValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_BeaconFreqAns.%s: %s%s", + "invalid %sMACCommand_RelayNotifyNewEndDeviceReq.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_BeaconFreqAnsValidationError{} +var _ error = MACCommand_RelayNotifyNewEndDeviceReqValidationError{} var _ interface { Field() string @@ -6794,34 +9086,55 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_BeaconFreqAnsValidationError{} +} = MACCommand_RelayNotifyNewEndDeviceReqValidationError{} -// ValidateFields checks the field values on MACCommand_DeviceModeInd with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DeviceModeInd) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on +// MACCommand_RelayConfReq_Configuration with the rules defined in the proto +// definition for this message. If any rules are violated, an error is returned. +func (m *MACCommand_RelayConfReq_Configuration) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DeviceModeIndFieldPathsNested + paths = MACCommand_RelayConfReq_ConfigurationFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "class": + case "second_channel": - if _, ok := Class_name[int32(m.GetClass())]; !ok { - return MACCommand_DeviceModeIndValidationError{ - field: "class", + if v, ok := interface{}(m.GetSecondChannel()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayConfReq_ConfigurationValidationError{ + field: "second_channel", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "default_channel_index": + + if m.GetDefaultChannelIndex() > 255 { + return MACCommand_RelayConfReq_ConfigurationValidationError{ + field: "default_channel_index", + reason: "value must be less than or equal to 255", + } + } + + case "cad_periodicity": + + if _, ok := RelayCADPeriodicity_name[int32(m.GetCadPeriodicity())]; !ok { + return MACCommand_RelayConfReq_ConfigurationValidationError{ + field: "cad_periodicity", reason: "value must be one of the defined enum values", } } default: - return MACCommand_DeviceModeIndValidationError{ + return MACCommand_RelayConfReq_ConfigurationValidationError{ field: name, reason: "invalid field path", } @@ -6830,10 +9143,10 @@ func (m *MACCommand_DeviceModeInd) ValidateFields(paths ...string) error { return nil } -// MACCommand_DeviceModeIndValidationError is the validation error returned by -// MACCommand_DeviceModeInd.ValidateFields if the designated constraints -// aren't met. -type MACCommand_DeviceModeIndValidationError struct { +// MACCommand_RelayConfReq_ConfigurationValidationError is the validation error +// returned by MACCommand_RelayConfReq_Configuration.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayConfReq_ConfigurationValidationError struct { field string reason string cause error @@ -6841,24 +9154,24 @@ type MACCommand_DeviceModeIndValidationError struct { } // Field function returns field value. -func (e MACCommand_DeviceModeIndValidationError) Field() string { return e.field } +func (e MACCommand_RelayConfReq_ConfigurationValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DeviceModeIndValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayConfReq_ConfigurationValidationError) Reason() string { return e.reason } // Cause function returns cause value. -func (e MACCommand_DeviceModeIndValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayConfReq_ConfigurationValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DeviceModeIndValidationError) Key() bool { return e.key } +func (e MACCommand_RelayConfReq_ConfigurationValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DeviceModeIndValidationError) ErrorName() string { - return "MACCommand_DeviceModeIndValidationError" +func (e MACCommand_RelayConfReq_ConfigurationValidationError) ErrorName() string { + return "MACCommand_RelayConfReq_ConfigurationValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DeviceModeIndValidationError) Error() string { +func (e MACCommand_RelayConfReq_ConfigurationValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6870,14 +9183,14 @@ func (e MACCommand_DeviceModeIndValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DeviceModeInd.%s: %s%s", + "invalid %sMACCommand_RelayConfReq_Configuration.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DeviceModeIndValidationError{} +var _ error = MACCommand_RelayConfReq_ConfigurationValidationError{} var _ interface { Field() string @@ -6885,34 +9198,128 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DeviceModeIndValidationError{} +} = MACCommand_RelayConfReq_ConfigurationValidationError{} -// ValidateFields checks the field values on MACCommand_DeviceModeConf with the -// rules defined in the proto definition for this message. If any rules are -// violated, an error is returned. -func (m *MACCommand_DeviceModeConf) ValidateFields(paths ...string) error { +// ValidateFields checks the field values on +// MACCommand_RelayEndDeviceConfReq_Configuration with the rules defined in +// the proto definition for this message. If any rules are violated, an error +// is returned. +func (m *MACCommand_RelayEndDeviceConfReq_Configuration) ValidateFields(paths ...string) error { if m == nil { return nil } if len(paths) == 0 { - paths = MACCommand_DeviceModeConfFieldPathsNested + paths = MACCommand_RelayEndDeviceConfReq_ConfigurationFieldPathsNested } for name, subs := range _processPaths(append(paths[:0:0], paths...)) { _ = subs switch name { - case "class": + case "backoff": - if _, ok := Class_name[int32(m.GetClass())]; !ok { - return MACCommand_DeviceModeConfValidationError{ - field: "class", - reason: "value must be one of the defined enum values", + if m.GetBackoff() > 63 { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "backoff", + reason: "value must be less than or equal to 63", + } + } + + case "second_channel": + + if v, ok := interface{}(m.GetSecondChannel()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "second_channel", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "serving_device_id": + + if utf8.RuneCountInString(m.GetServingDeviceId()) > 36 { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "serving_device_id", + reason: "value length must be at most 36 runes", + } + } + + if !_MACCommand_RelayEndDeviceConfReq_Configuration_ServingDeviceId_Pattern.MatchString(m.GetServingDeviceId()) { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "serving_device_id", + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + case "mode": + if m.Mode == nil { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "mode", + reason: "value is required", + } + } + if len(subs) == 0 { + subs = []string{ + "always", "dynamic", "end_device_controlled", } } + for name, subs := range _processPaths(subs) { + _ = subs + switch name { + case "always": + w, ok := m.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Always) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetAlways()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "always", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "dynamic": + w, ok := m.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetDynamic()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "dynamic", + reason: "embedded message failed validation", + cause: err, + } + } + } + + case "end_device_controlled": + w, ok := m.Mode.(*MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled) + if !ok || w == nil { + continue + } + + if v, ok := interface{}(m.GetEndDeviceControlled()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ + field: "end_device_controlled", + reason: "embedded message failed validation", + cause: err, + } + } + } + } + } default: - return MACCommand_DeviceModeConfValidationError{ + return MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{ field: name, reason: "invalid field path", } @@ -6921,10 +9328,11 @@ func (m *MACCommand_DeviceModeConf) ValidateFields(paths ...string) error { return nil } -// MACCommand_DeviceModeConfValidationError is the validation error returned by -// MACCommand_DeviceModeConf.ValidateFields if the designated constraints -// aren't met. -type MACCommand_DeviceModeConfValidationError struct { +// MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError is the +// validation error returned by +// MACCommand_RelayEndDeviceConfReq_Configuration.ValidateFields if the +// designated constraints aren't met. +type MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError struct { field string reason string cause error @@ -6932,24 +9340,26 @@ type MACCommand_DeviceModeConfValidationError struct { } // Field function returns field value. -func (e MACCommand_DeviceModeConfValidationError) Field() string { return e.field } +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) Field() string { return e.field } // Reason function returns reason value. -func (e MACCommand_DeviceModeConfValidationError) Reason() string { return e.reason } +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) Reason() string { + return e.reason +} // Cause function returns cause value. -func (e MACCommand_DeviceModeConfValidationError) Cause() error { return e.cause } +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) Cause() error { return e.cause } // Key function returns key value. -func (e MACCommand_DeviceModeConfValidationError) Key() bool { return e.key } +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) Key() bool { return e.key } // ErrorName returns error name. -func (e MACCommand_DeviceModeConfValidationError) ErrorName() string { - return "MACCommand_DeviceModeConfValidationError" +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) ErrorName() string { + return "MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError" } // Error satisfies the builtin error interface -func (e MACCommand_DeviceModeConfValidationError) Error() string { +func (e MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError) Error() string { cause := "" if e.cause != nil { cause = fmt.Sprintf(" | caused by: %v", e.cause) @@ -6961,14 +9371,14 @@ func (e MACCommand_DeviceModeConfValidationError) Error() string { } return fmt.Sprintf( - "invalid %sMACCommand_DeviceModeConf.%s: %s%s", + "invalid %sMACCommand_RelayEndDeviceConfReq_Configuration.%s: %s%s", key, e.field, e.reason, cause) } -var _ error = MACCommand_DeviceModeConfValidationError{} +var _ error = MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{} var _ interface { Field() string @@ -6976,4 +9386,6 @@ var _ interface { Key() bool Cause() error ErrorName() string -} = MACCommand_DeviceModeConfValidationError{} +} = MACCommand_RelayEndDeviceConfReq_ConfigurationValidationError{} + +var _MACCommand_RelayEndDeviceConfReq_Configuration_ServingDeviceId_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") diff --git a/pkg/ttnpb/lorawan_flags.pb.go b/pkg/ttnpb/lorawan_flags.pb.go index c46fef0ce9..ab460b1687 100644 --- a/pkg/ttnpb/lorawan_flags.pb.go +++ b/pkg/ttnpb/lorawan_flags.pb.go @@ -8,6 +8,7 @@ package ttnpb import ( flagsplugin "github.com/TheThingsIndustries/protoc-gen-go-flags/flagsplugin" + golang "github.com/TheThingsIndustries/protoc-gen-go-flags/golang" pflag "github.com/spf13/pflag" customflags "go.thethings.network/lorawan-stack/v3/cmd/ttn-lw-cli/customflags" ) @@ -509,6 +510,36 @@ func PathsFromSelectFlagsForLoRaDataRate(flags *pflag.FlagSet, prefix string) (p return paths, nil } +// AddSetFlagsForLoRaDataRate adds flags to select fields in LoRaDataRate. +func AddSetFlagsForLoRaDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("bandwidth", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("spreading-factor", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("coding-rate", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the LoRaDataRate message from flags. +func (m *LoRaDataRate) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("bandwidth", prefix)); err != nil { + return nil, err + } else if changed { + m.Bandwidth = val + paths = append(paths, flagsplugin.Prefix("bandwidth", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("spreading_factor", prefix)); err != nil { + return nil, err + } else if changed { + m.SpreadingFactor = val + paths = append(paths, flagsplugin.Prefix("spreading_factor", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("coding_rate", prefix)); err != nil { + return nil, err + } else if changed { + m.CodingRate = val + paths = append(paths, flagsplugin.Prefix("coding_rate", prefix)) + } + return paths, nil +} + // AddSelectFlagsForFSKDataRate adds flags to select fields in FSKDataRate. func AddSelectFlagsForFSKDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("bit-rate", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("bit-rate", prefix), false), flagsplugin.WithHidden(hidden))) @@ -524,6 +555,22 @@ func PathsFromSelectFlagsForFSKDataRate(flags *pflag.FlagSet, prefix string) (pa return paths, nil } +// AddSetFlagsForFSKDataRate adds flags to select fields in FSKDataRate. +func AddSetFlagsForFSKDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("bit-rate", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the FSKDataRate message from flags. +func (m *FSKDataRate) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("bit_rate", prefix)); err != nil { + return nil, err + } else if changed { + m.BitRate = val + paths = append(paths, flagsplugin.Prefix("bit_rate", prefix)) + } + return paths, nil +} + // AddSelectFlagsForLRFHSSDataRate adds flags to select fields in LRFHSSDataRate. func AddSelectFlagsForLRFHSSDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("modulation-type", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("modulation-type", prefix), false), flagsplugin.WithHidden(hidden))) @@ -551,6 +598,36 @@ func PathsFromSelectFlagsForLRFHSSDataRate(flags *pflag.FlagSet, prefix string) return paths, nil } +// AddSetFlagsForLRFHSSDataRate adds flags to select fields in LRFHSSDataRate. +func AddSetFlagsForLRFHSSDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("modulation-type", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("operating-channel-width", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("coding-rate", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the LRFHSSDataRate message from flags. +func (m *LRFHSSDataRate) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("modulation_type", prefix)); err != nil { + return nil, err + } else if changed { + m.ModulationType = val + paths = append(paths, flagsplugin.Prefix("modulation_type", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("operating_channel_width", prefix)); err != nil { + return nil, err + } else if changed { + m.OperatingChannelWidth = val + paths = append(paths, flagsplugin.Prefix("operating_channel_width", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("coding_rate", prefix)); err != nil { + return nil, err + } else if changed { + m.CodingRate = val + paths = append(paths, flagsplugin.Prefix("coding_rate", prefix)) + } + return paths, nil +} + // AddSelectFlagsForDataRate adds flags to select fields in DataRate. func AddSelectFlagsForDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("modulation.lora", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("modulation.lora", prefix), true), flagsplugin.WithHidden(hidden))) @@ -596,6 +673,54 @@ func PathsFromSelectFlagsForDataRate(flags *pflag.FlagSet, prefix string) (paths return paths, nil } +// AddSetFlagsForDataRate adds flags to select fields in DataRate. +func AddSetFlagsForDataRate(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForLoRaDataRate(flags, flagsplugin.Prefix("modulation.lora", prefix), hidden) + AddSetFlagsForFSKDataRate(flags, flagsplugin.Prefix("modulation.fsk", prefix), hidden) + AddSetFlagsForLRFHSSDataRate(flags, flagsplugin.Prefix("modulation.lrfhss", prefix), hidden) +} + +// SetFromFlags sets the DataRate message from flags. +func (m *DataRate) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("modulation.lora", prefix)); changed { + ov := &DataRate_Lora{} + if ov.Lora == nil { + ov.Lora = &LoRaDataRate{} + } + if setPaths, err := ov.Lora.SetFromFlags(flags, flagsplugin.Prefix("modulation.lora", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + m.Modulation = ov + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("modulation.fsk", prefix)); changed { + ov := &DataRate_Fsk{} + if ov.Fsk == nil { + ov.Fsk = &FSKDataRate{} + } + if setPaths, err := ov.Fsk.SetFromFlags(flags, flagsplugin.Prefix("modulation.fsk", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + m.Modulation = ov + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("modulation.lrfhss", prefix)); changed { + ov := &DataRate_Lrfhss{} + if ov.Lrfhss == nil { + ov.Lrfhss = &LRFHSSDataRate{} + } + if setPaths, err := ov.Lrfhss.SetFromFlags(flags, flagsplugin.Prefix("modulation.lrfhss", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + m.Modulation = ov + } + return paths, nil +} + // AddSelectFlagsForTxSettings_Downlink adds flags to select fields in TxSettings_Downlink. func AddSelectFlagsForTxSettings_Downlink(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("antenna-index", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("antenna-index", prefix), false), flagsplugin.WithHidden(hidden))) @@ -623,6 +748,36 @@ func PathsFromSelectFlagsForTxSettings_Downlink(flags *pflag.FlagSet, prefix str return paths, nil } +// AddSetFlagsForTxSettings_Downlink adds flags to select fields in TxSettings_Downlink. +func AddSetFlagsForTxSettings_Downlink(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("antenna-index", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewFloat32Flag(flagsplugin.Prefix("tx-power", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("invert-polarization", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the TxSettings_Downlink message from flags. +func (m *TxSettings_Downlink) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("antenna_index", prefix)); err != nil { + return nil, err + } else if changed { + m.AntennaIndex = val + paths = append(paths, flagsplugin.Prefix("antenna_index", prefix)) + } + if val, changed, err := flagsplugin.GetFloat32(flags, flagsplugin.Prefix("tx_power", prefix)); err != nil { + return nil, err + } else if changed { + m.TxPower = val + paths = append(paths, flagsplugin.Prefix("tx_power", prefix)) + } + if val, changed, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("invert_polarization", prefix)); err != nil { + return nil, err + } else if changed { + m.InvertPolarization = val + paths = append(paths, flagsplugin.Prefix("invert_polarization", prefix)) + } + return paths, nil +} + // AddSelectFlagsForTxSettings adds flags to select fields in TxSettings. func AddSelectFlagsForTxSettings(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("data-rate", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("data-rate", prefix), true), flagsplugin.WithHidden(hidden))) @@ -686,6 +841,480 @@ func PathsFromSelectFlagsForTxSettings(flags *pflag.FlagSet, prefix string) (pat return paths, nil } +// AddSetFlagsForTxSettings adds flags to select fields in TxSettings. +func AddSetFlagsForTxSettings(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForDataRate(flags, flagsplugin.Prefix("data-rate", prefix), hidden) + flags.AddFlag(flagsplugin.NewUint64Flag(flagsplugin.Prefix("frequency", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("enable-crc", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("timestamp", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewTimestampFlag(flagsplugin.Prefix("time", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForTxSettings_Downlink(flags, flagsplugin.Prefix("downlink", prefix), hidden) + flags.AddFlag(flagsplugin.NewInt64Flag(flagsplugin.Prefix("concentrator-timestamp", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the TxSettings message from flags. +func (m *TxSettings) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("data_rate", prefix)); changed { + if m.DataRate == nil { + m.DataRate = &DataRate{} + } + if setPaths, err := m.DataRate.SetFromFlags(flags, flagsplugin.Prefix("data_rate", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetUint64(flags, flagsplugin.Prefix("frequency", prefix)); err != nil { + return nil, err + } else if changed { + m.Frequency = val + paths = append(paths, flagsplugin.Prefix("frequency", prefix)) + } + if val, changed, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("enable_crc", prefix)); err != nil { + return nil, err + } else if changed { + m.EnableCrc = val + paths = append(paths, flagsplugin.Prefix("enable_crc", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("timestamp", prefix)); err != nil { + return nil, err + } else if changed { + m.Timestamp = val + paths = append(paths, flagsplugin.Prefix("timestamp", prefix)) + } + if val, changed, err := flagsplugin.GetTimestamp(flags, flagsplugin.Prefix("time", prefix)); err != nil { + return nil, err + } else if changed { + m.Time = golang.SetTimestamp(val) + paths = append(paths, flagsplugin.Prefix("time", prefix)) + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("downlink", prefix)); changed { + if m.Downlink == nil { + m.Downlink = &TxSettings_Downlink{} + } + if setPaths, err := m.Downlink.SetFromFlags(flags, flagsplugin.Prefix("downlink", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetInt64(flags, flagsplugin.Prefix("concentrator_timestamp", prefix)); err != nil { + return nil, err + } else if changed { + m.ConcentratorTimestamp = val + paths = append(paths, flagsplugin.Prefix("concentrator_timestamp", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelaySecondChannel adds flags to select fields in RelaySecondChannel. +func AddSelectFlagsForRelaySecondChannel(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("ack-offset", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("ack-offset", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("data-rate-index", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("data-rate-index", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("frequency", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("frequency", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelaySecondChannel message from select flags. +func PathsFromSelectFlagsForRelaySecondChannel(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("ack_offset", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("ack_offset", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("data_rate_index", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("data_rate_index", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("frequency", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("frequency", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelaySecondChannel adds flags to select fields in RelaySecondChannel. +func AddSetFlagsForRelaySecondChannel(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("ack-offset", prefix), flagsplugin.EnumValueDesc(RelaySecondChAckOffset_value), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("data-rate-index", prefix), flagsplugin.EnumValueDesc(DataRateIndex_value, DataRateIndex_customvalue), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint64Flag(flagsplugin.Prefix("frequency", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelaySecondChannel message from flags. +func (m *RelaySecondChannel) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("ack_offset", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelaySecondChAckOffset_value) + if err != nil { + return nil, err + } + m.AckOffset = RelaySecondChAckOffset(enumValue) + paths = append(paths, flagsplugin.Prefix("ack_offset", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("data_rate_index", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, DataRateIndex_value, DataRateIndex_customvalue) + if err != nil { + return nil, err + } + m.DataRateIndex = DataRateIndex(enumValue) + paths = append(paths, flagsplugin.Prefix("data_rate_index", prefix)) + } + if val, changed, err := flagsplugin.GetUint64(flags, flagsplugin.Prefix("frequency", prefix)); err != nil { + return nil, err + } else if changed { + m.Frequency = val + paths = append(paths, flagsplugin.Prefix("frequency", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayUplinkForwardLimits adds flags to select fields in RelayUplinkForwardLimits. +func AddSelectFlagsForRelayUplinkForwardLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("bucket-size", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("bucket-size", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("reload-rate", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("reload-rate", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayUplinkForwardLimits message from select flags. +func PathsFromSelectFlagsForRelayUplinkForwardLimits(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("bucket_size", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("bucket_size", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("reload_rate", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("reload_rate", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayUplinkForwardLimits adds flags to select fields in RelayUplinkForwardLimits. +func AddSetFlagsForRelayUplinkForwardLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("bucket-size", prefix), flagsplugin.EnumValueDesc(RelayLimitBucketSize_value), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("reload-rate", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayUplinkForwardLimits message from flags. +func (m *RelayUplinkForwardLimits) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("bucket_size", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelayLimitBucketSize_value) + if err != nil { + return nil, err + } + m.BucketSize = RelayLimitBucketSize(enumValue) + paths = append(paths, flagsplugin.Prefix("bucket_size", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("reload_rate", prefix)); err != nil { + return nil, err + } else if changed { + m.ReloadRate = val + paths = append(paths, flagsplugin.Prefix("reload_rate", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayForwardLimits adds flags to select fields in RelayForwardLimits. +func AddSelectFlagsForRelayForwardLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("bucket-size", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("bucket-size", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("reload-rate", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("reload-rate", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayForwardLimits message from select flags. +func PathsFromSelectFlagsForRelayForwardLimits(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("bucket_size", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("bucket_size", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("reload_rate", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("reload_rate", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayForwardLimits adds flags to select fields in RelayForwardLimits. +func AddSetFlagsForRelayForwardLimits(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("bucket-size", prefix), flagsplugin.EnumValueDesc(RelayLimitBucketSize_value), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("reload-rate", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayForwardLimits message from flags. +func (m *RelayForwardLimits) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("bucket_size", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelayLimitBucketSize_value) + if err != nil { + return nil, err + } + m.BucketSize = RelayLimitBucketSize(enumValue) + paths = append(paths, flagsplugin.Prefix("bucket_size", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("reload_rate", prefix)); err != nil { + return nil, err + } else if changed { + m.ReloadRate = val + paths = append(paths, flagsplugin.Prefix("reload_rate", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayEndDeviceAlwaysMode adds flags to select fields in RelayEndDeviceAlwaysMode. +func AddSelectFlagsForRelayEndDeviceAlwaysMode(flags *pflag.FlagSet, prefix string, hidden bool) { +} + +// SelectFromFlags outputs the fieldmask paths forRelayEndDeviceAlwaysMode message from select flags. +func PathsFromSelectFlagsForRelayEndDeviceAlwaysMode(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + return paths, nil +} + +// AddSetFlagsForRelayEndDeviceAlwaysMode adds flags to select fields in RelayEndDeviceAlwaysMode. +func AddSetFlagsForRelayEndDeviceAlwaysMode(flags *pflag.FlagSet, prefix string, hidden bool) { +} + +// SetFromFlags sets the RelayEndDeviceAlwaysMode message from flags. +func (m *RelayEndDeviceAlwaysMode) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + return paths, nil +} + +// AddSelectFlagsForRelayEndDeviceDynamicMode adds flags to select fields in RelayEndDeviceDynamicMode. +func AddSelectFlagsForRelayEndDeviceDynamicMode(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("smart-enable-level", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("smart-enable-level", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayEndDeviceDynamicMode message from select flags. +func PathsFromSelectFlagsForRelayEndDeviceDynamicMode(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("smart_enable_level", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("smart_enable_level", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayEndDeviceDynamicMode adds flags to select fields in RelayEndDeviceDynamicMode. +func AddSetFlagsForRelayEndDeviceDynamicMode(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("smart-enable-level", prefix), flagsplugin.EnumValueDesc(RelaySmartEnableLevel_value), flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayEndDeviceDynamicMode message from flags. +func (m *RelayEndDeviceDynamicMode) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("smart_enable_level", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelaySmartEnableLevel_value) + if err != nil { + return nil, err + } + m.SmartEnableLevel = RelaySmartEnableLevel(enumValue) + paths = append(paths, flagsplugin.Prefix("smart_enable_level", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayEndDeviceControlledMode adds flags to select fields in RelayEndDeviceControlledMode. +func AddSelectFlagsForRelayEndDeviceControlledMode(flags *pflag.FlagSet, prefix string, hidden bool) { +} + +// SelectFromFlags outputs the fieldmask paths forRelayEndDeviceControlledMode message from select flags. +func PathsFromSelectFlagsForRelayEndDeviceControlledMode(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + return paths, nil +} + +// AddSetFlagsForRelayEndDeviceControlledMode adds flags to select fields in RelayEndDeviceControlledMode. +func AddSetFlagsForRelayEndDeviceControlledMode(flags *pflag.FlagSet, prefix string, hidden bool) { +} + +// SetFromFlags sets the RelayEndDeviceControlledMode message from flags. +func (m *RelayEndDeviceControlledMode) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + return paths, nil +} + +// AddSelectFlagsForMACCommand_RelayUpdateUplinkListReq adds flags to select fields in MACCommand_RelayUpdateUplinkListReq. +func AddSelectFlagsForMACCommand_RelayUpdateUplinkListReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("rule-index", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("rule-index", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("forward-limits", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("forward-limits", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("forward-limits", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("dev-addr", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("dev-addr", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("w-f-cnt", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("w-f-cnt", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("root-wor-s-key", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("root-wor-s-key", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("device-id", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("device-id", 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))) +} + +// SelectFromFlags outputs the fieldmask paths forMACCommand_RelayUpdateUplinkListReq message from select flags. +func PathsFromSelectFlagsForMACCommand_RelayUpdateUplinkListReq(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("rule_index", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("rule_index", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("forward_limits", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("forward_limits", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("forward_limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("dev_addr", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("dev_addr", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("w_f_cnt", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("w_f_cnt", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("root_wor_s_key", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("root_wor_s_key", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("device_id", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("device_id", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("session_key_id", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("session_key_id", prefix)) + } + return paths, nil +} + +// AddSetFlagsForMACCommand_RelayUpdateUplinkListReq adds flags to select fields in MACCommand_RelayUpdateUplinkListReq. +func AddSetFlagsForMACCommand_RelayUpdateUplinkListReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("rule-index", prefix), "", flagsplugin.WithHidden(hidden))) + AddSetFlagsForRelayUplinkForwardLimits(flags, flagsplugin.Prefix("forward-limits", prefix), hidden) + flags.AddFlag(customflags.New4BytesFlag(flagsplugin.Prefix("dev-addr", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("w-f-cnt", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(customflags.New16BytesFlag(flagsplugin.Prefix("root-wor-s-key", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("device-id", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBytesFlag(flagsplugin.Prefix("session-key-id", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the MACCommand_RelayUpdateUplinkListReq message from flags. +func (m *MACCommand_RelayUpdateUplinkListReq) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("rule_index", prefix)); err != nil { + return nil, err + } else if changed { + m.RuleIndex = val + paths = append(paths, flagsplugin.Prefix("rule_index", prefix)) + } + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("forward_limits", prefix)); changed { + if m.ForwardLimits == nil { + m.ForwardLimits = &RelayUplinkForwardLimits{} + } + if setPaths, err := m.ForwardLimits.SetFromFlags(flags, flagsplugin.Prefix("forward_limits", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := customflags.GetExactBytes(flags, flagsplugin.Prefix("dev_addr", prefix)); err != nil { + return nil, err + } else if changed { + m.DevAddr = val + paths = append(paths, flagsplugin.Prefix("dev_addr", prefix)) + } + if val, changed, err := flagsplugin.GetUint32(flags, flagsplugin.Prefix("w_f_cnt", prefix)); err != nil { + return nil, err + } else if changed { + m.WFCnt = val + paths = append(paths, flagsplugin.Prefix("w_f_cnt", prefix)) + } + if val, changed, err := customflags.GetExactBytes(flags, flagsplugin.Prefix("root_wor_s_key", prefix)); err != nil { + return nil, err + } else if changed { + m.RootWorSKey = val + paths = append(paths, flagsplugin.Prefix("root_wor_s_key", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("device_id", prefix)); err != nil { + return nil, err + } else if changed { + m.DeviceId = val + paths = append(paths, flagsplugin.Prefix("device_id", prefix)) + } + if val, changed, err := flagsplugin.GetBytes(flags, flagsplugin.Prefix("session_key_id", prefix)); err != nil { + return nil, err + } else if changed { + m.SessionKeyId = val + paths = append(paths, flagsplugin.Prefix("session_key_id", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForMACCommand_RelayNotifyNewEndDeviceReq adds flags to select fields in MACCommand_RelayNotifyNewEndDeviceReq. +func AddSelectFlagsForMACCommand_RelayNotifyNewEndDeviceReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("dev-addr", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("dev-addr", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("snr", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("snr", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("rssi", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("rssi", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forMACCommand_RelayNotifyNewEndDeviceReq message from select flags. +func PathsFromSelectFlagsForMACCommand_RelayNotifyNewEndDeviceReq(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("dev_addr", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("dev_addr", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("snr", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("snr", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("rssi", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("rssi", prefix)) + } + return paths, nil +} + +// AddSetFlagsForMACCommand_RelayNotifyNewEndDeviceReq adds flags to select fields in MACCommand_RelayNotifyNewEndDeviceReq. +func AddSetFlagsForMACCommand_RelayNotifyNewEndDeviceReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(customflags.New4BytesFlag(flagsplugin.Prefix("dev-addr", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewInt32Flag(flagsplugin.Prefix("snr", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewInt32Flag(flagsplugin.Prefix("rssi", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the MACCommand_RelayNotifyNewEndDeviceReq message from flags. +func (m *MACCommand_RelayNotifyNewEndDeviceReq) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := customflags.GetExactBytes(flags, flagsplugin.Prefix("dev_addr", prefix)); err != nil { + return nil, err + } else if changed { + m.DevAddr = val + paths = append(paths, flagsplugin.Prefix("dev_addr", prefix)) + } + if val, changed, err := flagsplugin.GetInt32(flags, flagsplugin.Prefix("snr", prefix)); err != nil { + return nil, err + } else if changed { + m.Snr = val + paths = append(paths, flagsplugin.Prefix("snr", prefix)) + } + if val, changed, err := flagsplugin.GetInt32(flags, flagsplugin.Prefix("rssi", prefix)); err != nil { + return nil, err + } else if changed { + m.Rssi = val + paths = append(paths, flagsplugin.Prefix("rssi", prefix)) + } + return paths, nil +} + // AddSelectFlagsForFrequencyValue adds flags to select fields in FrequencyValue. func AddSelectFlagsForFrequencyValue(flags *pflag.FlagSet, prefix string, hidden bool) { flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("value", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("value", prefix), false), flagsplugin.WithHidden(hidden))) @@ -1027,3 +1656,144 @@ func (m *DeviceEIRPValue) SetFromFlags(flags *pflag.FlagSet, prefix string) (pat } return paths, nil } + +// AddSelectFlagsForRelayForwardUplinkReq adds flags to select fields in RelayForwardUplinkReq. +func AddSelectFlagsForRelayForwardUplinkReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("data-rate", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("data-rate", prefix), true), flagsplugin.WithHidden(hidden))) + AddSelectFlagsForDataRate(flags, flagsplugin.Prefix("data-rate", prefix), hidden) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("snr", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("snr", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("rssi", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("rssi", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("wor-channel", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("wor-channel", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("frequency", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("frequency", prefix), false), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("raw-payload", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("raw-payload", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayForwardUplinkReq message from select flags. +func PathsFromSelectFlagsForRelayForwardUplinkReq(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("data_rate", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("data_rate", prefix)) + } + if selectPaths, err := PathsFromSelectFlagsForDataRate(flags, flagsplugin.Prefix("data_rate", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, selectPaths...) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("snr", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("snr", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("rssi", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("rssi", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("wor_channel", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("wor_channel", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("frequency", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("frequency", prefix)) + } + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("raw_payload", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("raw_payload", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayForwardUplinkReq adds flags to select fields in RelayForwardUplinkReq. +func AddSetFlagsForRelayForwardUplinkReq(flags *pflag.FlagSet, prefix string, hidden bool) { + AddSetFlagsForDataRate(flags, flagsplugin.Prefix("data-rate", prefix), hidden) + flags.AddFlag(flagsplugin.NewInt32Flag(flagsplugin.Prefix("snr", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewInt32Flag(flagsplugin.Prefix("rssi", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewStringFlag(flagsplugin.Prefix("wor-channel", prefix), flagsplugin.EnumValueDesc(RelayWORChannel_value), flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewUint64Flag(flagsplugin.Prefix("frequency", prefix), "", flagsplugin.WithHidden(hidden))) + flags.AddFlag(flagsplugin.NewBytesFlag(flagsplugin.Prefix("raw-payload", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayForwardUplinkReq message from flags. +func (m *RelayForwardUplinkReq) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("data_rate", prefix)); changed { + if m.DataRate == nil { + m.DataRate = &DataRate{} + } + if setPaths, err := m.DataRate.SetFromFlags(flags, flagsplugin.Prefix("data_rate", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } + if val, changed, err := flagsplugin.GetInt32(flags, flagsplugin.Prefix("snr", prefix)); err != nil { + return nil, err + } else if changed { + m.Snr = val + paths = append(paths, flagsplugin.Prefix("snr", prefix)) + } + if val, changed, err := flagsplugin.GetInt32(flags, flagsplugin.Prefix("rssi", prefix)); err != nil { + return nil, err + } else if changed { + m.Rssi = val + paths = append(paths, flagsplugin.Prefix("rssi", prefix)) + } + if val, changed, err := flagsplugin.GetString(flags, flagsplugin.Prefix("wor_channel", prefix)); err != nil { + return nil, err + } else if changed { + enumValue, err := flagsplugin.SetEnumString(val, RelayWORChannel_value) + if err != nil { + return nil, err + } + m.WorChannel = RelayWORChannel(enumValue) + paths = append(paths, flagsplugin.Prefix("wor_channel", prefix)) + } + if val, changed, err := flagsplugin.GetUint64(flags, flagsplugin.Prefix("frequency", prefix)); err != nil { + return nil, err + } else if changed { + m.Frequency = val + paths = append(paths, flagsplugin.Prefix("frequency", prefix)) + } + if val, changed, err := flagsplugin.GetBytes(flags, flagsplugin.Prefix("raw_payload", prefix)); err != nil { + return nil, err + } else if changed { + m.RawPayload = val + paths = append(paths, flagsplugin.Prefix("raw_payload", prefix)) + } + return paths, nil +} + +// AddSelectFlagsForRelayForwardDownlinkReq adds flags to select fields in RelayForwardDownlinkReq. +func AddSelectFlagsForRelayForwardDownlinkReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBoolFlag(flagsplugin.Prefix("raw-payload", prefix), flagsplugin.SelectDesc(flagsplugin.Prefix("raw-payload", prefix), false), flagsplugin.WithHidden(hidden))) +} + +// SelectFromFlags outputs the fieldmask paths forRelayForwardDownlinkReq message from select flags. +func PathsFromSelectFlagsForRelayForwardDownlinkReq(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, selected, err := flagsplugin.GetBool(flags, flagsplugin.Prefix("raw_payload", prefix)); err != nil { + return nil, err + } else if selected && val { + paths = append(paths, flagsplugin.Prefix("raw_payload", prefix)) + } + return paths, nil +} + +// AddSetFlagsForRelayForwardDownlinkReq adds flags to select fields in RelayForwardDownlinkReq. +func AddSetFlagsForRelayForwardDownlinkReq(flags *pflag.FlagSet, prefix string, hidden bool) { + flags.AddFlag(flagsplugin.NewBytesFlag(flagsplugin.Prefix("raw-payload", prefix), "", flagsplugin.WithHidden(hidden))) +} + +// SetFromFlags sets the RelayForwardDownlinkReq message from flags. +func (m *RelayForwardDownlinkReq) SetFromFlags(flags *pflag.FlagSet, prefix string) (paths []string, err error) { + if val, changed, err := flagsplugin.GetBytes(flags, flagsplugin.Prefix("raw_payload", prefix)); err != nil { + return nil, err + } else if changed { + m.RawPayload = val + paths = append(paths, flagsplugin.Prefix("raw_payload", prefix)) + } + return paths, nil +} diff --git a/pkg/ttnpb/lorawan_json.pb.go b/pkg/ttnpb/lorawan_json.pb.go index 62825a6d37..0423befb41 100644 --- a/pkg/ttnpb/lorawan_json.pb.go +++ b/pkg/ttnpb/lorawan_json.pb.go @@ -558,27 +558,34 @@ func (x MACCommandIdentifier) MarshalJSON() ([]byte, error) { // MACCommandIdentifier_customvalue contains custom string values that extend MACCommandIdentifier_value. var MACCommandIdentifier_customvalue = map[string]int32{ - "RFU_0": 0, - "RESET": 1, - "LINK_CHECK": 2, - "LINK_ADR": 3, - "DUTY_CYCLE": 4, - "RX_PARAM_SETUP": 5, - "DEV_STATUS": 6, - "NEW_CHANNEL": 7, - "RX_TIMING_SETUP": 8, - "TX_PARAM_SETUP": 9, - "DL_CHANNEL": 10, - "REKEY": 11, - "ADR_PARAM_SETUP": 12, - "DEVICE_TIME": 13, - "FORCE_REJOIN": 14, - "REJOIN_PARAM_SETUP": 15, - "PING_SLOT_INFO": 16, - "PING_SLOT_CHANNEL": 17, - "BEACON_TIMING": 18, - "BEACON_FREQ": 19, - "DEVICE_MODE": 32, + "RFU_0": 0, + "RESET": 1, + "LINK_CHECK": 2, + "LINK_ADR": 3, + "DUTY_CYCLE": 4, + "RX_PARAM_SETUP": 5, + "DEV_STATUS": 6, + "NEW_CHANNEL": 7, + "RX_TIMING_SETUP": 8, + "TX_PARAM_SETUP": 9, + "DL_CHANNEL": 10, + "REKEY": 11, + "ADR_PARAM_SETUP": 12, + "DEVICE_TIME": 13, + "FORCE_REJOIN": 14, + "REJOIN_PARAM_SETUP": 15, + "PING_SLOT_INFO": 16, + "PING_SLOT_CHANNEL": 17, + "BEACON_TIMING": 18, + "BEACON_FREQ": 19, + "DEVICE_MODE": 32, + "RELAY_CONF": 64, + "RELAY_END_DEVICE_CONF": 65, + "RELAY_FILTER_LIST": 66, + "RELAY_UPDATE_UPLINK_LIST": 67, + "RELAY_CTRL_UPLINK_LIST": 68, + "RELAY_CONFIGURE_FWD_LIMIT": 69, + "RELAY_NOTIFY_NEW_END_DEVICE": 70, } // UnmarshalProtoJSON unmarshals the MACCommandIdentifier from JSON. @@ -606,6 +613,342 @@ func (x *MACCommandIdentifier) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } +// MarshalProtoJSON marshals the RelayCADPeriodicity to JSON. +func (x RelayCADPeriodicity) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelayCADPeriodicity_name) +} + +// MarshalText marshals the RelayCADPeriodicity to text. +func (x RelayCADPeriodicity) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelayCADPeriodicity_name)), nil +} + +// MarshalJSON marshals the RelayCADPeriodicity to JSON. +func (x RelayCADPeriodicity) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelayCADPeriodicity_customvalue contains custom string values that extend RelayCADPeriodicity_value. +var RelayCADPeriodicity_customvalue = map[string]int32{ + "1_SECOND": 0, + "500_MILLISECONDS": 1, + "250_MILLISECONDS": 2, + "100_MILLISECONDS": 3, + "50_MILLISECONDS": 4, + "20_MILLISECONDS": 5, +} + +// UnmarshalProtoJSON unmarshals the RelayCADPeriodicity from JSON. +func (x *RelayCADPeriodicity) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelayCADPeriodicity_value, RelayCADPeriodicity_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelayCADPeriodicity enum: %v", err) + return + } + *x = RelayCADPeriodicity(v) +} + +// UnmarshalText unmarshals the RelayCADPeriodicity from text. +func (x *RelayCADPeriodicity) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelayCADPeriodicity_customvalue, RelayCADPeriodicity_value) + if err != nil { + return err + } + *x = RelayCADPeriodicity(i) + return nil +} + +// UnmarshalJSON unmarshals the RelayCADPeriodicity from JSON. +func (x *RelayCADPeriodicity) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelaySecondChAckOffset to JSON. +func (x RelaySecondChAckOffset) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelaySecondChAckOffset_name) +} + +// MarshalText marshals the RelaySecondChAckOffset to text. +func (x RelaySecondChAckOffset) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelaySecondChAckOffset_name)), nil +} + +// MarshalJSON marshals the RelaySecondChAckOffset to JSON. +func (x RelaySecondChAckOffset) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelaySecondChAckOffset_customvalue contains custom string values that extend RelaySecondChAckOffset_value. +var RelaySecondChAckOffset_customvalue = map[string]int32{ + "0": 0, + "200": 1, + "400": 2, + "800": 3, + "1600": 4, + "3200": 5, +} + +// UnmarshalProtoJSON unmarshals the RelaySecondChAckOffset from JSON. +func (x *RelaySecondChAckOffset) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelaySecondChAckOffset_value, RelaySecondChAckOffset_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelaySecondChAckOffset enum: %v", err) + return + } + *x = RelaySecondChAckOffset(v) +} + +// UnmarshalText unmarshals the RelaySecondChAckOffset from text. +func (x *RelaySecondChAckOffset) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelaySecondChAckOffset_customvalue, RelaySecondChAckOffset_value) + if err != nil { + return err + } + *x = RelaySecondChAckOffset(i) + return nil +} + +// UnmarshalJSON unmarshals the RelaySecondChAckOffset from JSON. +func (x *RelaySecondChAckOffset) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayLimitBucketSize to JSON. +func (x RelayLimitBucketSize) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelayLimitBucketSize_name) +} + +// MarshalText marshals the RelayLimitBucketSize to text. +func (x RelayLimitBucketSize) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelayLimitBucketSize_name)), nil +} + +// MarshalJSON marshals the RelayLimitBucketSize to JSON. +func (x RelayLimitBucketSize) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelayLimitBucketSize_customvalue contains custom string values that extend RelayLimitBucketSize_value. +var RelayLimitBucketSize_customvalue = map[string]int32{ + "1": 0, + "2": 1, + "4": 2, + "12": 3, +} + +// UnmarshalProtoJSON unmarshals the RelayLimitBucketSize from JSON. +func (x *RelayLimitBucketSize) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelayLimitBucketSize_value, RelayLimitBucketSize_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelayLimitBucketSize enum: %v", err) + return + } + *x = RelayLimitBucketSize(v) +} + +// UnmarshalText unmarshals the RelayLimitBucketSize from text. +func (x *RelayLimitBucketSize) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelayLimitBucketSize_customvalue, RelayLimitBucketSize_value) + if err != nil { + return err + } + *x = RelayLimitBucketSize(i) + return nil +} + +// UnmarshalJSON unmarshals the RelayLimitBucketSize from JSON. +func (x *RelayLimitBucketSize) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelaySmartEnableLevel to JSON. +func (x RelaySmartEnableLevel) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelaySmartEnableLevel_name) +} + +// MarshalText marshals the RelaySmartEnableLevel to text. +func (x RelaySmartEnableLevel) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelaySmartEnableLevel_name)), nil +} + +// MarshalJSON marshals the RelaySmartEnableLevel to JSON. +func (x RelaySmartEnableLevel) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelaySmartEnableLevel_customvalue contains custom string values that extend RelaySmartEnableLevel_value. +var RelaySmartEnableLevel_customvalue = map[string]int32{ + "8": 0, + "16": 1, + "32": 2, + "64": 3, +} + +// UnmarshalProtoJSON unmarshals the RelaySmartEnableLevel from JSON. +func (x *RelaySmartEnableLevel) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelaySmartEnableLevel_value, RelaySmartEnableLevel_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelaySmartEnableLevel enum: %v", err) + return + } + *x = RelaySmartEnableLevel(v) +} + +// UnmarshalText unmarshals the RelaySmartEnableLevel from text. +func (x *RelaySmartEnableLevel) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelaySmartEnableLevel_customvalue, RelaySmartEnableLevel_value) + if err != nil { + return err + } + *x = RelaySmartEnableLevel(i) + return nil +} + +// UnmarshalJSON unmarshals the RelaySmartEnableLevel from JSON. +func (x *RelaySmartEnableLevel) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayWORChannel to JSON. +func (x RelayWORChannel) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelayWORChannel_name) +} + +// MarshalText marshals the RelayWORChannel to text. +func (x RelayWORChannel) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelayWORChannel_name)), nil +} + +// MarshalJSON marshals the RelayWORChannel to JSON. +func (x RelayWORChannel) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelayWORChannel_customvalue contains custom string values that extend RelayWORChannel_value. +var RelayWORChannel_customvalue = map[string]int32{ + "DEFAULT": 0, + "SECONDARY": 1, +} + +// UnmarshalProtoJSON unmarshals the RelayWORChannel from JSON. +func (x *RelayWORChannel) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelayWORChannel_value, RelayWORChannel_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelayWORChannel enum: %v", err) + return + } + *x = RelayWORChannel(v) +} + +// UnmarshalText unmarshals the RelayWORChannel from text. +func (x *RelayWORChannel) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelayWORChannel_customvalue, RelayWORChannel_value) + if err != nil { + return err + } + *x = RelayWORChannel(i) + return nil +} + +// UnmarshalJSON unmarshals the RelayWORChannel from JSON. +func (x *RelayWORChannel) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayResetLimitCounter to JSON. +func (x RelayResetLimitCounter) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelayResetLimitCounter_name) +} + +// MarshalText marshals the RelayResetLimitCounter to text. +func (x RelayResetLimitCounter) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelayResetLimitCounter_name)), nil +} + +// MarshalJSON marshals the RelayResetLimitCounter to JSON. +func (x RelayResetLimitCounter) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelayResetLimitCounter_customvalue contains custom string values that extend RelayResetLimitCounter_value. +var RelayResetLimitCounter_customvalue = map[string]int32{ + "ZERO": 0, + "RELOAD_RATE": 1, + "MAX_VALUE": 2, + "NO_RESET": 3, +} + +// UnmarshalProtoJSON unmarshals the RelayResetLimitCounter from JSON. +func (x *RelayResetLimitCounter) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelayResetLimitCounter_value, RelayResetLimitCounter_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelayResetLimitCounter enum: %v", err) + return + } + *x = RelayResetLimitCounter(v) +} + +// UnmarshalText unmarshals the RelayResetLimitCounter from text. +func (x *RelayResetLimitCounter) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelayResetLimitCounter_customvalue, RelayResetLimitCounter_value) + if err != nil { + return err + } + *x = RelayResetLimitCounter(i) + return nil +} + +// UnmarshalJSON unmarshals the RelayResetLimitCounter from JSON. +func (x *RelayResetLimitCounter) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayCtrlUplinkListAction to JSON. +func (x RelayCtrlUplinkListAction) MarshalProtoJSON(s *jsonplugin.MarshalState) { + s.WriteEnumString(int32(x), RelayCtrlUplinkListAction_name) +} + +// MarshalText marshals the RelayCtrlUplinkListAction to text. +func (x RelayCtrlUplinkListAction) MarshalText() ([]byte, error) { + return []byte(jsonplugin.GetEnumString(int32(x), RelayCtrlUplinkListAction_name)), nil +} + +// MarshalJSON marshals the RelayCtrlUplinkListAction to JSON. +func (x RelayCtrlUplinkListAction) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// RelayCtrlUplinkListAction_customvalue contains custom string values that extend RelayCtrlUplinkListAction_value. +var RelayCtrlUplinkListAction_customvalue = map[string]int32{ + "READ_W_F_CNT": 0, + "REMOVE_TRUSTED_END_DEVICE": 1, +} + +// UnmarshalProtoJSON unmarshals the RelayCtrlUplinkListAction from JSON. +func (x *RelayCtrlUplinkListAction) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + v := s.ReadEnum(RelayCtrlUplinkListAction_value, RelayCtrlUplinkListAction_customvalue) + if err := s.Err(); err != nil { + s.SetErrorf("could not read RelayCtrlUplinkListAction enum: %v", err) + return + } + *x = RelayCtrlUplinkListAction(v) +} + +// UnmarshalText unmarshals the RelayCtrlUplinkListAction from text. +func (x *RelayCtrlUplinkListAction) UnmarshalText(b []byte) error { + i, err := jsonplugin.ParseEnumString(string(b), RelayCtrlUplinkListAction_customvalue, RelayCtrlUplinkListAction_value) + if err != nil { + return err + } + *x = RelayCtrlUplinkListAction(i) + return nil +} + +// UnmarshalJSON unmarshals the RelayCtrlUplinkListAction from JSON. +func (x *RelayCtrlUplinkListAction) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + // MarshalProtoJSON marshals the AggregatedDutyCycle to JSON. func (x AggregatedDutyCycle) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteEnumString(int32(x), AggregatedDutyCycle_name) @@ -2329,29 +2672,39 @@ func (x *TxRequest) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_ResetInd message to JSON. -func (x *MACCommand_ResetInd) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the RelaySecondChannel message to JSON. +func (x *RelaySecondChannel) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.MinorVersion != 0 || s.HasField("minor_version") { + if x.AckOffset != 0 || s.HasField("ack_offset") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("minor_version") - x.MinorVersion.MarshalProtoJSON(s) + s.WriteObjectField("ack_offset") + x.AckOffset.MarshalProtoJSON(s) + } + if x.DataRateIndex != 0 || s.HasField("data_rate_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("data_rate_index") + x.DataRateIndex.MarshalProtoJSON(s) + } + if x.Frequency != 0 || s.HasField("frequency") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("frequency") + s.WriteUint64(x.Frequency) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_ResetInd to JSON. -func (x *MACCommand_ResetInd) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the RelaySecondChannel to JSON. +func (x *RelaySecondChannel) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_ResetInd message from JSON. -func (x *MACCommand_ResetInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the RelaySecondChannel message from JSON. +func (x *RelaySecondChannel) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -2359,41 +2712,52 @@ func (x *MACCommand_ResetInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { switch key { default: s.ReadAny() // ignore unknown field - case "minor_version", "minorVersion": - s.AddField("minor_version") - x.MinorVersion.UnmarshalProtoJSON(s) + case "ack_offset", "ackOffset": + s.AddField("ack_offset") + x.AckOffset.UnmarshalProtoJSON(s) + case "data_rate_index", "dataRateIndex": + s.AddField("data_rate_index") + x.DataRateIndex.UnmarshalProtoJSON(s) + case "frequency": + s.AddField("frequency") + x.Frequency = s.ReadUint64() } }) } -// UnmarshalJSON unmarshals the MACCommand_ResetInd from JSON. -func (x *MACCommand_ResetInd) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the RelaySecondChannel from JSON. +func (x *RelaySecondChannel) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_ResetConf message to JSON. -func (x *MACCommand_ResetConf) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the RelayUplinkForwardLimits message to JSON. +func (x *RelayUplinkForwardLimits) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.MinorVersion != 0 || s.HasField("minor_version") { + if x.BucketSize != 0 || s.HasField("bucket_size") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("minor_version") - x.MinorVersion.MarshalProtoJSON(s) + s.WriteObjectField("bucket_size") + x.BucketSize.MarshalProtoJSON(s) + } + if x.ReloadRate != 0 || s.HasField("reload_rate") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("reload_rate") + s.WriteUint32(x.ReloadRate) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_ResetConf to JSON. -func (x *MACCommand_ResetConf) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the RelayUplinkForwardLimits to JSON. +func (x *RelayUplinkForwardLimits) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_ResetConf message from JSON. -func (x *MACCommand_ResetConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the RelayUplinkForwardLimits message from JSON. +func (x *RelayUplinkForwardLimits) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -2401,61 +2765,49 @@ func (x *MACCommand_ResetConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) switch key { default: s.ReadAny() // ignore unknown field - case "minor_version", "minorVersion": - s.AddField("minor_version") - x.MinorVersion.UnmarshalProtoJSON(s) + case "bucket_size", "bucketSize": + s.AddField("bucket_size") + x.BucketSize.UnmarshalProtoJSON(s) + case "reload_rate", "reloadRate": + s.AddField("reload_rate") + x.ReloadRate = s.ReadUint32() } }) } -// UnmarshalJSON unmarshals the MACCommand_ResetConf from JSON. -func (x *MACCommand_ResetConf) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the RelayUplinkForwardLimits from JSON. +func (x *RelayUplinkForwardLimits) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_LinkADRReq message to JSON. -func (x *MACCommand_LinkADRReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the RelayForwardLimits message to JSON. +func (x *RelayForwardLimits) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.DataRateIndex != 0 || s.HasField("data_rate_index") { - s.WriteMoreIf(&wroteField) - s.WriteObjectField("data_rate_index") - x.DataRateIndex.MarshalProtoJSON(s) - } - if x.TxPowerIndex != 0 || s.HasField("tx_power_index") { - s.WriteMoreIf(&wroteField) - s.WriteObjectField("tx_power_index") - s.WriteUint32(x.TxPowerIndex) - } - if len(x.ChannelMask) > 0 || s.HasField("channel_mask") { - s.WriteMoreIf(&wroteField) - s.WriteObjectField("channel_mask") - s.WriteBoolArray(x.ChannelMask) - } - if x.ChannelMaskControl != 0 || s.HasField("channel_mask_control") { + if x.BucketSize != 0 || s.HasField("bucket_size") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("channel_mask_control") - s.WriteUint32(x.ChannelMaskControl) + s.WriteObjectField("bucket_size") + x.BucketSize.MarshalProtoJSON(s) } - if x.NbTrans != 0 || s.HasField("nb_trans") { + if x.ReloadRate != 0 || s.HasField("reload_rate") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("nb_trans") - s.WriteUint32(x.NbTrans) + s.WriteObjectField("reload_rate") + s.WriteUint32(x.ReloadRate) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_LinkADRReq to JSON. -func (x *MACCommand_LinkADRReq) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the RelayForwardLimits to JSON. +func (x *RelayForwardLimits) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_LinkADRReq message from JSON. -func (x *MACCommand_LinkADRReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the RelayForwardLimits message from JSON. +func (x *RelayForwardLimits) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -2463,31 +2815,222 @@ func (x *MACCommand_LinkADRReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) switch key { default: s.ReadAny() // ignore unknown field - case "data_rate_index", "dataRateIndex": - s.AddField("data_rate_index") - x.DataRateIndex.UnmarshalProtoJSON(s) - case "tx_power_index", "txPowerIndex": - s.AddField("tx_power_index") - x.TxPowerIndex = s.ReadUint32() - case "channel_mask", "channelMask": - s.AddField("channel_mask") - if s.ReadNil() { - x.ChannelMask = nil - return - } - x.ChannelMask = s.ReadBoolArray() - case "channel_mask_control", "channelMaskControl": - s.AddField("channel_mask_control") - x.ChannelMaskControl = s.ReadUint32() - case "nb_trans", "nbTrans": - s.AddField("nb_trans") - x.NbTrans = s.ReadUint32() + case "bucket_size", "bucketSize": + s.AddField("bucket_size") + x.BucketSize.UnmarshalProtoJSON(s) + case "reload_rate", "reloadRate": + s.AddField("reload_rate") + x.ReloadRate = s.ReadUint32() } }) } -// UnmarshalJSON unmarshals the MACCommand_LinkADRReq from JSON. -func (x *MACCommand_LinkADRReq) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the RelayForwardLimits from JSON. +func (x *RelayForwardLimits) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayEndDeviceDynamicMode message to JSON. +func (x *RelayEndDeviceDynamicMode) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.SmartEnableLevel != 0 || s.HasField("smart_enable_level") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("smart_enable_level") + x.SmartEnableLevel.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayEndDeviceDynamicMode to JSON. +func (x *RelayEndDeviceDynamicMode) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayEndDeviceDynamicMode message from JSON. +func (x *RelayEndDeviceDynamicMode) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "smart_enable_level", "smartEnableLevel": + s.AddField("smart_enable_level") + x.SmartEnableLevel.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the RelayEndDeviceDynamicMode from JSON. +func (x *RelayEndDeviceDynamicMode) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_ResetInd message to JSON. +func (x *MACCommand_ResetInd) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.MinorVersion != 0 || s.HasField("minor_version") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("minor_version") + x.MinorVersion.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_ResetInd to JSON. +func (x *MACCommand_ResetInd) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_ResetInd message from JSON. +func (x *MACCommand_ResetInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "minor_version", "minorVersion": + s.AddField("minor_version") + x.MinorVersion.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_ResetInd from JSON. +func (x *MACCommand_ResetInd) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_ResetConf message to JSON. +func (x *MACCommand_ResetConf) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.MinorVersion != 0 || s.HasField("minor_version") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("minor_version") + x.MinorVersion.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_ResetConf to JSON. +func (x *MACCommand_ResetConf) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_ResetConf message from JSON. +func (x *MACCommand_ResetConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "minor_version", "minorVersion": + s.AddField("minor_version") + x.MinorVersion.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_ResetConf from JSON. +func (x *MACCommand_ResetConf) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_LinkADRReq message to JSON. +func (x *MACCommand_LinkADRReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.DataRateIndex != 0 || s.HasField("data_rate_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("data_rate_index") + x.DataRateIndex.MarshalProtoJSON(s) + } + if x.TxPowerIndex != 0 || s.HasField("tx_power_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("tx_power_index") + s.WriteUint32(x.TxPowerIndex) + } + if len(x.ChannelMask) > 0 || s.HasField("channel_mask") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("channel_mask") + s.WriteBoolArray(x.ChannelMask) + } + if x.ChannelMaskControl != 0 || s.HasField("channel_mask_control") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("channel_mask_control") + s.WriteUint32(x.ChannelMaskControl) + } + if x.NbTrans != 0 || s.HasField("nb_trans") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("nb_trans") + s.WriteUint32(x.NbTrans) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_LinkADRReq to JSON. +func (x *MACCommand_LinkADRReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_LinkADRReq message from JSON. +func (x *MACCommand_LinkADRReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "data_rate_index", "dataRateIndex": + s.AddField("data_rate_index") + x.DataRateIndex.UnmarshalProtoJSON(s) + case "tx_power_index", "txPowerIndex": + s.AddField("tx_power_index") + x.TxPowerIndex = s.ReadUint32() + case "channel_mask", "channelMask": + s.AddField("channel_mask") + if s.ReadNil() { + x.ChannelMask = nil + return + } + x.ChannelMask = s.ReadBoolArray() + case "channel_mask_control", "channelMaskControl": + s.AddField("channel_mask_control") + x.ChannelMaskControl = s.ReadUint32() + case "nb_trans", "nbTrans": + s.AddField("nb_trans") + x.NbTrans = s.ReadUint32() + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_LinkADRReq from JSON. +func (x *MACCommand_LinkADRReq) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } @@ -3017,19 +3560,492 @@ func (x *MACCommand_PingSlotInfoReq) MarshalProtoJSON(s *jsonplugin.MarshalState var wroteField bool if x.Period != 0 || s.HasField("period") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("period") - x.Period.MarshalProtoJSON(s) + s.WriteObjectField("period") + x.Period.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_PingSlotInfoReq to JSON. +func (x *MACCommand_PingSlotInfoReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_PingSlotInfoReq message from JSON. +func (x *MACCommand_PingSlotInfoReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "period": + s.AddField("period") + x.Period.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_PingSlotInfoReq from JSON. +func (x *MACCommand_PingSlotInfoReq) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_PingSlotChannelReq message to JSON. +func (x *MACCommand_PingSlotChannelReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Frequency != 0 || s.HasField("frequency") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("frequency") + s.WriteUint64(x.Frequency) + } + if x.DataRateIndex != 0 || s.HasField("data_rate_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("data_rate_index") + x.DataRateIndex.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_PingSlotChannelReq to JSON. +func (x *MACCommand_PingSlotChannelReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_PingSlotChannelReq message from JSON. +func (x *MACCommand_PingSlotChannelReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "frequency": + s.AddField("frequency") + x.Frequency = s.ReadUint64() + case "data_rate_index", "dataRateIndex": + s.AddField("data_rate_index") + x.DataRateIndex.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_PingSlotChannelReq from JSON. +func (x *MACCommand_PingSlotChannelReq) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_DeviceModeInd message to JSON. +func (x *MACCommand_DeviceModeInd) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Class != 0 || s.HasField("class") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("class") + x.Class.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_DeviceModeInd to JSON. +func (x *MACCommand_DeviceModeInd) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_DeviceModeInd message from JSON. +func (x *MACCommand_DeviceModeInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "class": + s.AddField("class") + x.Class.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_DeviceModeInd from JSON. +func (x *MACCommand_DeviceModeInd) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_DeviceModeConf message to JSON. +func (x *MACCommand_DeviceModeConf) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Class != 0 || s.HasField("class") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("class") + x.Class.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_DeviceModeConf to JSON. +func (x *MACCommand_DeviceModeConf) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_DeviceModeConf message from JSON. +func (x *MACCommand_DeviceModeConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "class": + s.AddField("class") + x.Class.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_DeviceModeConf from JSON. +func (x *MACCommand_DeviceModeConf) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_RelayConfReq_Configuration message to JSON. +func (x *MACCommand_RelayConfReq_Configuration) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.SecondChannel != nil || s.HasField("second_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("second_channel") + x.SecondChannel.MarshalProtoJSON(s.WithField("second_channel")) + } + if x.DefaultChannelIndex != 0 || s.HasField("default_channel_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("default_channel_index") + s.WriteUint32(x.DefaultChannelIndex) + } + if x.CadPeriodicity != 0 || s.HasField("cad_periodicity") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("cad_periodicity") + x.CadPeriodicity.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_RelayConfReq_Configuration to JSON. +func (x *MACCommand_RelayConfReq_Configuration) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_RelayConfReq_Configuration message from JSON. +func (x *MACCommand_RelayConfReq_Configuration) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "second_channel", "secondChannel": + if s.ReadNil() { + x.SecondChannel = nil + return + } + x.SecondChannel = &RelaySecondChannel{} + x.SecondChannel.UnmarshalProtoJSON(s.WithField("second_channel", true)) + case "default_channel_index", "defaultChannelIndex": + s.AddField("default_channel_index") + x.DefaultChannelIndex = s.ReadUint32() + case "cad_periodicity", "cadPeriodicity": + s.AddField("cad_periodicity") + x.CadPeriodicity.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_RelayConfReq_Configuration from JSON. +func (x *MACCommand_RelayConfReq_Configuration) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_RelayConfReq message to JSON. +func (x *MACCommand_RelayConfReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Configuration != nil || s.HasField("configuration") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("configuration") + x.Configuration.MarshalProtoJSON(s.WithField("configuration")) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_RelayConfReq to JSON. +func (x *MACCommand_RelayConfReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_RelayConfReq message from JSON. +func (x *MACCommand_RelayConfReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "configuration": + if s.ReadNil() { + x.Configuration = nil + return + } + x.Configuration = &MACCommand_RelayConfReq_Configuration{} + x.Configuration.UnmarshalProtoJSON(s.WithField("configuration", true)) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_RelayConfReq from JSON. +func (x *MACCommand_RelayConfReq) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_RelayEndDeviceConfReq_Configuration message to JSON. +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Mode != nil { + switch ov := x.Mode.(type) { + case *MACCommand_RelayEndDeviceConfReq_Configuration_Always: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("always") + // NOTE: RelayEndDeviceAlwaysMode does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.Always) + case *MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("dynamic") + ov.Dynamic.MarshalProtoJSON(s.WithField("dynamic")) + case *MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("end_device_controlled") + // NOTE: RelayEndDeviceControlledMode does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.EndDeviceControlled) + } + } + if x.Backoff != 0 || s.HasField("backoff") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("backoff") + s.WriteUint32(x.Backoff) + } + if x.SecondChannel != nil || s.HasField("second_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("second_channel") + x.SecondChannel.MarshalProtoJSON(s.WithField("second_channel")) + } + if x.ServingDeviceId != "" || s.HasField("serving_device_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("serving_device_id") + s.WriteString(x.ServingDeviceId) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_RelayEndDeviceConfReq_Configuration to JSON. +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_RelayEndDeviceConfReq_Configuration message from JSON. +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "always": + s.AddField("always") + ov := &MACCommand_RelayEndDeviceConfReq_Configuration_Always{} + x.Mode = ov + if s.ReadNil() { + ov.Always = nil + return + } + // NOTE: RelayEndDeviceAlwaysMode does not seem to implement UnmarshalProtoJSON. + var v RelayEndDeviceAlwaysMode + golang.UnmarshalMessage(s, &v) + ov.Always = &v + case "dynamic": + ov := &MACCommand_RelayEndDeviceConfReq_Configuration_Dynamic{} + x.Mode = ov + if s.ReadNil() { + ov.Dynamic = nil + return + } + ov.Dynamic = &RelayEndDeviceDynamicMode{} + ov.Dynamic.UnmarshalProtoJSON(s.WithField("dynamic", true)) + case "end_device_controlled", "endDeviceControlled": + s.AddField("end_device_controlled") + ov := &MACCommand_RelayEndDeviceConfReq_Configuration_EndDeviceControlled{} + x.Mode = ov + if s.ReadNil() { + ov.EndDeviceControlled = nil + return + } + // NOTE: RelayEndDeviceControlledMode does not seem to implement UnmarshalProtoJSON. + var v RelayEndDeviceControlledMode + golang.UnmarshalMessage(s, &v) + ov.EndDeviceControlled = &v + case "backoff": + s.AddField("backoff") + x.Backoff = s.ReadUint32() + case "second_channel", "secondChannel": + if s.ReadNil() { + x.SecondChannel = nil + return + } + x.SecondChannel = &RelaySecondChannel{} + x.SecondChannel.UnmarshalProtoJSON(s.WithField("second_channel", true)) + case "serving_device_id", "servingDeviceId": + s.AddField("serving_device_id") + x.ServingDeviceId = s.ReadString() + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_RelayEndDeviceConfReq_Configuration from JSON. +func (x *MACCommand_RelayEndDeviceConfReq_Configuration) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_RelayEndDeviceConfReq message to JSON. +func (x *MACCommand_RelayEndDeviceConfReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Configuration != nil || s.HasField("configuration") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("configuration") + x.Configuration.MarshalProtoJSON(s.WithField("configuration")) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the MACCommand_RelayEndDeviceConfReq to JSON. +func (x *MACCommand_RelayEndDeviceConfReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the MACCommand_RelayEndDeviceConfReq message from JSON. +func (x *MACCommand_RelayEndDeviceConfReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "configuration": + if s.ReadNil() { + x.Configuration = nil + return + } + x.Configuration = &MACCommand_RelayEndDeviceConfReq_Configuration{} + x.Configuration.UnmarshalProtoJSON(s.WithField("configuration", true)) + } + }) +} + +// UnmarshalJSON unmarshals the MACCommand_RelayEndDeviceConfReq from JSON. +func (x *MACCommand_RelayEndDeviceConfReq) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the MACCommand_RelayUpdateUplinkListReq message to JSON. +func (x *MACCommand_RelayUpdateUplinkListReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.RuleIndex != 0 || s.HasField("rule_index") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("rule_index") + s.WriteUint32(x.RuleIndex) + } + if x.ForwardLimits != nil || s.HasField("forward_limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("forward_limits") + x.ForwardLimits.MarshalProtoJSON(s.WithField("forward_limits")) + } + if len(x.DevAddr) > 0 || s.HasField("dev_addr") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("dev_addr") + types.MarshalHEXBytes(s.WithField("dev_addr"), x.DevAddr) + } + if x.WFCnt != 0 || s.HasField("w_f_cnt") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("w_f_cnt") + s.WriteUint32(x.WFCnt) + } + if len(x.RootWorSKey) > 0 || s.HasField("root_wor_s_key") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("root_wor_s_key") + types.MarshalHEXBytes(s.WithField("root_wor_s_key"), x.RootWorSKey) + } + if x.DeviceId != "" || s.HasField("device_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("device_id") + s.WriteString(x.DeviceId) + } + if len(x.SessionKeyId) > 0 || s.HasField("session_key_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("session_key_id") + s.WriteBytes(x.SessionKeyId) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_PingSlotInfoReq to JSON. -func (x *MACCommand_PingSlotInfoReq) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the MACCommand_RelayUpdateUplinkListReq to JSON. +func (x *MACCommand_RelayUpdateUplinkListReq) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_PingSlotInfoReq message from JSON. -func (x *MACCommand_PingSlotInfoReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the MACCommand_RelayUpdateUplinkListReq message from JSON. +func (x *MACCommand_RelayUpdateUplinkListReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -3037,46 +4053,68 @@ func (x *MACCommand_PingSlotInfoReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalS switch key { default: s.ReadAny() // ignore unknown field - case "period": - s.AddField("period") - x.Period.UnmarshalProtoJSON(s) + case "rule_index", "ruleIndex": + s.AddField("rule_index") + x.RuleIndex = s.ReadUint32() + case "forward_limits", "forwardLimits": + if s.ReadNil() { + x.ForwardLimits = nil + return + } + x.ForwardLimits = &RelayUplinkForwardLimits{} + x.ForwardLimits.UnmarshalProtoJSON(s.WithField("forward_limits", true)) + case "dev_addr", "devAddr": + s.AddField("dev_addr") + x.DevAddr = types.Unmarshal4Bytes(s.WithField("dev_addr", false)) + case "w_f_cnt", "wFCnt": + s.AddField("w_f_cnt") + x.WFCnt = s.ReadUint32() + case "root_wor_s_key", "rootWorSKey": + s.AddField("root_wor_s_key") + x.RootWorSKey = types.Unmarshal16Bytes(s.WithField("root_wor_s_key", false)) + case "device_id", "deviceId": + s.AddField("device_id") + x.DeviceId = s.ReadString() + case "session_key_id", "sessionKeyId": + s.AddField("session_key_id") + x.SessionKeyId = s.ReadBytes() } }) } -// UnmarshalJSON unmarshals the MACCommand_PingSlotInfoReq from JSON. -func (x *MACCommand_PingSlotInfoReq) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the MACCommand_RelayUpdateUplinkListReq from JSON. +func (x *MACCommand_RelayUpdateUplinkListReq) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_PingSlotChannelReq message to JSON. -func (x *MACCommand_PingSlotChannelReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the MACCommand_RelayCtrlUplinkListReq message to JSON. +func (x *MACCommand_RelayCtrlUplinkListReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.Frequency != 0 || s.HasField("frequency") { + if x.RuleIndex != 0 || s.HasField("rule_index") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("frequency") - s.WriteUint64(x.Frequency) + s.WriteObjectField("rule_index") + s.WriteUint32(x.RuleIndex) } - if x.DataRateIndex != 0 || s.HasField("data_rate_index") { + if x.Action != 0 || s.HasField("action") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("data_rate_index") - x.DataRateIndex.MarshalProtoJSON(s) + s.WriteObjectField("action") + x.Action.MarshalProtoJSON(s) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_PingSlotChannelReq to JSON. -func (x *MACCommand_PingSlotChannelReq) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the MACCommand_RelayCtrlUplinkListReq to JSON. +func (x *MACCommand_RelayCtrlUplinkListReq) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_PingSlotChannelReq message from JSON. -func (x *MACCommand_PingSlotChannelReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the MACCommand_RelayCtrlUplinkListReq message from JSON. +func (x *MACCommand_RelayCtrlUplinkListReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -3084,44 +4122,64 @@ func (x *MACCommand_PingSlotChannelReq) UnmarshalProtoJSON(s *jsonplugin.Unmarsh switch key { default: s.ReadAny() // ignore unknown field - case "frequency": - s.AddField("frequency") - x.Frequency = s.ReadUint64() - case "data_rate_index", "dataRateIndex": - s.AddField("data_rate_index") - x.DataRateIndex.UnmarshalProtoJSON(s) + case "rule_index", "ruleIndex": + s.AddField("rule_index") + x.RuleIndex = s.ReadUint32() + case "action": + s.AddField("action") + x.Action.UnmarshalProtoJSON(s) } }) } -// UnmarshalJSON unmarshals the MACCommand_PingSlotChannelReq from JSON. -func (x *MACCommand_PingSlotChannelReq) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the MACCommand_RelayCtrlUplinkListReq from JSON. +func (x *MACCommand_RelayCtrlUplinkListReq) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_DeviceModeInd message to JSON. -func (x *MACCommand_DeviceModeInd) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the MACCommand_RelayConfigureFwdLimitReq message to JSON. +func (x *MACCommand_RelayConfigureFwdLimitReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.Class != 0 || s.HasField("class") { + if x.ResetLimitCounter != 0 || s.HasField("reset_limit_counter") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("class") - x.Class.MarshalProtoJSON(s) + s.WriteObjectField("reset_limit_counter") + x.ResetLimitCounter.MarshalProtoJSON(s) + } + if x.JoinRequestLimits != nil || s.HasField("join_request_limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("join_request_limits") + x.JoinRequestLimits.MarshalProtoJSON(s.WithField("join_request_limits")) + } + if x.NotifyLimits != nil || s.HasField("notify_limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("notify_limits") + x.NotifyLimits.MarshalProtoJSON(s.WithField("notify_limits")) + } + if x.GlobalUplinkLimits != nil || s.HasField("global_uplink_limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("global_uplink_limits") + x.GlobalUplinkLimits.MarshalProtoJSON(s.WithField("global_uplink_limits")) + } + if x.OverallLimits != nil || s.HasField("overall_limits") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("overall_limits") + x.OverallLimits.MarshalProtoJSON(s.WithField("overall_limits")) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_DeviceModeInd to JSON. -func (x *MACCommand_DeviceModeInd) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the MACCommand_RelayConfigureFwdLimitReq to JSON. +func (x *MACCommand_RelayConfigureFwdLimitReq) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_DeviceModeInd message from JSON. -func (x *MACCommand_DeviceModeInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the MACCommand_RelayConfigureFwdLimitReq message from JSON. +func (x *MACCommand_RelayConfigureFwdLimitReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -3129,41 +4187,79 @@ func (x *MACCommand_DeviceModeInd) UnmarshalProtoJSON(s *jsonplugin.UnmarshalSta switch key { default: s.ReadAny() // ignore unknown field - case "class": - s.AddField("class") - x.Class.UnmarshalProtoJSON(s) + case "reset_limit_counter", "resetLimitCounter": + s.AddField("reset_limit_counter") + x.ResetLimitCounter.UnmarshalProtoJSON(s) + case "join_request_limits", "joinRequestLimits": + if s.ReadNil() { + x.JoinRequestLimits = nil + return + } + x.JoinRequestLimits = &RelayForwardLimits{} + x.JoinRequestLimits.UnmarshalProtoJSON(s.WithField("join_request_limits", true)) + case "notify_limits", "notifyLimits": + if s.ReadNil() { + x.NotifyLimits = nil + return + } + x.NotifyLimits = &RelayForwardLimits{} + x.NotifyLimits.UnmarshalProtoJSON(s.WithField("notify_limits", true)) + case "global_uplink_limits", "globalUplinkLimits": + if s.ReadNil() { + x.GlobalUplinkLimits = nil + return + } + x.GlobalUplinkLimits = &RelayForwardLimits{} + x.GlobalUplinkLimits.UnmarshalProtoJSON(s.WithField("global_uplink_limits", true)) + case "overall_limits", "overallLimits": + if s.ReadNil() { + x.OverallLimits = nil + return + } + x.OverallLimits = &RelayForwardLimits{} + x.OverallLimits.UnmarshalProtoJSON(s.WithField("overall_limits", true)) } }) } -// UnmarshalJSON unmarshals the MACCommand_DeviceModeInd from JSON. -func (x *MACCommand_DeviceModeInd) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the MACCommand_RelayConfigureFwdLimitReq from JSON. +func (x *MACCommand_RelayConfigureFwdLimitReq) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } -// MarshalProtoJSON marshals the MACCommand_DeviceModeConf message to JSON. -func (x *MACCommand_DeviceModeConf) MarshalProtoJSON(s *jsonplugin.MarshalState) { +// MarshalProtoJSON marshals the MACCommand_RelayNotifyNewEndDeviceReq message to JSON. +func (x *MACCommand_RelayNotifyNewEndDeviceReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { if x == nil { s.WriteNil() return } s.WriteObjectStart() var wroteField bool - if x.Class != 0 || s.HasField("class") { + if len(x.DevAddr) > 0 || s.HasField("dev_addr") { s.WriteMoreIf(&wroteField) - s.WriteObjectField("class") - x.Class.MarshalProtoJSON(s) + s.WriteObjectField("dev_addr") + types.MarshalHEXBytes(s.WithField("dev_addr"), x.DevAddr) + } + if x.Snr != 0 || s.HasField("snr") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("snr") + s.WriteInt32(x.Snr) + } + if x.Rssi != 0 || s.HasField("rssi") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("rssi") + s.WriteInt32(x.Rssi) } s.WriteObjectEnd() } -// MarshalJSON marshals the MACCommand_DeviceModeConf to JSON. -func (x *MACCommand_DeviceModeConf) MarshalJSON() ([]byte, error) { +// MarshalJSON marshals the MACCommand_RelayNotifyNewEndDeviceReq to JSON. +func (x *MACCommand_RelayNotifyNewEndDeviceReq) MarshalJSON() ([]byte, error) { return jsonplugin.DefaultMarshalerConfig.Marshal(x) } -// UnmarshalProtoJSON unmarshals the MACCommand_DeviceModeConf message from JSON. -func (x *MACCommand_DeviceModeConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { +// UnmarshalProtoJSON unmarshals the MACCommand_RelayNotifyNewEndDeviceReq message from JSON. +func (x *MACCommand_RelayNotifyNewEndDeviceReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { if s.ReadNil() { return } @@ -3171,15 +4267,21 @@ func (x *MACCommand_DeviceModeConf) UnmarshalProtoJSON(s *jsonplugin.UnmarshalSt switch key { default: s.ReadAny() // ignore unknown field - case "class": - s.AddField("class") - x.Class.UnmarshalProtoJSON(s) + case "dev_addr", "devAddr": + s.AddField("dev_addr") + x.DevAddr = types.Unmarshal4Bytes(s.WithField("dev_addr", false)) + case "snr": + s.AddField("snr") + x.Snr = s.ReadInt32() + case "rssi": + s.AddField("rssi") + x.Rssi = s.ReadInt32() } }) } -// UnmarshalJSON unmarshals the MACCommand_DeviceModeConf from JSON. -func (x *MACCommand_DeviceModeConf) UnmarshalJSON(b []byte) error { +// UnmarshalJSON unmarshals the MACCommand_RelayNotifyNewEndDeviceReq from JSON. +func (x *MACCommand_RelayNotifyNewEndDeviceReq) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } @@ -3335,6 +4437,55 @@ func (x *MACCommand) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteMoreIf(&wroteField) s.WriteObjectField("device_mode_conf") ov.DeviceModeConf.MarshalProtoJSON(s.WithField("device_mode_conf")) + case *MACCommand_RelayConfReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_conf_req") + ov.RelayConfReq.MarshalProtoJSON(s.WithField("relay_conf_req")) + case *MACCommand_RelayConfAns_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_conf_ans") + // NOTE: MACCommand_RelayConfAns does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.RelayConfAns) + case *MACCommand_RelayEndDeviceConfReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_end_device_conf_req") + ov.RelayEndDeviceConfReq.MarshalProtoJSON(s.WithField("relay_end_device_conf_req")) + case *MACCommand_RelayEndDeviceConfAns_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_end_device_conf_ans") + // NOTE: MACCommand_RelayEndDeviceConfAns does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.RelayEndDeviceConfAns) + case *MACCommand_RelayUpdateUplinkListReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_update_uplink_list_req") + ov.RelayUpdateUplinkListReq.MarshalProtoJSON(s.WithField("relay_update_uplink_list_req")) + case *MACCommand_RelayUpdateUplinkListAns_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_update_uplink_list_ans") + // NOTE: MACCommand_RelayUpdateUplinkListAns does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.RelayUpdateUplinkListAns) + case *MACCommand_RelayCtrlUplinkListReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_ctrl_uplink_list_req") + ov.RelayCtrlUplinkListReq.MarshalProtoJSON(s.WithField("relay_ctrl_uplink_list_req")) + case *MACCommand_RelayCtrlUplinkListAns_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_ctrl_uplink_list_ans") + // NOTE: MACCommand_RelayCtrlUplinkListAns does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.RelayCtrlUplinkListAns) + case *MACCommand_RelayConfigureFwdLimitReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_configure_fwd_limit_req") + ov.RelayConfigureFwdLimitReq.MarshalProtoJSON(s.WithField("relay_configure_fwd_limit_req")) + case *MACCommand_RelayConfigureFwdLimitAns_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_configure_fwd_limit_ans") + // NOTE: MACCommand_RelayConfigureFwdLimitAns does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, ov.RelayConfigureFwdLimitAns) + case *MACCommand_RelayNotifyNewEndDeviceReq_: + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay_notify_new_end_device_req") + ov.RelayNotifyNewEndDeviceReq.MarshalProtoJSON(s.WithField("relay_notify_new_end_device_req")) } } s.WriteObjectEnd() @@ -3671,6 +4822,120 @@ func (x *MACCommand) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { } ov.DeviceModeConf = &MACCommand_DeviceModeConf{} ov.DeviceModeConf.UnmarshalProtoJSON(s.WithField("device_mode_conf", true)) + case "relay_conf_req", "relayConfReq": + ov := &MACCommand_RelayConfReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayConfReq = nil + return + } + ov.RelayConfReq = &MACCommand_RelayConfReq{} + ov.RelayConfReq.UnmarshalProtoJSON(s.WithField("relay_conf_req", true)) + case "relay_conf_ans", "relayConfAns": + s.AddField("relay_conf_ans") + ov := &MACCommand_RelayConfAns_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayConfAns = nil + return + } + // NOTE: MACCommand_RelayConfAns does not seem to implement UnmarshalProtoJSON. + var v MACCommand_RelayConfAns + golang.UnmarshalMessage(s, &v) + ov.RelayConfAns = &v + case "relay_end_device_conf_req", "relayEndDeviceConfReq": + ov := &MACCommand_RelayEndDeviceConfReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayEndDeviceConfReq = nil + return + } + ov.RelayEndDeviceConfReq = &MACCommand_RelayEndDeviceConfReq{} + ov.RelayEndDeviceConfReq.UnmarshalProtoJSON(s.WithField("relay_end_device_conf_req", true)) + case "relay_end_device_conf_ans", "relayEndDeviceConfAns": + s.AddField("relay_end_device_conf_ans") + ov := &MACCommand_RelayEndDeviceConfAns_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayEndDeviceConfAns = nil + return + } + // NOTE: MACCommand_RelayEndDeviceConfAns does not seem to implement UnmarshalProtoJSON. + var v MACCommand_RelayEndDeviceConfAns + golang.UnmarshalMessage(s, &v) + ov.RelayEndDeviceConfAns = &v + case "relay_update_uplink_list_req", "relayUpdateUplinkListReq": + ov := &MACCommand_RelayUpdateUplinkListReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayUpdateUplinkListReq = nil + return + } + ov.RelayUpdateUplinkListReq = &MACCommand_RelayUpdateUplinkListReq{} + ov.RelayUpdateUplinkListReq.UnmarshalProtoJSON(s.WithField("relay_update_uplink_list_req", true)) + case "relay_update_uplink_list_ans", "relayUpdateUplinkListAns": + s.AddField("relay_update_uplink_list_ans") + ov := &MACCommand_RelayUpdateUplinkListAns_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayUpdateUplinkListAns = nil + return + } + // NOTE: MACCommand_RelayUpdateUplinkListAns does not seem to implement UnmarshalProtoJSON. + var v MACCommand_RelayUpdateUplinkListAns + golang.UnmarshalMessage(s, &v) + ov.RelayUpdateUplinkListAns = &v + case "relay_ctrl_uplink_list_req", "relayCtrlUplinkListReq": + ov := &MACCommand_RelayCtrlUplinkListReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayCtrlUplinkListReq = nil + return + } + ov.RelayCtrlUplinkListReq = &MACCommand_RelayCtrlUplinkListReq{} + ov.RelayCtrlUplinkListReq.UnmarshalProtoJSON(s.WithField("relay_ctrl_uplink_list_req", true)) + case "relay_ctrl_uplink_list_ans", "relayCtrlUplinkListAns": + s.AddField("relay_ctrl_uplink_list_ans") + ov := &MACCommand_RelayCtrlUplinkListAns_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayCtrlUplinkListAns = nil + return + } + // NOTE: MACCommand_RelayCtrlUplinkListAns does not seem to implement UnmarshalProtoJSON. + var v MACCommand_RelayCtrlUplinkListAns + golang.UnmarshalMessage(s, &v) + ov.RelayCtrlUplinkListAns = &v + case "relay_configure_fwd_limit_req", "relayConfigureFwdLimitReq": + ov := &MACCommand_RelayConfigureFwdLimitReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayConfigureFwdLimitReq = nil + return + } + ov.RelayConfigureFwdLimitReq = &MACCommand_RelayConfigureFwdLimitReq{} + ov.RelayConfigureFwdLimitReq.UnmarshalProtoJSON(s.WithField("relay_configure_fwd_limit_req", true)) + case "relay_configure_fwd_limit_ans", "relayConfigureFwdLimitAns": + s.AddField("relay_configure_fwd_limit_ans") + ov := &MACCommand_RelayConfigureFwdLimitAns_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayConfigureFwdLimitAns = nil + return + } + // NOTE: MACCommand_RelayConfigureFwdLimitAns does not seem to implement UnmarshalProtoJSON. + var v MACCommand_RelayConfigureFwdLimitAns + golang.UnmarshalMessage(s, &v) + ov.RelayConfigureFwdLimitAns = &v + case "relay_notify_new_end_device_req", "relayNotifyNewEndDeviceReq": + ov := &MACCommand_RelayNotifyNewEndDeviceReq_{} + x.Payload = ov + if s.ReadNil() { + ov.RelayNotifyNewEndDeviceReq = nil + return + } + ov.RelayNotifyNewEndDeviceReq = &MACCommand_RelayNotifyNewEndDeviceReq{} + ov.RelayNotifyNewEndDeviceReq.UnmarshalProtoJSON(s.WithField("relay_notify_new_end_device_req", true)) } }) } @@ -4032,3 +5297,155 @@ func (x *DeviceEIRPValue) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { func (x *DeviceEIRPValue) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } + +// MarshalProtoJSON marshals the RelayForwardUplinkReq message to JSON. +func (x *RelayForwardUplinkReq) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.DataRate != nil || s.HasField("data_rate") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("data_rate") + // NOTE: DataRate does not seem to implement MarshalProtoJSON. + golang.MarshalMessage(s, x.DataRate) + } + if x.Snr != 0 || s.HasField("snr") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("snr") + s.WriteInt32(x.Snr) + } + if x.Rssi != 0 || s.HasField("rssi") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("rssi") + s.WriteInt32(x.Rssi) + } + if x.WorChannel != 0 || s.HasField("wor_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("wor_channel") + x.WorChannel.MarshalProtoJSON(s) + } + if x.Frequency != 0 || s.HasField("frequency") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("frequency") + s.WriteUint64(x.Frequency) + } + if len(x.RawPayload) > 0 || s.HasField("raw_payload") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("raw_payload") + s.WriteBytes(x.RawPayload) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayForwardUplinkReq to JSON. +func (x *RelayForwardUplinkReq) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayForwardUplinkReq message from JSON. +func (x *RelayForwardUplinkReq) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "data_rate", "dataRate": + s.AddField("data_rate") + if s.ReadNil() { + x.DataRate = nil + return + } + // NOTE: DataRate does not seem to implement UnmarshalProtoJSON. + var v DataRate + golang.UnmarshalMessage(s, &v) + x.DataRate = &v + case "snr": + s.AddField("snr") + x.Snr = s.ReadInt32() + case "rssi": + s.AddField("rssi") + x.Rssi = s.ReadInt32() + case "wor_channel", "worChannel": + s.AddField("wor_channel") + x.WorChannel.UnmarshalProtoJSON(s) + case "frequency": + s.AddField("frequency") + x.Frequency = s.ReadUint64() + case "raw_payload", "rawPayload": + s.AddField("raw_payload") + x.RawPayload = s.ReadBytes() + } + }) +} + +// UnmarshalJSON unmarshals the RelayForwardUplinkReq from JSON. +func (x *RelayForwardUplinkReq) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} + +// MarshalProtoJSON marshals the RelayUplinkToken message to JSON. +func (x *RelayUplinkToken) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.Ids != nil || s.HasField("ids") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("ids") + x.Ids.MarshalProtoJSON(s.WithField("ids")) + } + if len(x.SessionKeyId) > 0 || s.HasField("session_key_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("session_key_id") + s.WriteBytes(x.SessionKeyId) + } + if x.FullFCnt != 0 || s.HasField("full_f_cnt") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("full_f_cnt") + s.WriteUint32(x.FullFCnt) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayUplinkToken to JSON. +func (x *RelayUplinkToken) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayUplinkToken message from JSON. +func (x *RelayUplinkToken) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "ids": + if s.ReadNil() { + x.Ids = nil + return + } + x.Ids = &EndDeviceIdentifiers{} + x.Ids.UnmarshalProtoJSON(s.WithField("ids", true)) + case "session_key_id", "sessionKeyId": + s.AddField("session_key_id") + x.SessionKeyId = s.ReadBytes() + case "full_f_cnt", "fullFCnt": + s.AddField("full_f_cnt") + x.FullFCnt = s.ReadUint32() + } + }) +} + +// UnmarshalJSON unmarshals the RelayUplinkToken from JSON. +func (x *RelayUplinkToken) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} diff --git a/pkg/ttnpb/lorawan_mac_commands.go b/pkg/ttnpb/lorawan_mac_commands.go index 407b8d4d9b..38b0167494 100644 --- a/pkg/ttnpb/lorawan_mac_commands.go +++ b/pkg/ttnpb/lorawan_mac_commands.go @@ -328,3 +328,141 @@ func (pld *MACCommand_DeviceModeConf) MACCommand() *MACCommand { }, } } + +// MACCommand returns the RelayConfReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayConfReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CONF, + Payload: &MACCommand_RelayConfReq_{ + RelayConfReq: pld, + }, + } +} + +// MACCommand returns the RelayConfAns MAC command as a *MACCommand. +func (pld *MACCommand_RelayConfAns) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CONF, + Payload: &MACCommand_RelayConfAns_{ + RelayConfAns: pld, + }, + } +} + +// MACCommand returns the EndDeviceConfReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayEndDeviceConfReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + Payload: &MACCommand_RelayEndDeviceConfReq_{ + RelayEndDeviceConfReq: pld, + }, + } +} + +// MACCommand returns the EndDeviceConfAns MAC command as a *MACCommand. +func (pld *MACCommand_RelayEndDeviceConfAns) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_END_DEVICE_CONF, + Payload: &MACCommand_RelayEndDeviceConfAns_{ + RelayEndDeviceConfAns: pld, + }, + } +} + +// MACCommand returns the UpdateUplinkListReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayUpdateUplinkListReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + Payload: &MACCommand_RelayUpdateUplinkListReq_{ + RelayUpdateUplinkListReq: pld, + }, + } +} + +// MACCommand returns the UpdateUplinkListAns MAC command as a *MACCommand. +func (pld *MACCommand_RelayUpdateUplinkListAns) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_UPDATE_UPLINK_LIST, + Payload: &MACCommand_RelayUpdateUplinkListAns_{ + RelayUpdateUplinkListAns: pld, + }, + } +} + +// MACCommand returns the RelayCtrlUplinkListReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayCtrlUplinkListReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + Payload: &MACCommand_RelayCtrlUplinkListReq_{ + RelayCtrlUplinkListReq: pld, + }, + } +} + +// MACCommand returns the RelayCtrlUplinkListAns MAC command as a *MACCommand. +func (pld *MACCommand_RelayCtrlUplinkListAns) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CTRL_UPLINK_LIST, + Payload: &MACCommand_RelayCtrlUplinkListAns_{ + RelayCtrlUplinkListAns: pld, + }, + } +} + +// MACCommand returns the ConfigureFwdLimitReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayConfigureFwdLimitReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + Payload: &MACCommand_RelayConfigureFwdLimitReq_{ + RelayConfigureFwdLimitReq: pld, + }, + } +} + +// MACCommand returns the ConfigureFwdLimitAns MAC command as a *MACCommand. +func (pld *MACCommand_RelayConfigureFwdLimitAns) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_CONFIGURE_FWD_LIMIT, + Payload: &MACCommand_RelayConfigureFwdLimitAns_{ + RelayConfigureFwdLimitAns: pld, + }, + } +} + +// MACCommand returns the NotifyNewEndDeviceReq MAC command as a *MACCommand. +func (pld *MACCommand_RelayNotifyNewEndDeviceReq) MACCommand() *MACCommand { + return &MACCommand{ + Cid: MACCommandIdentifier_CID_RELAY_NOTIFY_NEW_END_DEVICE, + Payload: &MACCommand_RelayNotifyNewEndDeviceReq_{ + RelayNotifyNewEndDeviceReq: pld, + }, + } +} + +// sanitizableMACCommandPayload is a MAC command payload that can be sanitized. +type sanitizableMACCommandPayload interface { + // sanitizedMACCommand returns a sanitized copy of the MAC command. + sanitizedMACCommand() *MACCommand +} + +// Sanitized returns a sanitized copy of the MAC command. +func (m *MACCommand) Sanitized() *MACCommand { + if v, ok := m.GetPayload().(sanitizableMACCommandPayload); ok { + return v.sanitizedMACCommand() + } + return m +} + +var _ sanitizableMACCommandPayload = (*MACCommand_RelayUpdateUplinkListReq_)(nil) + +// Sanitized returns a sanitized copy of the payload. +func (pld *MACCommand_RelayUpdateUplinkListReq) Sanitized() *MACCommand_RelayUpdateUplinkListReq { + pld = Clone(pld) + pld.RootWorSKey = nil + return pld +} + +// sanitizedMACCommand returns a sanitized copy of the MAC command. +func (pld *MACCommand_RelayUpdateUplinkListReq_) sanitizedMACCommand() *MACCommand { + return pld.RelayUpdateUplinkListReq.Sanitized().MACCommand() +} diff --git a/pkg/ttnpb/messages_flags.pb.go b/pkg/ttnpb/messages_flags.pb.go index e8dfada3f1..38ea4ccdd8 100644 --- a/pkg/ttnpb/messages_flags.pb.go +++ b/pkg/ttnpb/messages_flags.pb.go @@ -165,7 +165,7 @@ func AddSetFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hidden // FIXME: Skipping NormalizedPayload because this repeated WKT is currently not supported. flags.AddFlag(flagsplugin.NewStringSliceFlag(flagsplugin.Prefix("normalized-payload-warnings", prefix), "", flagsplugin.WithHidden(hidden))) // FIXME: Skipping RxMetadata because repeated messages are currently not supported. - // FIXME: Skipping Settings because it does not seem to implement AddSetFlags. + AddSetFlagsForTxSettings(flags, flagsplugin.Prefix("settings", prefix), hidden) flags.AddFlag(flagsplugin.NewTimestampFlag(flagsplugin.Prefix("received-at", prefix), "", flagsplugin.WithHidden(hidden))) AddSetFlagsForKeyEnvelope(flags, flagsplugin.Prefix("app-s-key", prefix), hidden) flags.AddFlag(flagsplugin.NewUint32Flag(flagsplugin.Prefix("last-a-f-cnt-down", prefix), "", flagsplugin.WithHidden(hidden))) @@ -173,7 +173,7 @@ func AddSetFlagsForApplicationUplink(flags *pflag.FlagSet, prefix string, hidden flags.AddFlag(flagsplugin.NewDurationFlag(flagsplugin.Prefix("consumed-airtime", prefix), "", flagsplugin.WithHidden(hidden))) // FIXME: Skipping Locations because maps with message value types are currently not supported. AddSetFlagsForEndDeviceVersionIdentifiers(flags, flagsplugin.Prefix("version-ids", prefix), hidden) - // FIXME: Skipping NetworkIds because it does not seem to implement AddSetFlags. + AddSetFlagsForNetworkIdentifiers(flags, flagsplugin.Prefix("network-ids", prefix), hidden) } // SetFromFlags sets the ApplicationUplink message from flags. @@ -217,7 +217,16 @@ func (m *ApplicationUplink) SetFromFlags(flags *pflag.FlagSet, prefix string) (p paths = append(paths, flagsplugin.Prefix("normalized_payload_warnings", prefix)) } // FIXME: Skipping RxMetadata because it does not seem to implement AddSetFlags. - // FIXME: Skipping Settings because it does not seem to implement AddSetFlags. + if changed := flagsplugin.IsAnyPrefixSet(flags, flagsplugin.Prefix("settings", prefix)); changed { + if m.Settings == nil { + m.Settings = &TxSettings{} + } + if setPaths, err := m.Settings.SetFromFlags(flags, flagsplugin.Prefix("settings", prefix)); err != nil { + return nil, err + } else { + paths = append(paths, setPaths...) + } + } if val, changed, err := flagsplugin.GetTimestamp(flags, flagsplugin.Prefix("received_at", prefix)); err != nil { return nil, err } else if changed { @@ -263,7 +272,16 @@ func (m *ApplicationUplink) SetFromFlags(flags *pflag.FlagSet, prefix string) (p paths = append(paths, setPaths...) } } - // FIXME: Skipping NetworkIds because it does not seem to implement AddSetFlags. + 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...) + } + } return paths, nil } diff --git a/pkg/ttnpb/metadata.pb.go b/pkg/ttnpb/metadata.pb.go index 9ae514f75a..a3ec06d512 100644 --- a/pkg/ttnpb/metadata.pb.go +++ b/pkg/ttnpb/metadata.pb.go @@ -126,6 +126,7 @@ type RxMetadata struct { GatewayIds *GatewayIdentifiers `protobuf:"bytes,1,opt,name=gateway_ids,json=gatewayIds,proto3" json:"gateway_ids,omitempty"` PacketBroker *PacketBrokerMetadata `protobuf:"bytes,18,opt,name=packet_broker,json=packetBroker,proto3" json:"packet_broker,omitempty"` + Relay *RelayMetadata `protobuf:"bytes,23,opt,name=relay,proto3" json:"relay,omitempty"` AntennaIndex uint32 `protobuf:"varint,2,opt,name=antenna_index,json=antennaIndex,proto3" json:"antenna_index,omitempty"` // Timestamp at the end of the transmission, provided by the gateway. The accuracy is undefined. Time *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time,proto3" json:"time,omitempty"` @@ -218,6 +219,13 @@ func (x *RxMetadata) GetPacketBroker() *PacketBrokerMetadata { return nil } +func (x *RxMetadata) GetRelay() *RelayMetadata { + if x != nil { + return x.Relay + } + return nil +} + func (x *RxMetadata) GetAntennaIndex() uint32 { if x != nil { return x.AntennaIndex @@ -663,6 +671,63 @@ func (x *PacketBrokerRouteHop) GetReceiverAgent() string { return "" } +type RelayMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // End device identifiers of the relay. + DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"` + // Wake on radio channel. + WorChannel RelayWORChannel `protobuf:"varint,2,opt,name=wor_channel,json=worChannel,proto3,enum=ttn.lorawan.v3.RelayWORChannel" json:"wor_channel,omitempty"` +} + +func (x *RelayMetadata) Reset() { + *x = RelayMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_ttn_lorawan_v3_metadata_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RelayMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RelayMetadata) ProtoMessage() {} + +func (x *RelayMetadata) ProtoReflect() protoreflect.Message { + mi := &file_ttn_lorawan_v3_metadata_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RelayMetadata.ProtoReflect.Descriptor instead. +func (*RelayMetadata) Descriptor() ([]byte, []int) { + return file_ttn_lorawan_v3_metadata_proto_rawDescGZIP(), []int{4} +} + +func (x *RelayMetadata) GetDeviceId() string { + if x != nil { + return x.DeviceId + } + return "" +} + +func (x *RelayMetadata) GetWorChannel() RelayWORChannel { + if x != nil { + return x.WorChannel + } + return RelayWORChannel_RELAY_WOR_CHANNEL_DEFAULT +} + var File_ttn_lorawan_v3_metadata_proto protoreflect.FileDescriptor var file_ttn_lorawan_v3_metadata_proto_rawDesc = []byte{ @@ -686,201 +751,216 @@ var file_ttn_lorawan_v3_metadata_proto_rawDesc = []byte{ 0x2f, 0x76, 0x33, 0x2f, 0x65, 0x6e, 0x75, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, 0x33, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x95, 0x09, 0x0a, 0x0a, 0x52, - 0x78, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4d, 0x0a, 0x0b, 0x67, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, - 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x67, 0x61, - 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x73, 0x12, 0x49, 0x0a, 0x0d, 0x70, 0x61, 0x63, 0x6b, - 0x65, 0x74, 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, - 0x6b, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6e, 0x74, 0x65, 0x6e, 0x6e, 0x61, 0x5f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, 0x6e, 0x74, 0x65, - 0x6e, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, - 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, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x69, 0x6e, 0x65, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, - 0x66, 0x69, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x38, 0x0a, - 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x65, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x16, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, 0x1f, 0x65, 0x6e, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x1b, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, 0x65, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x12, 0x0a, - 0x04, 0x72, 0x73, 0x73, 0x69, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x04, 0x72, 0x73, 0x73, - 0x69, 0x12, 0x3c, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x73, 0x73, 0x69, - 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x73, 0x73, 0x69, 0x12, - 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x73, 0x73, 0x69, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x73, - 0x73, 0x69, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x73, 0x73, 0x69, 0x5f, 0x73, 0x74, 0x61, 0x6e, 0x64, - 0x61, 0x72, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x02, 0x52, 0x15, 0x72, 0x73, 0x73, 0x69, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, - 0x64, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x6e, - 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, 0x29, 0x0a, 0x10, - 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, - 0x79, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x0d, 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, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6a, 0x0a, - 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x63, - 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, - 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x43, 0x6f, 0x6e, - 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, - 0x01, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x43, - 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x75, 0x70, 0x6c, - 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2d, 0x0a, 0x0d, - 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, 0x52, 0x0c, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x68, - 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, 0x13, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x57, 0x69, 0x64, 0x74, 0x68, - 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x64, 0x72, - 0x69, 0x66, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x66, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x79, 0x44, 0x72, 0x69, 0x66, 0x74, 0x12, 0x35, 0x0a, 0x08, 0x67, 0x70, 0x73, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x15, 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, 0x07, 0x67, 0x70, 0x73, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, - 0x16, 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, 0x33, 0x0a, - 0x08, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x63, 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, 0x08, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, - 0x65, 0x64, 0x22, 0x80, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x33, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x01, 0x42, 0x17, 0xfa, 0x42, 0x14, 0x12, 0x12, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x56, - 0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x56, 0xc0, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, - 0x74, 0x75, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x42, 0x17, 0xfa, 0x42, 0x14, 0x12, 0x12, 0x19, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x66, 0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x66, 0xc0, - 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, - 0x6c, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x61, - 0x6c, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x75, 0x72, - 0x61, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x61, 0x63, 0x63, 0x75, 0x72, - 0x61, 0x63, 0x79, 0x12, 0x46, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, - 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x42, 0x0e, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0xf2, 0xaa, 0x19, - 0x02, 0x10, 0x00, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0xf2, 0xaa, 0x19, - 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xae, 0x08, 0x0a, 0x14, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, - 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1d, - 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, 0x12, 0xd5, 0x01, - 0x0a, 0x10, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x65, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xaa, 0x01, 0x92, 0x41, 0x17, 0x4a, 0x08, - 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, 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, 0x33, - 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, - 0x4e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, - 0x65, 0x72, 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x11, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x54, 0x65, 0x6e, - 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, - 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x12, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x43, 0x6c, - 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0xe9, 0x01, 0x0a, 0x15, 0x66, 0x6f, 0x72, 0x77, - 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x65, 0x75, - 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, 0x92, 0x41, 0x21, 0x4a, 0x12, 0x22, - 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, 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, 0x08, 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, 0x38, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x13, - 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x45, 0x75, 0x69, 0x12, 0x4e, 0x0a, 0x14, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, - 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x12, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, - 0x79, 0x49, 0x64, 0x12, 0xda, 0x01, 0x0a, 0x13, 0x68, 0x6f, 0x6d, 0x65, 0x5f, 0x6e, 0x65, 0x74, - 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x0c, 0x42, 0xaa, 0x01, 0x92, 0x41, 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, - 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, - 0x06, 0x7a, 0x04, 0x68, 0x03, 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, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x10, - 0x68, 0x6f, 0x6d, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x65, 0x74, 0x49, 0x64, - 0x12, 0x33, 0x0a, 0x16, 0x68, 0x6f, 0x6d, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, - 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x13, 0x68, 0x6f, 0x6d, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x54, 0x65, 0x6e, - 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x17, 0x68, 0x6f, 0x6d, 0x65, 0x5f, 0x6e, 0x65, - 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x68, 0x6f, 0x6d, 0x65, 0x4e, 0x65, 0x74, 0x77, - 0x6f, 0x72, 0x6b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x04, - 0x68, 0x6f, 0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x74, 0x74, 0x6e, - 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, 0x61, 0x63, 0x6b, - 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x6f, 0x70, - 0x52, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x22, 0xe7, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x63, 0x6b, 0x65, - 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x6f, 0x70, 0x12, - 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x01, - 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, 0x1f, 0x0a, 0x0b, - 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, - 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, - 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x72, 0x65, 0x63, - 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, - 0x2a, 0x9b, 0x02, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x4e, - 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x47, 0x50, 0x53, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, 0x59, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, - 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x57, 0x49, 0x46, 0x49, 0x5f, 0x52, 0x53, 0x53, 0x49, 0x5f, 0x47, 0x45, 0x4f, 0x4c, - 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x42, 0x54, 0x5f, 0x52, 0x53, 0x53, 0x49, 0x5f, 0x47, 0x45, 0x4f, 0x4c, - 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x4c, 0x4f, 0x52, 0x41, 0x5f, 0x52, 0x53, 0x53, 0x49, 0x5f, 0x47, 0x45, - 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x07, 0x12, 0x20, 0x0a, 0x1c, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x4c, 0x4f, 0x52, 0x41, 0x5f, 0x54, 0x44, 0x4f, 0x41, 0x5f, - 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x08, 0x12, 0x1f, 0x0a, - 0x1b, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x45, 0x44, - 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x1a, 0x0e, - 0xea, 0xaa, 0x19, 0x0a, 0x18, 0x01, 0x2a, 0x06, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x42, 0x31, - 0x5a, 0x2f, 0x67, 0x6f, 0x2e, 0x74, 0x68, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x6e, + 0x6f, 0x1a, 0x1c, 0x74, 0x74, 0x6e, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2f, 0x76, + 0x33, 0x2f, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xca, 0x09, 0x0a, 0x0a, 0x52, 0x78, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4d, 0x0a, 0x0b, 0x67, 0x61, 0x74, 0x65, 0x77, + 0x61, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, + 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x47, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x67, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x49, 0x64, 0x73, 0x12, 0x49, 0x0a, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, + 0x5f, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x0c, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, + 0x72, 0x12, 0x33, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x61, 0x6e, 0x74, 0x65, 0x6e, 0x6e, + 0x61, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x61, + 0x6e, 0x74, 0x65, 0x6e, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2e, 0x0a, 0x04, 0x74, + 0x69, 0x6d, 0x65, 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, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x69, 0x6e, + 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0d, 0x66, 0x69, 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x38, 0x0a, 0x18, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, + 0x6e, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x16, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6e, + 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x44, 0x0a, 0x1f, 0x65, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6e, 0x65, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x1b, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x46, 0x69, + 0x6e, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x4b, 0x65, 0x79, 0x49, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x72, 0x73, 0x73, 0x69, 0x18, 0x08, 0x20, 0x01, 0x28, 0x02, 0x52, 0x04, + 0x72, 0x73, 0x73, 0x69, 0x12, 0x3c, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, + 0x73, 0x73, 0x69, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, + 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x73, + 0x73, 0x69, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x73, + 0x73, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x52, 0x73, 0x73, 0x69, 0x12, 0x36, 0x0a, 0x17, 0x72, 0x73, 0x73, 0x69, 0x5f, 0x73, 0x74, + 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x02, 0x52, 0x15, 0x72, 0x73, 0x73, 0x69, 0x53, 0x74, 0x61, 0x6e, + 0x64, 0x61, 0x72, 0x64, 0x44, 0x65, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, + 0x03, 0x73, 0x6e, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x02, 0x52, 0x03, 0x73, 0x6e, 0x72, 0x12, + 0x29, 0x0a, 0x10, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x34, 0x0a, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0d, 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, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x6a, 0x0a, 0x18, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x61, 0x74, + 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x18, 0x0e, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, + 0x2e, 0x76, 0x33, 0x2e, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, 0x74, 0x68, + 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, + 0x01, 0x02, 0x10, 0x01, 0x52, 0x16, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x50, 0x61, + 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0b, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, + 0x2d, 0x0a, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x2a, 0x03, 0x18, 0xff, 0x01, + 0x52, 0x0c, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x23, + 0x0a, 0x0d, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x77, 0x69, 0x64, 0x74, 0x68, 0x18, + 0x13, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x57, 0x69, + 0x64, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x5f, 0x64, 0x72, 0x69, 0x66, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x66, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x44, 0x72, 0x69, 0x66, 0x74, 0x12, 0x35, 0x0a, 0x08, + 0x67, 0x70, 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x15, 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, 0x07, 0x67, 0x70, 0x73, 0x54, + 0x69, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, + 0x61, 0x74, 0x18, 0x16, 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, 0x33, 0x0a, 0x08, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x18, 0x63, 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, 0x08, 0x61, 0x64, 0x76, + 0x61, 0x6e, 0x63, 0x65, 0x64, 0x22, 0x80, 0x02, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x01, 0x42, 0x17, 0xfa, 0x42, 0x14, 0x12, 0x12, 0x19, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x56, 0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x56, 0xc0, 0x52, 0x08, 0x6c, + 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, + 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x42, 0x17, 0xfa, 0x42, 0x14, 0x12, + 0x12, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x66, 0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x66, 0xc0, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x61, 0x6c, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x61, 0x6c, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, + 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x61, 0x63, + 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x12, 0x46, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, + 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x0e, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, + 0xf2, 0xaa, 0x19, 0x02, 0x10, 0x00, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, + 0xf2, 0xaa, 0x19, 0x04, 0x08, 0x01, 0x10, 0x01, 0x22, 0xae, 0x08, 0x0a, 0x14, 0x50, 0x61, 0x63, + 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x64, + 0x12, 0xd5, 0x01, 0x0a, 0x10, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x6e, + 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xaa, 0x01, 0x92, 0x41, + 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, + 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, 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, 0x33, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x0e, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x65, 0x72, 0x4e, 0x65, 0x74, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x13, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, + 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, + 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, 0xe9, 0x01, 0x0a, 0x15, 0x66, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x5f, 0x65, 0x75, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x42, 0xb4, 0x01, 0x92, 0x41, 0x21, + 0x4a, 0x12, 0x22, 0x37, 0x30, 0x42, 0x33, 0x44, 0x35, 0x37, 0x45, 0x44, 0x30, 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, 0x08, 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, 0x74, 0x6e, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 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, 0x38, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x13, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x45, 0x75, 0x69, 0x12, 0x4e, 0x0a, 0x14, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, + 0x64, 0x65, 0x72, 0x5f, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x12, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x65, 0x72, 0x47, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x49, 0x64, 0x12, 0xda, 0x01, 0x0a, 0x13, 0x68, 0x6f, 0x6d, 0x65, 0x5f, + 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0c, 0x42, 0xaa, 0x01, 0x92, 0x41, 0x17, 0x4a, 0x08, 0x22, 0x30, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x22, 0x9a, 0x02, 0x01, 0x07, 0xa2, 0x02, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0xfa, 0x42, 0x06, 0x7a, 0x04, 0x68, 0x03, 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, 0x33, 0x42, 0x79, 0x74, 0x65, + 0x73, 0x52, 0x10, 0x68, 0x6f, 0x6d, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x65, + 0x74, 0x49, 0x64, 0x12, 0x33, 0x0a, 0x16, 0x68, 0x6f, 0x6d, 0x65, 0x5f, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x5f, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x68, 0x6f, 0x6d, 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, + 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x35, 0x0a, 0x17, 0x68, 0x6f, 0x6d, 0x65, + 0x5f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 0x68, 0x6f, 0x6d, 0x65, 0x4e, + 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x12, + 0x38, 0x0a, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, 0x33, 0x2e, 0x50, + 0x61, 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x48, 0x6f, 0x70, 0x52, 0x04, 0x68, 0x6f, 0x70, 0x73, 0x22, 0xe7, 0x01, 0x0a, 0x14, 0x50, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, + 0x6f, 0x70, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x01, 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, + 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, + 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xfa, 0x42, 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, 0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x4a, 0x0a, 0x0b, 0x77, + 0x6f, 0x72, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1f, 0x2e, 0x74, 0x74, 0x6e, 0x2e, 0x6c, 0x6f, 0x72, 0x61, 0x77, 0x61, 0x6e, 0x2e, 0x76, + 0x33, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x57, 0x4f, 0x52, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x77, 0x6f, 0x72, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x2a, 0x9b, 0x02, 0x0a, 0x0e, 0x4c, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, + 0x0a, 0x0a, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x47, 0x50, 0x53, 0x10, 0x01, 0x12, 0x13, + 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x52, 0x45, 0x47, 0x49, 0x53, 0x54, 0x52, + 0x59, 0x10, 0x03, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x49, 0x50, + 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x04, 0x12, 0x20, + 0x0a, 0x1c, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x57, 0x49, 0x46, 0x49, 0x5f, 0x52, 0x53, + 0x53, 0x49, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, + 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x42, 0x54, 0x5f, 0x52, 0x53, + 0x53, 0x49, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x06, + 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x4c, 0x4f, 0x52, 0x41, 0x5f, + 0x52, 0x53, 0x53, 0x49, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, 0x4f, 0x4e, + 0x10, 0x07, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x4c, 0x4f, 0x52, + 0x41, 0x5f, 0x54, 0x44, 0x4f, 0x41, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x08, 0x12, 0x1f, 0x0a, 0x1b, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, + 0x4f, 0x4d, 0x42, 0x49, 0x4e, 0x45, 0x44, 0x5f, 0x47, 0x45, 0x4f, 0x4c, 0x4f, 0x43, 0x41, 0x54, + 0x49, 0x4f, 0x4e, 0x10, 0x09, 0x1a, 0x0e, 0xea, 0xaa, 0x19, 0x0a, 0x18, 0x01, 0x2a, 0x06, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 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 ( @@ -896,39 +976,43 @@ func file_ttn_lorawan_v3_metadata_proto_rawDescGZIP() []byte { } var file_ttn_lorawan_v3_metadata_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_ttn_lorawan_v3_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_ttn_lorawan_v3_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_ttn_lorawan_v3_metadata_proto_goTypes = []interface{}{ (LocationSource)(0), // 0: ttn.lorawan.v3.LocationSource (*RxMetadata)(nil), // 1: ttn.lorawan.v3.RxMetadata (*Location)(nil), // 2: ttn.lorawan.v3.Location (*PacketBrokerMetadata)(nil), // 3: ttn.lorawan.v3.PacketBrokerMetadata (*PacketBrokerRouteHop)(nil), // 4: ttn.lorawan.v3.PacketBrokerRouteHop - (*GatewayIdentifiers)(nil), // 5: ttn.lorawan.v3.GatewayIdentifiers - (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp - (*wrapperspb.FloatValue)(nil), // 7: google.protobuf.FloatValue - (DownlinkPathConstraint)(0), // 8: ttn.lorawan.v3.DownlinkPathConstraint - (*structpb.Struct)(nil), // 9: google.protobuf.Struct - (*wrapperspb.StringValue)(nil), // 10: google.protobuf.StringValue + (*RelayMetadata)(nil), // 5: ttn.lorawan.v3.RelayMetadata + (*GatewayIdentifiers)(nil), // 6: ttn.lorawan.v3.GatewayIdentifiers + (*timestamppb.Timestamp)(nil), // 7: google.protobuf.Timestamp + (*wrapperspb.FloatValue)(nil), // 8: google.protobuf.FloatValue + (DownlinkPathConstraint)(0), // 9: ttn.lorawan.v3.DownlinkPathConstraint + (*structpb.Struct)(nil), // 10: google.protobuf.Struct + (*wrapperspb.StringValue)(nil), // 11: google.protobuf.StringValue + (RelayWORChannel)(0), // 12: ttn.lorawan.v3.RelayWORChannel } var file_ttn_lorawan_v3_metadata_proto_depIdxs = []int32{ - 5, // 0: ttn.lorawan.v3.RxMetadata.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers + 6, // 0: ttn.lorawan.v3.RxMetadata.gateway_ids:type_name -> ttn.lorawan.v3.GatewayIdentifiers 3, // 1: ttn.lorawan.v3.RxMetadata.packet_broker:type_name -> ttn.lorawan.v3.PacketBrokerMetadata - 6, // 2: ttn.lorawan.v3.RxMetadata.time:type_name -> google.protobuf.Timestamp - 7, // 3: ttn.lorawan.v3.RxMetadata.signal_rssi:type_name -> google.protobuf.FloatValue - 2, // 4: ttn.lorawan.v3.RxMetadata.location:type_name -> ttn.lorawan.v3.Location - 8, // 5: ttn.lorawan.v3.RxMetadata.downlink_path_constraint:type_name -> ttn.lorawan.v3.DownlinkPathConstraint - 6, // 6: ttn.lorawan.v3.RxMetadata.gps_time:type_name -> google.protobuf.Timestamp - 6, // 7: ttn.lorawan.v3.RxMetadata.received_at:type_name -> google.protobuf.Timestamp - 9, // 8: ttn.lorawan.v3.RxMetadata.advanced:type_name -> google.protobuf.Struct - 0, // 9: ttn.lorawan.v3.Location.source:type_name -> ttn.lorawan.v3.LocationSource - 10, // 10: ttn.lorawan.v3.PacketBrokerMetadata.forwarder_gateway_id:type_name -> google.protobuf.StringValue - 4, // 11: ttn.lorawan.v3.PacketBrokerMetadata.hops:type_name -> ttn.lorawan.v3.PacketBrokerRouteHop - 6, // 12: ttn.lorawan.v3.PacketBrokerRouteHop.received_at:type_name -> google.protobuf.Timestamp - 13, // [13:13] is the sub-list for method output_type - 13, // [13:13] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 5, // 2: ttn.lorawan.v3.RxMetadata.relay:type_name -> ttn.lorawan.v3.RelayMetadata + 7, // 3: ttn.lorawan.v3.RxMetadata.time:type_name -> google.protobuf.Timestamp + 8, // 4: ttn.lorawan.v3.RxMetadata.signal_rssi:type_name -> google.protobuf.FloatValue + 2, // 5: ttn.lorawan.v3.RxMetadata.location:type_name -> ttn.lorawan.v3.Location + 9, // 6: ttn.lorawan.v3.RxMetadata.downlink_path_constraint:type_name -> ttn.lorawan.v3.DownlinkPathConstraint + 7, // 7: ttn.lorawan.v3.RxMetadata.gps_time:type_name -> google.protobuf.Timestamp + 7, // 8: ttn.lorawan.v3.RxMetadata.received_at:type_name -> google.protobuf.Timestamp + 10, // 9: ttn.lorawan.v3.RxMetadata.advanced:type_name -> google.protobuf.Struct + 0, // 10: ttn.lorawan.v3.Location.source:type_name -> ttn.lorawan.v3.LocationSource + 11, // 11: ttn.lorawan.v3.PacketBrokerMetadata.forwarder_gateway_id:type_name -> google.protobuf.StringValue + 4, // 12: ttn.lorawan.v3.PacketBrokerMetadata.hops:type_name -> ttn.lorawan.v3.PacketBrokerRouteHop + 7, // 13: ttn.lorawan.v3.PacketBrokerRouteHop.received_at:type_name -> google.protobuf.Timestamp + 12, // 14: ttn.lorawan.v3.RelayMetadata.wor_channel:type_name -> ttn.lorawan.v3.RelayWORChannel + 15, // [15:15] is the sub-list for method output_type + 15, // [15:15] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_ttn_lorawan_v3_metadata_proto_init() } @@ -938,6 +1022,7 @@ func file_ttn_lorawan_v3_metadata_proto_init() { } file_ttn_lorawan_v3_enums_proto_init() file_ttn_lorawan_v3_identifiers_proto_init() + file_ttn_lorawan_v3_lorawan_proto_init() if !protoimpl.UnsafeEnabled { file_ttn_lorawan_v3_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RxMetadata); i { @@ -987,6 +1072,18 @@ func file_ttn_lorawan_v3_metadata_proto_init() { return nil } } + file_ttn_lorawan_v3_metadata_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RelayMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -994,7 +1091,7 @@ func file_ttn_lorawan_v3_metadata_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_ttn_lorawan_v3_metadata_proto_rawDesc, NumEnums: 1, - NumMessages: 4, + NumMessages: 5, NumExtensions: 0, NumServices: 0, }, diff --git a/pkg/ttnpb/metadata.pb.paths.fm.go b/pkg/ttnpb/metadata.pb.paths.fm.go index 692280d0c8..878d9d1826 100644 --- a/pkg/ttnpb/metadata.pb.paths.fm.go +++ b/pkg/ttnpb/metadata.pb.paths.fm.go @@ -36,6 +36,9 @@ var RxMetadataFieldPathsNested = []string{ "packet_broker.hops", "packet_broker.message_id", "received_at", + "relay", + "relay.device_id", + "relay.wor_channel", "rssi", "rssi_standard_deviation", "signal_rssi", @@ -62,6 +65,7 @@ var RxMetadataFieldPathsTopLevel = []string{ "location", "packet_broker", "received_at", + "relay", "rssi", "rssi_standard_deviation", "signal_rssi", @@ -125,3 +129,12 @@ var PacketBrokerRouteHopFieldPathsTopLevel = []string{ "sender_address", "sender_name", } +var RelayMetadataFieldPathsNested = []string{ + "device_id", + "wor_channel", +} + +var RelayMetadataFieldPathsTopLevel = []string{ + "device_id", + "wor_channel", +} diff --git a/pkg/ttnpb/metadata.pb.setters.fm.go b/pkg/ttnpb/metadata.pb.setters.fm.go index 5eac69dbb0..b6e711d744 100644 --- a/pkg/ttnpb/metadata.pb.setters.fm.go +++ b/pkg/ttnpb/metadata.pb.setters.fm.go @@ -57,6 +57,31 @@ func (dst *RxMetadata) SetFields(src *RxMetadata, paths ...string) error { dst.PacketBroker = nil } } + case "relay": + if len(subs) > 0 { + var newDst, newSrc *RelayMetadata + if (src == nil || src.Relay == nil) && dst.Relay == nil { + continue + } + if src != nil { + newSrc = src.Relay + } + if dst.Relay != nil { + newDst = dst.Relay + } else { + newDst = &RelayMetadata{} + dst.Relay = newDst + } + if err := newDst.SetFields(newSrc, subs...); err != nil { + return err + } + } else { + if src != nil { + dst.Relay = src.Relay + } else { + dst.Relay = nil + } + } case "antenna_index": if len(subs) > 0 { return fmt.Errorf("'antenna_index' has no subfields, but %s were specified", subs) @@ -507,3 +532,33 @@ func (dst *PacketBrokerRouteHop) SetFields(src *PacketBrokerRouteHop, paths ...s } return nil } + +func (dst *RelayMetadata) SetFields(src *RelayMetadata, paths ...string) error { + for name, subs := range _processPaths(paths) { + switch name { + case "device_id": + if len(subs) > 0 { + return fmt.Errorf("'device_id' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.DeviceId = src.DeviceId + } else { + var zero string + dst.DeviceId = zero + } + case "wor_channel": + if len(subs) > 0 { + return fmt.Errorf("'wor_channel' has no subfields, but %s were specified", subs) + } + if src != nil { + dst.WorChannel = src.WorChannel + } else { + dst.WorChannel = 0 + } + + default: + return fmt.Errorf("invalid field: '%s'", name) + } + } + return nil +} diff --git a/pkg/ttnpb/metadata.pb.validate.go b/pkg/ttnpb/metadata.pb.validate.go index 90a88dd264..852bcc101e 100644 --- a/pkg/ttnpb/metadata.pb.validate.go +++ b/pkg/ttnpb/metadata.pb.validate.go @@ -78,6 +78,18 @@ func (m *RxMetadata) ValidateFields(paths ...string) error { } } + case "relay": + + if v, ok := interface{}(m.GetRelay()).(interface{ ValidateFields(...string) error }); ok { + if err := v.ValidateFields(subs...); err != nil { + return RxMetadataValidationError{ + field: "relay", + reason: "embedded message failed validation", + cause: err, + } + } + } + case "antenna_index": // no validation rules for AntennaIndex case "time": @@ -627,3 +639,109 @@ var _ interface { Cause() error ErrorName() string } = PacketBrokerRouteHopValidationError{} + +// ValidateFields checks the field values on RelayMetadata with the rules +// defined in the proto definition for this message. If any rules are +// violated, an error is returned. +func (m *RelayMetadata) ValidateFields(paths ...string) error { + if m == nil { + return nil + } + + if len(paths) == 0 { + paths = RelayMetadataFieldPathsNested + } + + for name, subs := range _processPaths(append(paths[:0:0], paths...)) { + _ = subs + switch name { + case "device_id": + + if utf8.RuneCountInString(m.GetDeviceId()) > 36 { + return RelayMetadataValidationError{ + field: "device_id", + reason: "value length must be at most 36 runes", + } + } + + if !_RelayMetadata_DeviceId_Pattern.MatchString(m.GetDeviceId()) { + return RelayMetadataValidationError{ + field: "device_id", + reason: "value does not match regex pattern \"^[a-z0-9](?:[-]?[a-z0-9]){2,}$\"", + } + } + + case "wor_channel": + + if _, ok := RelayWORChannel_name[int32(m.GetWorChannel())]; !ok { + return RelayMetadataValidationError{ + field: "wor_channel", + reason: "value must be one of the defined enum values", + } + } + + default: + return RelayMetadataValidationError{ + field: name, + reason: "invalid field path", + } + } + } + return nil +} + +// RelayMetadataValidationError is the validation error returned by +// RelayMetadata.ValidateFields if the designated constraints aren't met. +type RelayMetadataValidationError struct { + field string + reason string + cause error + key bool +} + +// Field function returns field value. +func (e RelayMetadataValidationError) Field() string { return e.field } + +// Reason function returns reason value. +func (e RelayMetadataValidationError) Reason() string { return e.reason } + +// Cause function returns cause value. +func (e RelayMetadataValidationError) Cause() error { return e.cause } + +// Key function returns key value. +func (e RelayMetadataValidationError) Key() bool { return e.key } + +// ErrorName returns error name. +func (e RelayMetadataValidationError) ErrorName() string { return "RelayMetadataValidationError" } + +// Error satisfies the builtin error interface +func (e RelayMetadataValidationError) Error() string { + cause := "" + if e.cause != nil { + cause = fmt.Sprintf(" | caused by: %v", e.cause) + } + + key := "" + if e.key { + key = "key for " + } + + return fmt.Sprintf( + "invalid %sRelayMetadata.%s: %s%s", + key, + e.field, + e.reason, + cause) +} + +var _ error = RelayMetadataValidationError{} + +var _ interface { + Field() string + Reason() string + Key() bool + Cause() error + ErrorName() string +} = RelayMetadataValidationError{} + +var _RelayMetadata_DeviceId_Pattern = regexp.MustCompile("^[a-z0-9](?:[-]?[a-z0-9]){2,}$") diff --git a/pkg/ttnpb/metadata_json.pb.go b/pkg/ttnpb/metadata_json.pb.go index 08f5421ed0..78fb30da13 100644 --- a/pkg/ttnpb/metadata_json.pb.go +++ b/pkg/ttnpb/metadata_json.pb.go @@ -84,6 +84,11 @@ func (x *RxMetadata) MarshalProtoJSON(s *jsonplugin.MarshalState) { s.WriteObjectField("packet_broker") x.PacketBroker.MarshalProtoJSON(s.WithField("packet_broker")) } + if x.Relay != nil || s.HasField("relay") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("relay") + x.Relay.MarshalProtoJSON(s.WithField("relay")) + } if x.AntennaIndex != 0 || s.HasField("antenna_index") { s.WriteMoreIf(&wroteField) s.WriteObjectField("antenna_index") @@ -240,6 +245,13 @@ func (x *RxMetadata) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { } x.PacketBroker = &PacketBrokerMetadata{} x.PacketBroker.UnmarshalProtoJSON(s.WithField("packet_broker", true)) + case "relay": + if s.ReadNil() { + x.Relay = nil + return + } + x.Relay = &RelayMetadata{} + x.Relay.UnmarshalProtoJSON(s.WithField("relay", true)) case "antenna_index", "antennaIndex": s.AddField("antenna_index") x.AntennaIndex = s.ReadUint32() @@ -571,3 +583,53 @@ func (x *PacketBrokerMetadata) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) func (x *PacketBrokerMetadata) UnmarshalJSON(b []byte) error { return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) } + +// MarshalProtoJSON marshals the RelayMetadata message to JSON. +func (x *RelayMetadata) MarshalProtoJSON(s *jsonplugin.MarshalState) { + if x == nil { + s.WriteNil() + return + } + s.WriteObjectStart() + var wroteField bool + if x.DeviceId != "" || s.HasField("device_id") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("device_id") + s.WriteString(x.DeviceId) + } + if x.WorChannel != 0 || s.HasField("wor_channel") { + s.WriteMoreIf(&wroteField) + s.WriteObjectField("wor_channel") + x.WorChannel.MarshalProtoJSON(s) + } + s.WriteObjectEnd() +} + +// MarshalJSON marshals the RelayMetadata to JSON. +func (x *RelayMetadata) MarshalJSON() ([]byte, error) { + return jsonplugin.DefaultMarshalerConfig.Marshal(x) +} + +// UnmarshalProtoJSON unmarshals the RelayMetadata message from JSON. +func (x *RelayMetadata) UnmarshalProtoJSON(s *jsonplugin.UnmarshalState) { + if s.ReadNil() { + return + } + s.ReadObject(func(key string) { + switch key { + default: + s.ReadAny() // ignore unknown field + case "device_id", "deviceId": + s.AddField("device_id") + x.DeviceId = s.ReadString() + case "wor_channel", "worChannel": + s.AddField("wor_channel") + x.WorChannel.UnmarshalProtoJSON(s) + } + }) +} + +// UnmarshalJSON unmarshals the RelayMetadata from JSON. +func (x *RelayMetadata) UnmarshalJSON(b []byte) error { + return jsonplugin.DefaultUnmarshalerConfig.Unmarshal(b, x) +} diff --git a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go index ab09f0addd..52103884db 100644 --- a/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go +++ b/pkg/ttnpb/qrcodegenerator.pb.paths.fm.go @@ -110,6 +110,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device.mac_settings.desired_ping_slot_frequency", "end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device.mac_settings.desired_relay", + "end_device.mac_settings.desired_relay.mode", + "end_device.mac_settings.desired_relay.mode.served", + "end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device.mac_settings.desired_relay.mode.served.mode", + "end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device.mac_settings.desired_relay.mode.serving", + "end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.desired_rx1_data_rate_offset", "end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device.mac_settings.desired_rx1_delay", @@ -129,6 +165,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_settings.ping_slot_frequency.value", "end_device.mac_settings.ping_slot_periodicity", "end_device.mac_settings.ping_slot_periodicity.value", + "end_device.mac_settings.relay", + "end_device.mac_settings.relay.mode", + "end_device.mac_settings.relay.mode.served", + "end_device.mac_settings.relay.mode.served.backoff", + "end_device.mac_settings.relay.mode.served.mode", + "end_device.mac_settings.relay.mode.served.mode.always", + "end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device.mac_settings.relay.mode.served.second_channel", + "end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device.mac_settings.relay.mode.serving", + "end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device.mac_settings.relay.mode.serving.limits", + "end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_settings.relay.mode.serving.second_channel", + "end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_settings.resets_f_cnt", "end_device.mac_settings.resets_f_cnt.value", "end_device.mac_settings.rx1_data_rate_offset", @@ -172,6 +244,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_state.current_parameters.ping_slot_frequency", "end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device.mac_state.current_parameters.relay", + "end_device.mac_state.current_parameters.relay.mode", + "end_device.mac_state.current_parameters.relay.mode.served", + "end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.current_parameters.relay.mode.serving", + "end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device.mac_state.current_parameters.rx1_delay", "end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -200,6 +308,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.mac_state.desired_parameters.relay", + "end_device.mac_state.desired_parameters.relay.mode", + "end_device.mac_state.desired_parameters.relay.mode.served", + "end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device.mac_state.desired_parameters.rx1_delay", "end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -239,6 +383,8 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.mac_state.pending_join_request.rx_delay", + "end_device.mac_state.pending_relay_downlink", + "end_device.mac_state.pending_relay_downlink.raw_payload", "end_device.mac_state.pending_requests", "end_device.mac_state.ping_slot_periodicity", "end_device.mac_state.ping_slot_periodicity.value", @@ -314,6 +460,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.current_parameters.relay", + "end_device.pending_mac_state.current_parameters.relay.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.current_parameters.rx1_delay", "end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -342,6 +524,42 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device.pending_mac_state.desired_parameters.relay", + "end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -381,6 +599,8 @@ var GenerateEndDeviceQRCodeRequestFieldPathsNested = []string{ "end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device.pending_mac_state.pending_relay_downlink", + "end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device.pending_mac_state.pending_requests", "end_device.pending_mac_state.ping_slot_periodicity", "end_device.pending_mac_state.ping_slot_periodicity.value", @@ -629,6 +849,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_settings.desired_ping_slot_data_rate_index.value", "end_device_template.end_device.mac_settings.desired_ping_slot_frequency", "end_device_template.end_device.mac_settings.desired_ping_slot_frequency.value", + "end_device_template.end_device.mac_settings.desired_relay", + "end_device_template.end_device.mac_settings.desired_relay.mode", + "end_device_template.end_device.mac_settings.desired_relay.mode.served", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.backoff", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.mode", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.mode.always", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.mode.dynamic", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.second_channel", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.second_channel.frequency", + "end_device_template.end_device.mac_settings.desired_relay.mode.served.serving_device_id", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.cad_periodicity", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.default_channel_index", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.join_requests", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.notifications", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.overall", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.second_channel", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.mac_settings.desired_relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.mac_settings.desired_rx1_data_rate_offset", "end_device_template.end_device.mac_settings.desired_rx1_data_rate_offset.value", "end_device_template.end_device.mac_settings.desired_rx1_delay", @@ -648,6 +904,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_settings.ping_slot_frequency.value", "end_device_template.end_device.mac_settings.ping_slot_periodicity", "end_device_template.end_device.mac_settings.ping_slot_periodicity.value", + "end_device_template.end_device.mac_settings.relay", + "end_device_template.end_device.mac_settings.relay.mode", + "end_device_template.end_device.mac_settings.relay.mode.served", + "end_device_template.end_device.mac_settings.relay.mode.served.backoff", + "end_device_template.end_device.mac_settings.relay.mode.served.mode", + "end_device_template.end_device.mac_settings.relay.mode.served.mode.always", + "end_device_template.end_device.mac_settings.relay.mode.served.mode.dynamic", + "end_device_template.end_device.mac_settings.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.mac_settings.relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.mac_settings.relay.mode.served.second_channel", + "end_device_template.end_device.mac_settings.relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.mac_settings.relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.mac_settings.relay.mode.served.second_channel.frequency", + "end_device_template.end_device.mac_settings.relay.mode.served.serving_device_id", + "end_device_template.end_device.mac_settings.relay.mode.serving", + "end_device_template.end_device.mac_settings.relay.mode.serving.cad_periodicity", + "end_device_template.end_device.mac_settings.relay.mode.serving.default_channel_index", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.join_requests", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.notifications", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.overall", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.mac_settings.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.mac_settings.relay.mode.serving.second_channel", + "end_device_template.end_device.mac_settings.relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.mac_settings.relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.mac_settings.relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.mac_settings.relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.mac_settings.resets_f_cnt", "end_device_template.end_device.mac_settings.resets_f_cnt.value", "end_device_template.end_device.mac_settings.rx1_data_rate_offset", @@ -691,6 +983,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_state.current_parameters.ping_slot_frequency", "end_device_template.end_device.mac_state.current_parameters.rejoin_count_periodicity", "end_device_template.end_device.mac_state.current_parameters.rejoin_time_periodicity", + "end_device_template.end_device.mac_state.current_parameters.relay", + "end_device_template.end_device.mac_state.current_parameters.relay.mode", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.backoff", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.mode", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.mode.always", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.second_channel", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.mac_state.current_parameters.rx1_data_rate_offset", "end_device_template.end_device.mac_state.current_parameters.rx1_delay", "end_device_template.end_device.mac_state.current_parameters.rx2_data_rate_index", @@ -719,6 +1047,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_state.desired_parameters.ping_slot_frequency", "end_device_template.end_device.mac_state.desired_parameters.rejoin_count_periodicity", "end_device_template.end_device.mac_state.desired_parameters.rejoin_time_periodicity", + "end_device_template.end_device.mac_state.desired_parameters.relay", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.backoff", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.mode", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.mac_state.desired_parameters.rx1_data_rate_offset", "end_device_template.end_device.mac_state.desired_parameters.rx1_delay", "end_device_template.end_device.mac_state.desired_parameters.rx2_data_rate_index", @@ -758,6 +1122,8 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device_template.end_device.mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device_template.end_device.mac_state.pending_join_request.rx_delay", + "end_device_template.end_device.mac_state.pending_relay_downlink", + "end_device_template.end_device.mac_state.pending_relay_downlink.raw_payload", "end_device_template.end_device.mac_state.pending_requests", "end_device_template.end_device.mac_state.ping_slot_periodicity", "end_device_template.end_device.mac_state.ping_slot_periodicity.value", @@ -833,6 +1199,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.pending_mac_state.current_parameters.ping_slot_frequency", "end_device_template.end_device.pending_mac_state.current_parameters.rejoin_count_periodicity", "end_device_template.end_device.pending_mac_state.current_parameters.rejoin_time_periodicity", + "end_device_template.end_device.pending_mac_state.current_parameters.relay", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.backoff", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.mode", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.mode.always", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.second_channel.frequency", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.served.serving_device_id", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.cad_periodicity", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.default_channel_index", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.pending_mac_state.current_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.pending_mac_state.current_parameters.rx1_data_rate_offset", "end_device_template.end_device.pending_mac_state.current_parameters.rx1_delay", "end_device_template.end_device.pending_mac_state.current_parameters.rx2_data_rate_index", @@ -861,6 +1263,42 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.pending_mac_state.desired_parameters.ping_slot_frequency", "end_device_template.end_device.pending_mac_state.desired_parameters.rejoin_count_periodicity", "end_device_template.end_device.pending_mac_state.desired_parameters.rejoin_time_periodicity", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.backoff", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.mode", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.always", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.dynamic.smart_enable_level", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.mode.end_device_controlled", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.ack_offset", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.data_rate_index", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.second_channel.frequency", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.served.serving_device_id", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.cad_periodicity", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.default_channel_index", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.bucket_size", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.join_requests.reload_rate", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.bucket_size", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.notifications.reload_rate", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.bucket_size", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.overall.reload_rate", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.reset_behavior", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.bucket_size", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.limits.uplink_messages.reload_rate", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.ack_offset", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.data_rate_index", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.second_channel.frequency", + "end_device_template.end_device.pending_mac_state.desired_parameters.relay.mode.serving.uplink_forwarding_rules", "end_device_template.end_device.pending_mac_state.desired_parameters.rx1_data_rate_offset", "end_device_template.end_device.pending_mac_state.desired_parameters.rx1_delay", "end_device_template.end_device.pending_mac_state.desired_parameters.rx2_data_rate_index", @@ -900,6 +1338,8 @@ var ParseEndDeviceQRCodeResponseFieldPathsNested = []string{ "end_device_template.end_device.pending_mac_state.pending_join_request.downlink_settings.rx1_dr_offset", "end_device_template.end_device.pending_mac_state.pending_join_request.downlink_settings.rx2_dr", "end_device_template.end_device.pending_mac_state.pending_join_request.rx_delay", + "end_device_template.end_device.pending_mac_state.pending_relay_downlink", + "end_device_template.end_device.pending_mac_state.pending_relay_downlink.raw_payload", "end_device_template.end_device.pending_mac_state.pending_requests", "end_device_template.end_device.pending_mac_state.ping_slot_periodicity", "end_device_template.end_device.pending_mac_state.ping_slot_periodicity.value", diff --git a/pkg/ttnpb/testdata/ttnpb_encoding_golden.md b/pkg/ttnpb/testdata/ttnpb_encoding_golden.md index e87dac40fa..4bb15def24 100644 --- a/pkg/ttnpb/testdata/ttnpb_encoding_golden.md +++ b/pkg/ttnpb/testdata/ttnpb_encoding_golden.md @@ -201,6 +201,13 @@ Binary | ttnpb.MACCommandIdentifier | CID_PING_SLOT_CHANNEL | [17] Binary | ttnpb.MACCommandIdentifier | CID_PING_SLOT_INFO | [16] Binary | ttnpb.MACCommandIdentifier | CID_REJOIN_PARAM_SETUP | [15] Binary | ttnpb.MACCommandIdentifier | CID_REKEY | [11] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_CONF | [64] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_CONFIGURE_FWD_LIMIT | [69] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_CTRL_UPLINK_LIST | [68] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_END_DEVICE_CONF | [65] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_FILTER_LIST | [66] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_NOTIFY_NEW_END_DEVICE | [70] +Binary | ttnpb.MACCommandIdentifier | CID_RELAY_UPDATE_UPLINK_LIST | [67] Binary | ttnpb.MACCommandIdentifier | CID_RESET | [1] Binary | ttnpb.MACCommandIdentifier | CID_RFU_0 | [0] Binary | ttnpb.MACCommandIdentifier | CID_RX_PARAM_SETUP | [5] @@ -570,6 +577,13 @@ JSON | ttnpb.MACCommandIdentifier | CID_PING_SLOT_CHANNEL | "CID_PING_SLOT_CHANN JSON | ttnpb.MACCommandIdentifier | CID_PING_SLOT_INFO | "CID_PING_SLOT_INFO" JSON | ttnpb.MACCommandIdentifier | CID_REJOIN_PARAM_SETUP | "CID_REJOIN_PARAM_SETUP" JSON | ttnpb.MACCommandIdentifier | CID_REKEY | "CID_REKEY" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_CONF | "CID_RELAY_CONF" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_CONFIGURE_FWD_LIMIT | "CID_RELAY_CONFIGURE_FWD_LIMIT" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_CTRL_UPLINK_LIST | "CID_RELAY_CTRL_UPLINK_LIST" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_END_DEVICE_CONF | "CID_RELAY_END_DEVICE_CONF" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_FILTER_LIST | "CID_RELAY_FILTER_LIST" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_NOTIFY_NEW_END_DEVICE | "CID_RELAY_NOTIFY_NEW_END_DEVICE" +JSON | ttnpb.MACCommandIdentifier | CID_RELAY_UPDATE_UPLINK_LIST | "CID_RELAY_UPDATE_UPLINK_LIST" JSON | ttnpb.MACCommandIdentifier | CID_RESET | "CID_RESET" JSON | ttnpb.MACCommandIdentifier | CID_RFU_0 | "CID_RFU_0" JSON | ttnpb.MACCommandIdentifier | CID_RX_PARAM_SETUP | "CID_RX_PARAM_SETUP" @@ -1012,6 +1026,13 @@ ProtoJSON | ttnpb.MACCommandIdentifier | CID_PING_SLOT_CHANNEL | "CID_PING_SLOT_ ProtoJSON | ttnpb.MACCommandIdentifier | CID_PING_SLOT_INFO | "CID_PING_SLOT_INFO" ProtoJSON | ttnpb.MACCommandIdentifier | CID_REJOIN_PARAM_SETUP | "CID_REJOIN_PARAM_SETUP" ProtoJSON | ttnpb.MACCommandIdentifier | CID_REKEY | "CID_REKEY" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_CONF | "CID_RELAY_CONF" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_CONFIGURE_FWD_LIMIT | "CID_RELAY_CONFIGURE_FWD_LIMIT" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_CTRL_UPLINK_LIST | "CID_RELAY_CTRL_UPLINK_LIST" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_END_DEVICE_CONF | "CID_RELAY_END_DEVICE_CONF" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_FILTER_LIST | "CID_RELAY_FILTER_LIST" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_NOTIFY_NEW_END_DEVICE | "CID_RELAY_NOTIFY_NEW_END_DEVICE" +ProtoJSON | ttnpb.MACCommandIdentifier | CID_RELAY_UPDATE_UPLINK_LIST | "CID_RELAY_UPDATE_UPLINK_LIST" ProtoJSON | ttnpb.MACCommandIdentifier | CID_RESET | "CID_RESET" ProtoJSON | ttnpb.MACCommandIdentifier | CID_RFU_0 | "CID_RFU_0" ProtoJSON | ttnpb.MACCommandIdentifier | CID_RX_PARAM_SETUP | "CID_RX_PARAM_SETUP" @@ -1454,6 +1475,13 @@ Text | ttnpb.MACCommandIdentifier | CID_PING_SLOT_CHANNEL | CID_PING_SLOT_CHANNE Text | ttnpb.MACCommandIdentifier | CID_PING_SLOT_INFO | CID_PING_SLOT_INFO Text | ttnpb.MACCommandIdentifier | CID_REJOIN_PARAM_SETUP | CID_REJOIN_PARAM_SETUP Text | ttnpb.MACCommandIdentifier | CID_REKEY | CID_REKEY +Text | ttnpb.MACCommandIdentifier | CID_RELAY_CONF | CID_RELAY_CONF +Text | ttnpb.MACCommandIdentifier | CID_RELAY_CONFIGURE_FWD_LIMIT | CID_RELAY_CONFIGURE_FWD_LIMIT +Text | ttnpb.MACCommandIdentifier | CID_RELAY_CTRL_UPLINK_LIST | CID_RELAY_CTRL_UPLINK_LIST +Text | ttnpb.MACCommandIdentifier | CID_RELAY_END_DEVICE_CONF | CID_RELAY_END_DEVICE_CONF +Text | ttnpb.MACCommandIdentifier | CID_RELAY_FILTER_LIST | CID_RELAY_FILTER_LIST +Text | ttnpb.MACCommandIdentifier | CID_RELAY_NOTIFY_NEW_END_DEVICE | CID_RELAY_NOTIFY_NEW_END_DEVICE +Text | ttnpb.MACCommandIdentifier | CID_RELAY_UPDATE_UPLINK_LIST | CID_RELAY_UPDATE_UPLINK_LIST Text | ttnpb.MACCommandIdentifier | CID_RESET | CID_RESET Text | ttnpb.MACCommandIdentifier | CID_RFU_0 | CID_RFU_0 Text | ttnpb.MACCommandIdentifier | CID_RX_PARAM_SETUP | CID_RX_PARAM_SETUP diff --git a/pkg/ttnpb/zero_test.go b/pkg/ttnpb/zero_test.go index efda844672..f4958d041e 100644 --- a/pkg/ttnpb/zero_test.go +++ b/pkg/ttnpb/zero_test.go @@ -107,6 +107,20 @@ func TestFieldIsZero(t *testing.T) { (*SetEndDeviceRequest)(nil): EndDeviceFieldPathsNested, &UpdateEndDeviceRequest{}: EndDeviceFieldPathsNested, (*UpdateEndDeviceRequest)(nil): EndDeviceFieldPathsNested, + &RelayParameters{}: RelayParametersFieldPathsNested, + (*RelayParameters)(nil): RelayParametersFieldPathsNested, + &ServedRelayParameters{}: ServedRelayParametersFieldPathsNested, + (*ServedRelayParameters)(nil): ServedRelayParametersFieldPathsNested, + &ServingRelayParameters{}: ServingRelayParametersFieldPathsNested, + (*ServingRelayParameters)(nil): ServingRelayParametersFieldPathsNested, + &RelaySecondChannel{}: RelaySecondChannelFieldPathsNested, + (*RelaySecondChannel)(nil): RelaySecondChannelFieldPathsNested, + &RelayEndDeviceDynamicMode{}: RelayEndDeviceDynamicModeFieldPathsNested, + (*RelayEndDeviceDynamicMode)(nil): RelayEndDeviceDynamicModeFieldPathsNested, + &RelayForwardLimits{}: RelayForwardLimitsFieldPathsNested, + (*RelayForwardLimits)(nil): RelayForwardLimitsFieldPathsNested, + &ServingRelayForwardingLimits{}: ServingRelayForwardingLimitsFieldPathsNested, + (*ServingRelayForwardingLimits)(nil): ServingRelayForwardingLimitsFieldPathsNested, } { for _, p := range paths { v, p := v, p diff --git a/pkg/util/test/constructors_generated.go b/pkg/util/test/constructors_generated.go index 7403d703ac..abb8efc41a 100644 --- a/pkg/util/test/constructors_generated.go +++ b/pkg/util/test/constructors_generated.go @@ -483,6 +483,15 @@ func (MACStateOptionNamespace) WithRecentMacCommandIdentifiers(vs ...ttnpb.MACCo } } +// WithPendingRelayDownlink returns a MACStateOption, which returns a copy of ttnpb.MACState with PendingRelayDownlink set to v. +func (MACStateOptionNamespace) WithPendingRelayDownlink(v *ttnpb.RelayForwardDownlinkReq) MACStateOption { + return func(x *ttnpb.MACState) *ttnpb.MACState { + copy := ttnpb.Clone(x) + copy.PendingRelayDownlink = v + return copy + } +} + // Compose returns a functional composition of opts as a singular MACStateOption. func (MACStateOptionNamespace) Compose(opts ...MACStateOption) MACStateOption { return func(x *ttnpb.MACState) *ttnpb.MACState { diff --git a/pkg/version/ttn.go b/pkg/version/ttn.go index 2fa9d9073f..87ae965713 100644 --- a/pkg/version/ttn.go +++ b/pkg/version/ttn.go @@ -3,4 +3,4 @@ package version // TTN Version -var TTN = "3.27.2-dev" +var TTN = "3.28.1-dev" diff --git a/pkg/web/web.go b/pkg/web/web.go index ad2725d268..a5c1f0c270 100644 --- a/pkg/web/web.go +++ b/pkg/web/web.go @@ -27,8 +27,10 @@ import ( "github.com/gorilla/csrf" "github.com/gorilla/mux" + "github.com/klauspost/compress/gzhttp" "go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux" "go.thethings.network/lorawan-stack/v3/pkg/errors" + "go.thethings.network/lorawan-stack/v3/pkg/experimental" "go.thethings.network/lorawan-stack/v3/pkg/fillcontext" "go.thethings.network/lorawan-stack/v3/pkg/log" "go.thethings.network/lorawan-stack/v3/pkg/random" @@ -39,6 +41,19 @@ import ( "gopkg.in/yaml.v2" ) +var responseCompressionFeatureFlag = experimental.DefineFeature("http.server.transport.compression", true) + +func compressionMiddleware(ctx context.Context) (func(http.Handler) http.Handler, error) { + if !responseCompressionFeatureFlag.GetValue(ctx) { + return func(next http.Handler) http.Handler { return next }, nil + } + m, err := gzhttp.NewWrapper() + if err != nil { + return nil, err + } + return func(h http.Handler) http.Handler { return m(h) }, nil +} + // Registerer allows components to register their services to the web server. type Registerer interface { RegisterRoutes(s *Server) @@ -171,7 +186,13 @@ func New(ctx context.Context, opts ...Option) (*Server, error) { } var proxyConfiguration webmiddleware.ProxyConfiguration - proxyConfiguration.ParseAndAddTrusted(options.trustedProxies...) + if err := proxyConfiguration.ParseAndAddTrusted(options.trustedProxies...); err != nil { + return nil, err + } + compressor, err := compressionMiddleware(ctx) + if err != nil { + return nil, err + } root := mux.NewRouter() root.NotFoundHandler = http.HandlerFunc(webhandlers.NotFound) root.Use( @@ -179,6 +200,7 @@ func New(ctx context.Context, opts ...Option) (*Server, error) { "text/html": webhandlers.Template, }), mux.MiddlewareFunc(webmiddleware.Recover()), + compressor, otelmux.Middleware("ttn-lw-stack", otelmux.WithTracerProvider(tracing.FromContext(ctx))), mux.MiddlewareFunc(webmiddleware.FillContext(options.contextFillers...)), mux.MiddlewareFunc(webmiddleware.Peer()), diff --git a/pkg/webui/account/components/oauth-client-form/messages.js b/pkg/webui/account/components/oauth-client-form/messages.js index 2b204a8fb7..bfbc36f2e7 100644 --- a/pkg/webui/account/components/oauth-client-form/messages.js +++ b/pkg/webui/account/components/oauth-client-form/messages.js @@ -21,7 +21,6 @@ export default defineMessages({ clientDescDescription: 'The description is displayed to the user when authorizing the client. Use it to explain the purpose of your client.', createClient: 'Create OAuth client', - deleteTitle: 'Are you sure you want to delete this account?', deleteWarning: 'This will PERMANENTLY DELETE THIS OAUTH CLIENT and LOCK THE OAUTH ID. Make sure you assign new collaborators to such entities if you plan to continue using them.', purgeWarning: @@ -41,9 +40,7 @@ export default defineMessages({ 'If set, the authorization page will visually indicate endorsement to improve trust', grants: 'Grant types', grantsDesc: 'OAuth flows that can be used for the client to get a token', - grantAuthorizationLabel: 'Authorization code', grantRefreshTokenLabel: 'Refresh token', - grantPasswordLabel: 'Password', deleteClient: 'Delete OAuth client', urlsPlaceholder: 'https://example.com/oauth/callback', rightsWarning: diff --git a/pkg/webui/account/containers/authorizations-table/index.js b/pkg/webui/account/containers/authorizations-table/index.js index f7ac141a72..6f9fad7007 100644 --- a/pkg/webui/account/containers/authorizations-table/index.js +++ b/pkg/webui/account/containers/authorizations-table/index.js @@ -14,7 +14,6 @@ import React from 'react' import { useSelector } from 'react-redux' -import { defineMessages } from 'react-intl' import { createSelector } from 'reselect' import FetchTable from '@ttn-lw/containers/fetch-table' @@ -32,11 +31,6 @@ import { } from '@account/store/selectors/authorizations' import { selectUserId } from '@account/store/selectors/user' -const m = defineMessages({ - clientId: 'Client ID', - tableTitle: 'OAuth client authorizations', -}) - const getItemPathPrefix = item => `${item.client_ids.client_id}` const OAuthClientAuthorizationsTable = () => { @@ -46,7 +40,7 @@ const OAuthClientAuthorizationsTable = () => { const baseHeaders = [ { name: 'client_ids.client_id', - displayName: m.clientId, + displayName: sharedMessages.clientId, width: 20, }, { @@ -84,7 +78,7 @@ const OAuthClientAuthorizationsTable = () => { getItemsAction={getItems} baseDataSelector={baseDataSelector} getItemPathPrefix={getItemPathPrefix} - tableTitle={} + tableTitle={} clickable /> ) diff --git a/pkg/webui/account/containers/clients-table/index.js b/pkg/webui/account/containers/clients-table/index.js index fefbb8dd9f..36d2c5f33c 100644 --- a/pkg/webui/account/containers/clients-table/index.js +++ b/pkg/webui/account/containers/clients-table/index.js @@ -44,7 +44,6 @@ const m = defineMessages({ restoreFail: 'There was an error and OAuth client could not be restored', purgeSuccess: 'OAuth client purged', purgeFail: 'There was an error and the OAuth client could not be purged', - addClient: 'Add OAuth client', }) const OWNED_TAB = 'owned' @@ -200,7 +199,7 @@ const ClientsTable = () => { { @@ -87,7 +84,7 @@ const CollaboratorsTable = props => { const baseHeaders = [ { name: 'ids', - displayName: m.id, + displayName: sharedMessages.userOrgId, render: ids => { const isUser = 'user_ids' in ids const collaboratorId = getCollaboratorId({ ids }) @@ -144,7 +141,7 @@ const CollaboratorsTable = props => {

- + { diff --git a/pkg/webui/account/views/front-not-found/index.js b/pkg/webui/account/views/front-not-found/index.js index 9b74065e81..1b8c107afa 100644 --- a/pkg/webui/account/views/front-not-found/index.js +++ b/pkg/webui/account/views/front-not-found/index.js @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -13,7 +13,6 @@ // limitations under the License. import React from 'react' -import { defineMessages } from 'react-intl' import Button from '@ttn-lw/components/button' @@ -25,10 +24,7 @@ import style from '@account/views/front/front.styl' import { selectApplicationSiteName, selectApplicationSiteTitle } from '@ttn-lw/lib/selectors/env' import errorMessages from '@ttn-lw/lib/errors/error-messages' import statusCodeMessages from '@ttn-lw/lib/errors/status-code-messages' - -const m = defineMessages({ - backToAccount: 'Back to {siteTitle}', -}) +import sharedMessages from '@ttn-lw/lib/shared-messages' const siteName = selectApplicationSiteName() const siteTitle = selectApplicationSiteTitle() @@ -51,7 +47,7 @@ const FrontNotFound = () => ( diff --git a/pkg/webui/account/views/login/index.js b/pkg/webui/account/views/login/index.js index fdddbed39d..cfc7d379bb 100644 --- a/pkg/webui/account/views/login/index.js +++ b/pkg/webui/account/views/login/index.js @@ -44,8 +44,6 @@ const m = defineMessages({ createAccount: 'Create an account', forgotPassword: 'Forgot password?', loginToContinue: 'Please login to continue', - loginFailed: 'Login failed', - accountDeleted: 'Account deleted', }) const appRoot = selectApplicationRootPath() @@ -114,7 +112,7 @@ const Login = () => { } else if (!next || (next !== appRoot && !Boolean(error))) { info = m.loginToContinue } else if ('account-deleted' in Query.parse(location.search)) { - info = m.accountDeleted + info = sharedMessages.accountDeleted } return ( @@ -130,7 +128,7 @@ const Login = () => { onSubmit={handleSubmit} initialValues={initialValues} error={error} - errorTitle={m.loginFailed} + errorTitle={sharedMessages.loginFailed} info={info} validationSchema={validationSchema} horizontal={false} diff --git a/pkg/webui/account/views/oauth-client-add/index.js b/pkg/webui/account/views/oauth-client-add/index.js index 33423c5758..1c2cf01027 100644 --- a/pkg/webui/account/views/oauth-client-add/index.js +++ b/pkg/webui/account/views/oauth-client-add/index.js @@ -15,7 +15,6 @@ import React from 'react' import { useSelector } from 'react-redux' import { Container, Col, Row } from 'react-grid-system' -import { defineMessages } from 'react-intl' import PageTitle from '@ttn-lw/components/page-title' @@ -23,6 +22,8 @@ import RequireRequest from '@ttn-lw/lib/components/require-request' import ClientAdd from '@account/containers/oauth-client-add' +import sharedMessages from '@ttn-lw/lib/shared-messages' + import { getUserRights } from '@account/store/actions/user' import { @@ -32,10 +33,6 @@ import { selectUserPseudoRights, } from '@account/store/selectors/user' -const m = defineMessages({ - addClient: 'Add OAuth client', -}) - const OAuthClientAddInner = () => { const userId = useSelector(selectUserId) const isAdmin = useSelector(selectUserIsAdmin) @@ -44,7 +41,7 @@ const OAuthClientAddInner = () => { return ( - + { > - + diff --git a/pkg/webui/account/views/token-login/index.js b/pkg/webui/account/views/token-login/index.js index 3a502a8a6e..fab8cb9dbc 100644 --- a/pkg/webui/account/views/token-login/index.js +++ b/pkg/webui/account/views/token-login/index.js @@ -37,7 +37,6 @@ import sharedMessages from '@ttn-lw/lib/shared-messages' const m = defineMessages({ loginToken: 'Login Token', - loginFailed: 'Login failed', }) const appRoot = selectApplicationRootPath() @@ -97,7 +96,7 @@ const TokenLogin = () => { onSubmit={handleSubmit} initialValues={initialValues} error={error} - errorTitle={m.loginFailed} + errorTitle={sharedMessages.loginFailed} validationSchema={validationSchema} horizontal={false} > diff --git a/pkg/webui/components/breadcrumbs/context.js b/pkg/webui/components/breadcrumbs/context.js index 6adf8c6770..ba6e6334a2 100644 --- a/pkg/webui/components/breadcrumbs/context.js +++ b/pkg/webui/components/breadcrumbs/context.js @@ -1,4 +1,4 @@ -// Copyright © 2019 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,114 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useContext, useEffect } from 'react' -import bind from 'autobind-decorator' +import React, { useContext, useEffect, useState } from 'react' import PropTypes from '@ttn-lw/lib/prop-types' const BreadcrumbsContext = React.createContext() const { Provider, Consumer } = BreadcrumbsContext -class BreadcrumbsProvider extends React.Component { - static propTypes = { - children: PropTypes.node.isRequired, - } - - state = { - breadcrumbs: [], - } +const BreadcrumbsProvider = ({ children }) => { + const [breadcrumbs, setBreadcrumbs] = useState([]) - @bind - add(id, breadcrumb) { - this.setState(prev => { - const index = prev.breadcrumbs.findIndex(({ id: breadcrumbId }) => breadcrumbId === id) + const add = (id, breadcrumb) => { + setBreadcrumbs(prev => { + const index = prev.findIndex(({ id: breadcrumbId }) => breadcrumbId === id) if (index === -1) { - return { - breadcrumbs: [...prev.breadcrumbs, { id, breadcrumb }].sort((a, b) => - a.id < b.id ? -1 : 1, - ), - } + return [...prev, { id, breadcrumb }].sort((a, b) => (a.id < b.id ? -1 : 1)) } // Replace breadcrumb with existing id. - return { - breadcrumbs: [ - ...prev.breadcrumbs.slice(0, index), - { id, breadcrumb }, - ...prev.breadcrumbs.slice(index + 1), - ], - } + return [...prev.slice(0, index), { id, breadcrumb }, ...prev.slice(index + 1)] }) } - @bind - remove(id) { - this.setState(prev => ({ - breadcrumbs: prev.breadcrumbs.filter(b => b.id !== id), - })) + const remove = id => { + setBreadcrumbs(prev => prev.filter(b => b.id !== id)) } - render() { - const { children } = this.props - const value = { - add: this.add, - remove: this.remove, - breadcrumbs: this.state.breadcrumbs.map(b => b.breadcrumb), - } - - return {children} + const value = { + add, + remove, + breadcrumbs: breadcrumbs.map(b => b.breadcrumb), } -} -const withBreadcrumb = (id, element) => Component => { - class BreadcrumbsConsumer extends React.Component { - static propTypes = { - add: PropTypes.func.isRequired, - breadcrumb: PropTypes.oneOfType([PropTypes.func, PropTypes.element]).isRequired, - remove: PropTypes.func.isRequired, - } - - constructor(props) { - super(props) - - this.add() - } - - add() { - const { add, breadcrumb } = this.props - - add(id, breadcrumb) - } - - remove() { - const { remove } = this.props - - remove(id) - } - - componentWillUnmount() { - this.remove() - } - - render() { - const { add, remove, breadcrumb, ...rest } = this.props - - return - } - } - - const BreadcrumbsConsumerContainer = props => ( - - {({ add, remove }) => ( - - )} - - ) - - return BreadcrumbsConsumerContainer + return {children} } -withBreadcrumb.displayName = 'withBreadcrumb' +BreadcrumbsProvider.propTypes = { + children: PropTypes.node.isRequired, +} const useBreadcrumbs = (id, element) => { const context = useContext(BreadcrumbsContext) @@ -133,10 +63,4 @@ const useBreadcrumbs = (id, element) => { }, []) } -export { - Consumer as BreadcrumbsConsumer, - BreadcrumbsProvider, - withBreadcrumb, - BreadcrumbsContext, - useBreadcrumbs, -} +export { Consumer as BreadcrumbsConsumer, BreadcrumbsProvider, BreadcrumbsContext, useBreadcrumbs } diff --git a/pkg/webui/components/checkbox/checkbox.js b/pkg/webui/components/checkbox/checkbox.js index a83adf674d..488322e92d 100644 --- a/pkg/webui/components/checkbox/checkbox.js +++ b/pkg/webui/components/checkbox/checkbox.js @@ -60,7 +60,7 @@ const Checkbox = props => { event => { const { checked } = event.target - if (hasValue && !context) { + if (!hasValue && !context) { setChecked(checked) } diff --git a/pkg/webui/components/checkbox/group/index.js b/pkg/webui/components/checkbox/group/index.js index 1cd09a084f..25b63e36da 100644 --- a/pkg/webui/components/checkbox/group/index.js +++ b/pkg/webui/components/checkbox/group/index.js @@ -22,9 +22,25 @@ import style from './group.styl' export const CheckboxGroupContext = React.createContext() const CheckboxGroup = props => { - const { children, className, horizontal, onChange, disabled, onFocus, onBlur, ...rest } = props - const hasValue = 'value' in rest - const [value, setValue] = React.useState(hasValue ? rest.value : rest.initialValue || {}) + const { + children, + className, + horizontal, + onChange, + disabled, + onFocus, + onBlur, + value: valueProp, + ...rest + } = props + const hasValue = Boolean(valueProp) + const [value, setValue] = React.useState(hasValue ? valueProp : rest.initialValue || {}) + + React.useEffect(() => { + if (valueProp) { + setValue(valueProp || {}) + } + }, [valueProp]) const handleCheckboxChange = useCallback( async event => { diff --git a/pkg/webui/components/file-input/index.js b/pkg/webui/components/file-input/index.js index e071ec82c7..9978046666 100644 --- a/pkg/webui/components/file-input/index.js +++ b/pkg/webui/components/file-input/index.js @@ -35,7 +35,6 @@ const m = defineMessages({ noFileSelected: 'No file selected', fileProvided: 'A file has been provided', tooBig: 'The selected file is too large', - remove: 'Remove', }) const defaultDataTransform = content => content.replace(/^.*;base64,/, '') diff --git a/pkg/webui/components/form/field/index.js b/pkg/webui/components/form/field/index.js index cef8c33795..46b5764992 100644 --- a/pkg/webui/components/form/field/index.js +++ b/pkg/webui/components/form/field/index.js @@ -192,7 +192,7 @@ const FormField = props => { const hasTooltip = Boolean(tooltipId) const hasTitle = Boolean(title) const showError = touched && !isEmpty(errors) - const showWarning = isEmpty(errors) && Boolean(warning) + const showWarning = !showError && Boolean(warning) const error = showError && errors[0] const showDescription = !showError && !showWarning && Boolean(description) const tooltipIcon = hasTooltip ? : null diff --git a/pkg/webui/components/form/field/stories/shared.js b/pkg/webui/components/form/field/stories/shared.js index f9f5f71fc7..56c98c0b1c 100644 --- a/pkg/webui/components/form/field/stories/shared.js +++ b/pkg/webui/components/form/field/stories/shared.js @@ -1,4 +1,4 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,12 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -/* eslint-disable react/prop-types */ - -import React from 'react' +import React, { useEffect, useRef } from 'react' import { action } from '@storybook/addon-actions' import Yup from '@ttn-lw/lib/yup' +import PropTypes from '@ttn-lw/lib/prop-types' import Form from '../..' @@ -38,28 +37,31 @@ const validationSchema = Yup.object().shape({ error: errorSchema, }) -class FieldsWrapperExample extends React.Component { - form = React.createRef() - - componentDidMount() { - if (this.form.current) { - this.form.current.setFieldError('error', 'Something went wrong.') - this.form.current.setFieldTouched('error') +const FieldsWrapperExample = props => { + const formRef = useRef(null) + const { initialValues, children } = props + useEffect(() => { + if (formRef.current) { + formRef.current.setFieldError('error', 'Something went wrong.') + formRef.current.setFieldTouched('error') } - } + }, []) + + return ( +
+ {children} + + ) +} - render() { - return ( -
- {this.props.children} - - ) - } +FieldsWrapperExample.propTypes = { + children: PropTypes.node.isRequired, + initialValues: PropTypes.shape({}).isRequired, } export { info, FieldsWrapperExample } diff --git a/pkg/webui/components/input/byte.js b/pkg/webui/components/input/byte.js index 3f0a0c2129..0cf440b053 100644 --- a/pkg/webui/components/input/byte.js +++ b/pkg/webui/components/input/byte.js @@ -55,139 +55,134 @@ const upper = str => str.toUpperCase() const clean = str => (typeof str === 'string' ? str.replace(voidChars, '') : str) -const ByteInput = ({ - onBlur, - value, - className, - min, - max, - onChange, - placeholder, - showPerChar, - unbounded, - ...rest -}) => { - const onCopy = useCallback(evt => { - const input = evt.target - const selectedValue = input.value.substr( - input.selectionStart, - input.selectionEnd - input.selectionStart, - ) - evt.clipboardData.setData('text/plain', clean(selectedValue)) - evt.preventDefault() - }, []) - - const onPaste = useCallback( - evt => { - // Ignore empty pastes. - if (evt?.clipboardData?.getData('text/plain')?.length === 0) { - return - } - const val = evt.target.value - const cleanedSelection = clean( - val.substr( - evt.target.selectionStart, - Math.max(1, evt.target.selectionEnd - evt.target.selectionStart), - ), +const ByteInput = React.forwardRef( + ( + { onBlur, value, className, min, max, onChange, placeholder, showPerChar, unbounded, ...rest }, + ref, + ) => { + const onCopy = useCallback(evt => { + const input = evt.target + const selectedValue = input.value.substr( + input.selectionStart, + input.selectionEnd - input.selectionStart, ) + evt.clipboardData.setData('text/plain', clean(selectedValue)) + evt.preventDefault() + }, []) + + const onPaste = useCallback( + evt => { + // Ignore empty pastes. + if (evt?.clipboardData?.getData('text/plain')?.length === 0) { + return + } + const val = evt.target.value + const cleanedSelection = clean( + val.substr( + evt.target.selectionStart, + Math.max(1, evt.target.selectionEnd - evt.target.selectionStart), + ), + ) + + // To avoid the masked input from cutting off characters when the cursor + // is placed in the mask placeholders, the placeholder chars are removed before + // the paste is applied, unless the user made a selection to paste into. + // This will ensure a consistent pasting experience. + if (!unbounded && cleanedSelection === '') { + evt.target.value = val.replace(voidChars, '') + } + }, + [unbounded], + ) - // To avoid the masked input from cutting off characters when the cursor - // is placed in the mask placeholders, the placeholder chars are removed before - // the paste is applied, unless the user made a selection to paste into. - // This will ensure a consistent pasting experience. - if (!unbounded && cleanedSelection === '') { - evt.target.value = val.replace(voidChars, '') - } - }, - [unbounded], - ) - - const onChangeCallback = useCallback( - evt => { - const data = evt?.nativeEvent?.data - - // Due to the way that react-text-mask works, it is not possible to - // store the cleaned value, since it would create ambiguity between - // values like `AA` and `AA `. This causes backspaces to not work - // if it targets the space character, since the deleted space would - // be re-added right away. Hence, unbounded inputs need to remove - // the space paddings manually. - let newValue = unbounded ? evt.target.value : clean(evt.target.value) - - // Make sure values entered at the end of the input (with placeholders) - // are added as expected. `selectionStart` cannot be used due to - // inconsistent behavior on Android phones. - if ( - evt.target.value.endsWith(PLACEHOLDER_CHAR) && - data && - hex.test(data) && - value === newValue - ) { - newValue += data - } - - onChange({ - target: { - name: evt.target.name, - value: newValue, - }, - }) - }, - [onChange, value, unbounded], - ) - - const onBlurCallback = useCallback( - evt => { - onBlur({ - relatedTarget: evt.relatedTarget, - target: { - name: evt.target.name, - value: clean(evt.target.value), - }, - }) - }, - [onBlur], - ) - - const onCut = useCallback(evt => { - evt.preventDefault() - // Recreate cut action by deleting and reusing copy handler. - document.execCommand('copy') - document.execCommand('delete') - }, []) - - // Instead of calculating the max width dynamically, which leads to various issues - // with pasting, it's better to use a high max value for unbounded inputs instead. - const calculatedMax = max || 4096 - - if (!unbounded && typeof max !== 'number') { - warn( - 'Byte input has been setup without `max` prop. Always use a max prop unless using `unbounded`', + const onChangeCallback = useCallback( + evt => { + const data = evt?.nativeEvent?.data + + // Due to the way that react-text-mask works, it is not possible to + // store the cleaned value, since it would create ambiguity between + // values like `AA` and `AA `. This causes backspaces to not work + // if it targets the space character, since the deleted space would + // be re-added right away. Hence, unbounded inputs need to remove + // the space paddings manually. + let newValue = unbounded ? evt.target.value : clean(evt.target.value) + + // Make sure values entered at the end of the input (with placeholders) + // are added as expected. `selectionStart` cannot be used due to + // inconsistent behavior on Android phones. + if ( + evt.target.value.endsWith(PLACEHOLDER_CHAR) && + data && + hex.test(data) && + value === newValue + ) { + newValue += data + } + + onChange({ + target: { + name: evt.target.name, + value: newValue, + }, + }) + }, + [onChange, value, unbounded], ) - } - return ( - - ) -} + const onBlurCallback = useCallback( + evt => { + onBlur({ + relatedTarget: evt.relatedTarget, + target: { + name: evt.target.name, + value: clean(evt.target.value), + }, + }) + }, + [onBlur], + ) + + const onCut = useCallback(evt => { + evt.preventDefault() + // Recreate cut action by deleting and reusing copy handler. + document.execCommand('copy') + document.execCommand('delete') + }, []) + + // Instead of calculating the max width dynamically, which leads to various issues + // with pasting, it's better to use a high max value for unbounded inputs instead. + const calculatedMax = max || 4096 + + if (!unbounded && typeof max !== 'number') { + warn( + 'Byte input has been setup without `max` prop. Always use a max prop unless using `unbounded`', + ) + } + + return ( + + ) + }, +) ByteInput.propTypes = { className: PropTypes.string, diff --git a/pkg/webui/components/input/stories/shared.js b/pkg/webui/components/input/stories/shared.js index 3e4350d296..5cdaf61735 100644 --- a/pkg/webui/components/input/stories/shared.js +++ b/pkg/webui/components/input/stories/shared.js @@ -14,33 +14,22 @@ /* eslint-disable react/prop-types, import/prefer-default-export */ -import React from 'react' -import bind from 'autobind-decorator' +import React, { useCallback, useState } from 'react' import Input from '..' -class Example extends React.Component { - constructor(props) { - super(props) +const Example = props => { + const { value: initialValue, type, component: Component, ...rest } = props - this.state = { - value: props.value || '', - } - } + const [value, setValue] = useState(initialValue || '') - @bind - onChange(value) { - this.setState({ value }) - } + const handleChangeInput = useCallback(newValue => { + setValue(newValue) + }, []) - render() { - const { type, component: Component, ...props } = this.props - const { value } = this.state + const InputComponent = Component || Input - const InputComponent = Component ? Component : Input - - return - } + return } export { Example } diff --git a/pkg/webui/components/key-value-map/entry.js b/pkg/webui/components/key-value-map/entry.js index 05e25355df..b509198db9 100644 --- a/pkg/webui/components/key-value-map/entry.js +++ b/pkg/webui/components/key-value-map/entry.js @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useCallback, useMemo } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { defineMessages } from 'react-intl' import classnames from 'classnames' import Button from '@ttn-lw/components/button' +import sharedMessages from '@ttn-lw/lib/shared-messages' import PropTypes from '@ttn-lw/lib/prop-types' import style from './key-value-map.styl' @@ -30,6 +31,7 @@ const Entry = ({ readOnly, name, value, + fieldValue, index, onRemoveButtonClick, onChange, @@ -39,12 +41,19 @@ const Entry = ({ valuePlaceholder, keyPlaceholder, additionalInputProps, + removeMessage, + distinctOptions, + atLeastOneEntry, + filterByTag, }) => { + const [currentValue, setCurrentValue] = useState(value) + const [newOptions, setNewOptions] = useState(undefined) + const { options, ...additionalInputPropsRest } = additionalInputProps const _getKeyInputName = useMemo(() => `${name}[${index}].key`, [index, name]) const _getValueInputName = useMemo(() => `${name}[${index}].value`, [index, name]) - const handleRemoveButtonClicked = useCallback( + const handleRemoveButtonClick = useCallback( event => { onRemoveButtonClick(index, event) }, @@ -60,6 +69,7 @@ const Entry = ({ const handleValueChanged = useCallback( newValue => { + setCurrentValue(newValue) onChange(index, { value: newValue }) }, [index, onChange], @@ -82,6 +92,25 @@ const Entry = ({ [onBlur, name, value, _getKeyInputName, _getValueInputName], ) + const handleOptionComposition = useCallback(() => { + let newOptions + if (currentValue) { + newOptions = options.filter(v => !fieldValue.includes(v.value) || v.value === currentValue) + } else { + newOptions = options.filter(v => !fieldValue.includes(v.value)) + } + + let taggedOptions = newOptions + if (fieldValue.length >= 2 && filterByTag) { + const selectedOption = options.find(v => v.value === fieldValue[0]) + taggedOptions = newOptions.filter(v => selectedOption.tag === v.tag) + } + + setNewOptions(taggedOptions) + }, [currentValue, options, fieldValue, filterByTag]) + + const showRemoveButton = atLeastOneEntry ? index !== 0 : true + return (
{!indexAsKey && ( @@ -107,25 +136,36 @@ const Entry = ({ type="text" onChange={handleValueChanged} onBlur={handleBlur} + onFocus={distinctOptions && options ? handleOptionComposition : undefined} value={indexAsKey ? value : value.value} readOnly={readOnly} code - {...additionalInputProps} - /> -
) } Entry.propTypes = { - additionalInputProps: PropTypes.shape({}).isRequired, + additionalInputProps: PropTypes.shape({ + options: PropTypes.array, + }).isRequired, + atLeastOneEntry: PropTypes.bool, + distinctOptions: PropTypes.bool, + fieldValue: PropTypes.any, + filterByTag: PropTypes.bool, index: PropTypes.number.isRequired, indexAsKey: PropTypes.bool.isRequired, inputElement: PropTypes.elementType.isRequired, @@ -135,6 +175,7 @@ Entry.propTypes = { onChange: PropTypes.func.isRequired, onRemoveButtonClick: PropTypes.func.isRequired, readOnly: PropTypes.bool, + removeMessage: PropTypes.message, value: PropTypes.oneOfType([ PropTypes.shape({ key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), @@ -148,6 +189,11 @@ Entry.propTypes = { Entry.defaultProps = { value: undefined, readOnly: false, + removeMessage: sharedMessages.remove, + distinctOptions: false, + fieldValue: undefined, + atLeastOneEntry: false, + filterByTag: false, } export default Entry diff --git a/pkg/webui/components/key-value-map/index.js b/pkg/webui/components/key-value-map/index.js index 42900f0730..b908a8f6e9 100644 --- a/pkg/webui/components/key-value-map/index.js +++ b/pkg/webui/components/key-value-map/index.js @@ -31,6 +31,7 @@ const m = defineMessages({ const KeyValueMap = ({ addMessage, + removeMessage, additionalInputProps, className, disabled, @@ -43,6 +44,9 @@ const KeyValueMap = ({ onChange, value, valuePlaceholder, + distinctOptions, + atLeastOneEntry, + filterByTag, }) => { const handleEntryChange = useCallback( (index, newValues) => { @@ -76,11 +80,12 @@ const KeyValueMap = ({
{value && - value.map((value, index) => ( + value.map((individualValue, index) => ( ))}
@@ -111,8 +120,11 @@ const KeyValueMap = ({ KeyValueMap.propTypes = { addMessage: PropTypes.message, additionalInputProps: PropTypes.shape({}), + atLeastOneEntry: PropTypes.bool, className: PropTypes.string, disabled: PropTypes.bool, + distinctOptions: PropTypes.bool, + filterByTag: PropTypes.bool, indexAsKey: PropTypes.bool, inputElement: PropTypes.elementType, isReadOnly: PropTypes.func, @@ -120,6 +132,7 @@ KeyValueMap.propTypes = { name: PropTypes.string.isRequired, onBlur: PropTypes.func, onChange: PropTypes.func, + removeMessage: PropTypes.message, value: PropTypes.arrayOf( PropTypes.oneOfType([ PropTypes.shape({ @@ -144,6 +157,10 @@ KeyValueMap.defaultProps = { disabled: false, isReadOnly: () => null, inputElement: Input, + removeMessage: undefined, + distinctOptions: false, + atLeastOneEntry: false, + filterByTag: false, } export default KeyValueMap diff --git a/pkg/webui/components/modal/modal.styl b/pkg/webui/components/modal/modal.styl index 845b81c688..703e85eca1 100644 --- a/pkg/webui/components/modal/modal.styl +++ b/pkg/webui/components/modal/modal.styl @@ -136,6 +136,7 @@ margin-bottom: $cs.s flex-direction: row align-items: stretch + gap: 1rem button:not(:last-child) margin-right: 0 diff --git a/pkg/webui/components/profile-dropdown/index.js b/pkg/webui/components/profile-dropdown/index.js index 31149e3437..1c69eee1ea 100644 --- a/pkg/webui/components/profile-dropdown/index.js +++ b/pkg/webui/components/profile-dropdown/index.js @@ -1,4 +1,4 @@ -// Copyright © 2019 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react' -import bind from 'autobind-decorator' +import React, { useCallback, useRef, useState } from 'react' import classnames from 'classnames' import Icon from '@ttn-lw/components/icon' @@ -24,69 +23,41 @@ import PropTypes from '@ttn-lw/lib/prop-types' import styles from './profile-dropdown.styl' -export default class ProfileDropdown extends React.PureComponent { - state = { - expanded: false, - } +const ProfileDropdown = props => { + const [expanded, setExpanded] = useState(false) + const node = useRef(null) + const { userName, className, children, profilePicture, ...rest } = props - @bind - showDropdown() { - document.addEventListener('mousedown', this.handleClickOutside) - this.setState({ expanded: true }) - } - - @bind - hideDropdown() { - document.removeEventListener('mousedown', this.handleClickOutside) - this.setState({ expanded: false }) - } - - @bind - handleClickOutside(e) { - if (!this.node.contains(e.target)) { - this.hideDropdown() - } - } - - @bind - toggleDropdown() { - let { expanded } = this.state - expanded = !expanded - if (expanded) { - this.showDropdown() - } else { - this.hideDropdown() + const handleClickOutside = useCallback(e => { + if (node.current && !node.current.contains(e.target)) { + setExpanded(false) } - } - - @bind - ref(node) { - this.node = node - } + }, []) - render() { - const { userName, className, children, profilePicture, ...rest } = this.props + const toggleDropdown = useCallback(() => { + setExpanded(oldExpanded => { + const newState = !oldExpanded + if (newState) document.addEventListener('mousedown', handleClickOutside) + else document.removeEventListener('mousedown', handleClickOutside) + return newState + }) + }, [handleClickOutside]) - return ( -
- - {userName} - - {this.state.expanded && {children}} -
- ) - } + return ( +
+ + {userName} + + {expanded && {children}} +
+ ) } ProfileDropdown.propTypes = { @@ -106,3 +77,5 @@ ProfileDropdown.defaultProps = { className: undefined, profilePicture: undefined, } + +export default ProfileDropdown diff --git a/pkg/webui/components/qr-modal-button/index.js b/pkg/webui/components/qr-modal-button/index.js index ab66035cc1..4771b134e2 100644 --- a/pkg/webui/components/qr-modal-button/index.js +++ b/pkg/webui/components/qr-modal-button/index.js @@ -34,7 +34,6 @@ const QrScanDoc = ( ) const m = defineMessages({ - scanEndDevice: 'Scan end device QR code', scanEndDeviceContinue: 'Please scan the QR code to continue. {qrScanDoc}', invalidData: 'Invalid QR code data. Please note that only TR005 LoRaWAN® Device Identification QR Code can be scanned. Some devices have unrelated QR codes printed on them that cannot be used.', @@ -81,7 +80,7 @@ const QRModalButton = props => { onApprove={onApprove} message={message} modalData={{ - title: m.scanEndDevice, + title: sharedMessages.scanEndDevice, children: modalData, buttonMessage: m.apply, approveButtonProps: { diff --git a/pkg/webui/components/qr/input/video/index.js b/pkg/webui/components/qr/input/video/index.js index f965f9672e..d08e614ce7 100644 --- a/pkg/webui/components/qr/input/video/index.js +++ b/pkg/webui/components/qr/input/video/index.js @@ -1,4 +1,4 @@ -// Copyright © 2022 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -28,42 +28,118 @@ const m = defineMessages({ switchCamera: 'Switch camera', }) -const Video = props => { +const Camera = props => { const { onRead, setError, setCapture } = props - const videoRef = createRef() - const [stream, setStream] = useState(undefined) - const [devices, setDevices] = useState([]) const [cameras, setCameras] = useState([]) - const isMobile = window.innerWidth <= 768 + const [deviceId, setDeviceId] = useState(undefined) + + const [hasFrontCamera, setHasFrontCamera] = useState(false) + const [hasBackCamera, setHasBackCamera] = useState(false) + + const handleSwitchCamera = useCallback(() => { + // The majority of mobile device will have labeled front and back cameras. + const currentCamera = cameras.find(device => device.deviceId === deviceId) + + if (hasFrontCamera && hasBackCamera) { + if (currentCamera.label.toLowerCase().includes('back')) { + const frontCamera = cameras.find(device => device.label.toLowerCase().includes('front')) + setDeviceId(frontCamera.deviceId) + } + + if (currentCamera.label.toLowerCase().includes('front')) { + const backCamera = cameras.find(device => device.label.toLowerCase().includes('back')) + setDeviceId(backCamera.deviceId) + } + } + }, [cameras, deviceId, hasBackCamera, hasFrontCamera]) + + const handleCameraCycle = useCallback(() => { + // If there are more than one camera then cycle through them, only if there are no camera clearly labeled and back and front + if (cameras.length > 1) { + const currentIndex = cameras.findIndex(device => device.deviceId === deviceId) + + const nextDevice = currentIndex !== -1 ? cameras[(currentIndex + 1) % cameras.length] : null + setDeviceId(nextDevice.deviceId) + } + }, [cameras, deviceId]) const getDevices = useCallback(async () => { - if (!devices.length) { - const enumerateDevices = await navigator.mediaDevices.enumerateDevices() - setDevices(enumerateDevices) + // Depending on your device you may have access to this list on initial load + // If you do not have access to this list then you will need to request a stream to get the list + const enumerateDevices = await navigator.mediaDevices.enumerateDevices() + const videoInputs = enumerateDevices.filter(device => device.kind === 'videoinput') + + if (videoInputs.length !== cameras.length) { + setCameras(videoInputs) } - }, [devices.length]) - - const getStream = useCallback(async () => { - if (devices.length && !stream) { - const ua = navigator.userAgent.toLowerCase() - const cameras = devices.filter(device => device.kind === 'videoinput') - setCameras(cameras) - let rearCamera = cameras.find(device => device.label.toLowerCase().includes('back')) - if (!rearCamera) { - rearCamera = cameras[1] ?? cameras[0] - } - const videoMode = - cameras.length > 1 - ? ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1 - ? { facingMode: { exact: 'environment' } } - : { deviceId: rearCamera.deviceId } - : { facingMode: 'environment' } + }, [cameras]) + + const setDeviceIdFromStream = useCallback(userStream => { + const videoTracks = userStream.getVideoTracks() + + if (videoTracks.length > 0) { + const { deviceId } = videoTracks[0].getSettings() + setDeviceId(deviceId) + } + }, []) + + useEffect(() => { + setHasFrontCamera(cameras.some(device => device.label.toLowerCase().includes('front'))) + setHasBackCamera(cameras.some(device => device.label.toLowerCase().includes('back'))) + }, [cameras]) + + return ( + <> + {hasFrontCamera && hasBackCamera ? ( +
+ + + + + + {useDefault && ( + <> + + + + + + + + + + + + + + + + )} + + ) +} + +export default DefaultRoutingPolicyForm diff --git a/pkg/webui/console/components/device-import-form/index.js b/pkg/webui/console/components/device-import-form/index.js index bcbb6ca42c..5eb629adc0 100644 --- a/pkg/webui/console/components/device-import-form/index.js +++ b/pkg/webui/console/components/device-import-form/index.js @@ -53,7 +53,6 @@ const m = defineMessages({ formatInfo: 'Format information', selectAFile: 'Please select a template file', fileInfoPlaceholder: 'Please select a template format', - claiming: 'Claiming', setClaimAuthCode: 'Set claim authentication code', targetedComponents: 'Targeted components', advancedSectionTitle: 'Advanced end device claiming settings', @@ -143,7 +142,7 @@ const DeviceBulkCreateFormInner = props => { { - const appId = selectSelectedApplicationId(state) - const devId = selectSelectedDeviceId(state) - const device = selectSelectedDevice(state) - const skipPayloadCrypto = selectApplicationLinkSkipPayloadCrypto(state) - - return { - appId, - devId, - device, - downlinkQueue: tts.Applications.Devices.DownlinkQueue, - skipPayloadCrypto, - } -} - -export default DownlinkForm => connect(mapStateToProps)(DownlinkForm) diff --git a/pkg/webui/console/components/downlink-form/downlink-form.js b/pkg/webui/console/components/downlink-form/downlink-form.js deleted file mode 100644 index e7f196a172..0000000000 --- a/pkg/webui/console/components/downlink-form/downlink-form.js +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright © 2020 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. - -import React, { useState, useCallback } from 'react' -import { defineMessages } from 'react-intl' - -import Notification from '@ttn-lw/components/notification' -import SubmitButton from '@ttn-lw/components/submit-button' -import RadioButton from '@ttn-lw/components/radio-button' -import Checkbox from '@ttn-lw/components/checkbox' -import Input from '@ttn-lw/components/input' -import SubmitBar from '@ttn-lw/components/submit-bar' -import toast from '@ttn-lw/components/toast' -import Form from '@ttn-lw/components/form' -import CodeEditor from '@ttn-lw/components/code-editor' - -import IntlHelmet from '@ttn-lw/lib/components/intl-helmet' - -import Yup from '@ttn-lw/lib/yup' -import PropTypes from '@ttn-lw/lib/prop-types' -import sharedMessages from '@ttn-lw/lib/shared-messages' - -import { hexToBase64 } from '@console/lib/bytes' - -const m = defineMessages({ - insertMode: 'Insert Mode', - payloadType: 'Payload type', - bytes: 'Bytes', - replace: 'Replace downlink queue', - push: 'Push to downlink queue (append)', - confirmedDownlink: 'Confirmed downlink', - scheduleDownlink: 'Schedule downlink', - downlinkSuccess: 'Downlink scheduled', - bytesPayloadDescription: 'The desired payload bytes of the downlink message', - jsonPayloadDescription: 'The decoded payload of the downlink message', - invalidSessionWarning: - 'Downlinks can only be scheduled for end devices with a valid session. Please make sure your end device is properly connected to the network.', -}) - -const validationSchema = Yup.object({ - _mode: Yup.string().oneOf(['replace', 'push']).required(sharedMessages.validateRequired), - _payload_type: Yup.string().oneOf(['bytes', 'json']), - f_port: Yup.number() - .min(1, Yup.passValues(sharedMessages.validateNumberGte)) - .max(223, Yup.passValues(sharedMessages.validateNumberLte)) - .required(sharedMessages.validateRequired), - confirmed: Yup.bool().required(), - frm_payload: Yup.string().when('_payload_type', { - is: type => type === 'bytes', - then: schema => - schema.test( - 'len', - Yup.passValues(sharedMessages.validateHexLength), - val => !Boolean(val) || val.length % 3 === 0, - ), - otherwise: schema => schema.strip(), - }), - decoded_payload: Yup.string().when('_payload_type', { - is: type => type === 'json', - then: schema => - schema.test('valid-json', sharedMessages.validateJson, json => { - try { - JSON.parse(json) - return true - } catch (e) { - return false - } - }), - otherwise: schema => schema.strip(), - }), -}) - -const initialValues = { - _mode: 'replace', - _payload_type: 'bytes', - f_port: 1, - confirmed: false, - frm_payload: '', - decoded_payload: '', -} - -const DownlinkForm = ({ appId, devId, device, downlinkQueue, skipPayloadCrypto }) => { - const [payloadType, setPayloadType] = React.useState('bytes') - const [error, setError] = useState('') - - const handleSubmit = useCallback( - async (vals, { setSubmitting, resetForm }) => { - const { _mode, _payload_type, ...values } = validationSchema.cast(vals) - try { - if (_payload_type === 'bytes') { - values.frm_payload = hexToBase64(values.frm_payload) - } - - if (_payload_type === 'json') { - values.decoded_payload = JSON.parse(values.decoded_payload) - } - - await downlinkQueue[_mode](appId, devId, [values]) - toast({ - title: sharedMessages.success, - type: toast.types.SUCCESS, - message: m.downlinkSuccess, - }) - setSubmitting(false) - } catch (err) { - setError(err) - resetForm({ values: vals }) - } - }, - [appId, devId, downlinkQueue], - ) - - const validSession = device.session || device.pending_session - const payloadCryptoSkipped = device.skip_payload_crypto_override ?? skipPayloadCrypto - const deviceSimulationDisabled = !validSession || payloadCryptoSkipped - - return ( - <> - {payloadCryptoSkipped && ( - - )} - {!validSession && } - -
- - - - - - - - - - - {payloadType === 'bytes' ? ( - - ) : ( - - )} - - - - - - - ) -} - -DownlinkForm.propTypes = { - appId: PropTypes.string.isRequired, - devId: PropTypes.string.isRequired, - device: PropTypes.device.isRequired, - downlinkQueue: PropTypes.shape({ - list: PropTypes.func.isRequired, - push: PropTypes.func.isRequired, - replace: PropTypes.func.isRequired, - }).isRequired, - skipPayloadCrypto: PropTypes.bool.isRequired, -} - -export default DownlinkForm diff --git a/pkg/webui/console/components/downlink-form/index.js b/pkg/webui/console/components/downlink-form/index.js index de4f69e297..413aba6b65 100644 --- a/pkg/webui/console/components/downlink-form/index.js +++ b/pkg/webui/console/components/downlink-form/index.js @@ -12,9 +12,199 @@ // See the License for the specific language governing permissions and // limitations under the License. -import DownlinkForm from './downlink-form' -import connect from './connect' +import React, { useState, useCallback } from 'react' +import { defineMessages } from 'react-intl' +import { useSelector } from 'react-redux' -const ConnectedDownlinkForm = connect(DownlinkForm) +import tts from '@console/api/tts' -export { ConnectedDownlinkForm as default, DownlinkForm } +import Notification from '@ttn-lw/components/notification' +import SubmitButton from '@ttn-lw/components/submit-button' +import RadioButton from '@ttn-lw/components/radio-button' +import Checkbox from '@ttn-lw/components/checkbox' +import Input from '@ttn-lw/components/input' +import SubmitBar from '@ttn-lw/components/submit-bar' +import toast from '@ttn-lw/components/toast' +import Form from '@ttn-lw/components/form' +import CodeEditor from '@ttn-lw/components/code-editor' + +import IntlHelmet from '@ttn-lw/lib/components/intl-helmet' + +import Yup from '@ttn-lw/lib/yup' +import sharedMessages from '@ttn-lw/lib/shared-messages' + +import { hexToBase64 } from '@console/lib/bytes' + +import { + selectApplicationLinkSkipPayloadCrypto, + selectSelectedApplicationId, +} from '@console/store/selectors/applications' +import { selectSelectedDevice, selectSelectedDeviceId } from '@console/store/selectors/devices' + +const m = defineMessages({ + insertMode: 'Insert Mode', + payloadType: 'Payload type', + bytes: 'Bytes', + replace: 'Replace downlink queue', + push: 'Push to downlink queue (append)', + scheduleDownlink: 'Schedule downlink', + downlinkSuccess: 'Downlink scheduled', + bytesPayloadDescription: 'The desired payload bytes of the downlink message', + jsonPayloadDescription: 'The decoded payload of the downlink message', + invalidSessionWarning: + 'Downlinks can only be scheduled for end devices with a valid session. Please make sure your end device is properly connected to the network.', +}) + +const validationSchema = Yup.object({ + _mode: Yup.string().oneOf(['replace', 'push']).required(sharedMessages.validateRequired), + _payload_type: Yup.string().oneOf(['bytes', 'json']), + f_port: Yup.number() + .min(1, Yup.passValues(sharedMessages.validateNumberGte)) + .max(223, Yup.passValues(sharedMessages.validateNumberLte)) + .required(sharedMessages.validateRequired), + confirmed: Yup.bool().required(), + frm_payload: Yup.string().when('_payload_type', { + is: type => type === 'bytes', + then: schema => + schema.test( + 'len', + Yup.passValues(sharedMessages.validateHexLength), + val => !Boolean(val) || val.length % 3 === 0, + ), + otherwise: schema => schema.strip(), + }), + decoded_payload: Yup.string().when('_payload_type', { + is: type => type === 'json', + then: schema => + schema.test('valid-json', sharedMessages.validateJson, json => { + try { + JSON.parse(json) + return true + } catch (e) { + return false + } + }), + otherwise: schema => schema.strip(), + }), +}) + +const initialValues = { + _mode: 'replace', + _payload_type: 'bytes', + f_port: 1, + confirmed: false, + frm_payload: '', + decoded_payload: '', +} + +const DownlinkForm = () => { + const [payloadType, setPayloadType] = React.useState('bytes') + const [error, setError] = useState('') + const appId = useSelector(selectSelectedApplicationId) + const devId = useSelector(selectSelectedDeviceId) + const device = useSelector(selectSelectedDevice) + const skipPayloadCrypto = useSelector(selectApplicationLinkSkipPayloadCrypto) + + const handleSubmit = useCallback( + async (vals, { setSubmitting, resetForm }) => { + const { _mode, _payload_type, ...values } = validationSchema.cast(vals) + try { + if (_payload_type === 'bytes') { + values.frm_payload = hexToBase64(values.frm_payload) + } + + if (_payload_type === 'json') { + values.decoded_payload = JSON.parse(values.decoded_payload) + } + + await tts.Applications.Devices.DownlinkQueue[_mode](appId, devId, [values]) + toast({ + title: sharedMessages.success, + type: toast.types.SUCCESS, + message: m.downlinkSuccess, + }) + setSubmitting(false) + } catch (err) { + setError(err) + resetForm({ values: vals }) + } + }, + [appId, devId], + ) + + const validSession = device.session || device.pending_session + const payloadCryptoSkipped = device.skip_payload_crypto_override ?? skipPayloadCrypto + const deviceSimulationDisabled = !validSession || payloadCryptoSkipped + + return ( + <> + {payloadCryptoSkipped && ( + + )} + {!validSession && } + +
+ + + + + + + + + + + {payloadType === 'bytes' ? ( + + ) : ( + + )} + + + + + + + ) +} + +export default DownlinkForm diff --git a/pkg/webui/console/components/events/error-boundary.js b/pkg/webui/console/components/events/error-boundary.js index 951bb8d102..df905cb630 100644 --- a/pkg/webui/console/components/events/error-boundary.js +++ b/pkg/webui/console/components/events/error-boundary.js @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react' +import React, { useCallback, useState } from 'react' import Icon from '@ttn-lw/components/icon' @@ -24,32 +24,38 @@ import m from './messages' import style from './events.styl' -class EventErrorBoundary extends React.Component { - state = { hasErrored: false, error: undefined, expanded: false } +const EventErrorBoundary = ({ children }) => { + const [hasErrored, setHasErrored] = useState(false) - static getDerivedStateFromError() { - return { hasErrored: true } - } - - render() { - const { hasErrored } = this.state - const { children } = this.props + const handleError = useCallback(() => { + setHasErrored(true) + }, []) - if (hasErrored) { - return ( -
- - -
- ) - } - - return children + if (hasErrored) { + return ( +
+ + +
+ ) } + + return ( + + {React.Children.map(children, child => { + if (!child) { + return null + } + return React.cloneElement(child, { + onError: handleError, + }) + })} + + ) } EventErrorBoundary.propTypes = { - children: PropTypes.node.isRequired, + children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired, } export default EventErrorBoundary diff --git a/pkg/webui/console/components/events/messages.js b/pkg/webui/console/components/events/messages.js index 77e54d255a..7e6e8a6827 100644 --- a/pkg/webui/console/components/events/messages.js +++ b/pkg/webui/console/components/events/messages.js @@ -15,8 +15,6 @@ import { defineMessages } from 'react-intl' const messages = defineMessages({ - // Field messages - payload: 'Payload', MACPayload: 'MAC payload', devAddr: 'DevAddr', fPort: 'FPort', @@ -37,6 +35,7 @@ const messages = defineMessages({ rx2DataRateIndex: 'Rx2 Data Rate Index', rx2Frequency: 'Rx2 Frequency', class: 'Class', + // Generic messages eventDetails: 'Event details', rawEvent: 'Raw event', @@ -53,7 +52,6 @@ const messages = defineMessages({ 'Old events have been truncated to save memory. The current event limit per stream is {limit}.', eventUnavailable: 'This event is not available anymore. It was likely truncated to save memory.', verboseStream: 'Verbose stream', - confirmedDownlink: 'Confirmed downlink', confirmedUplink: 'Confirmed uplink', }) diff --git a/pkg/webui/console/components/gateway-visibility-form/index.js b/pkg/webui/console/components/gateway-visibility-form/index.js index 724f405f4a..535477a7ac 100644 --- a/pkg/webui/console/components/gateway-visibility-form/index.js +++ b/pkg/webui/console/components/gateway-visibility-form/index.js @@ -23,6 +23,7 @@ import SubmitButton from '@ttn-lw/components/submit-button' import PropTypes from '@ttn-lw/lib/prop-types' import Yup from '@ttn-lw/lib/yup' +import sharedMessages from '@ttn-lw/lib/shared-messages' import gatewayVisibilityMessages from '@console/lib/packet-broker/messages' @@ -49,7 +50,7 @@ const GatewayVisibilityForm = ({ onSubmit, initialValues, error }) => { { { + const { + formTitle, validationSchema, - updatesDisabled: false, - noLocationSetInfo: m.noLocationSetInfo, - } + children, + updatesDisabled, + additionalMarkers, + initialValues, + disabledInfo, + noLocationSetInfo, + onSubmit, + onDelete, + entityId, + } = props - constructor(props) { - super(props) + const form = useRef(null) + const [latitude, setLatitude] = useState(props.initialValues.latitude) + const [longitude, setLongitude] = useState(props.initialValues.longitude) + const [zoom, setZoom] = useState(14) + const [error, setError] = useState(undefined) + const [mapCenter, setMapCenter] = useState(undefined) + const [loading, setLoading] = useState(true) + const [deleteAll, setDeleteAll] = useState( + !hasLocationSet(initialValues) && Object.keys(additionalMarkers).length !== 0, + ) - this.form = React.createRef() - - this.state = { - latitude: props.initialValues.latitude, - longitude: props.initialValues.longitude, - zoom: 14, - error: undefined, - mapCenter: undefined, - loading: true, - deleteAll: - !hasLocationSet(props.initialValues) && Object.keys(props.additionalMarkers).length !== 0, - } + const entryExists = useMemo(() => hasLocationSet(initialValues), [initialValues]) + const automaticExists = Object.keys(additionalMarkers).length !== 0 + const anyEntryExists = entryExists || automaticExists + const onlyAutomaticExists = !entryExists && anyEntryExists + const markers = [...additionalMarkers] + if (typeof longitude === 'number' && typeof latitude === 'number') { + markers.push({ position: { longitude, latitude } }) } - @bind - async componentDidMount() { - const { initialValues, additionalMarkers } = this.props - let newState = { mapCenter: defaultLocation, loading: false } - if (!hasLocationSet(initialValues) && additionalMarkers.length === 0) { - if ('geolocation' in navigator) { - newState = await new Promise(resolve => { - navigator.geolocation.getCurrentPosition( - position => { - resolve({ - mapCenter: [ - isNaN(position.coords.latitude) ? defaultLocation[0] : position.coords.latitude, - isNaN(position.coords.longitude) ? defaultLocation[1] : position.coords.longitude, - ], - loading: false, - }) - }, - () => { - resolve({ mapCenter: defaultLocation, zoom: 2, loading: false }) - }, - ) - }) - } + const getCurrentLocation = useCallback(async () => { + let newState = { mapCenter: defaultLocation } + if ( + !hasLocationSet(initialValues) && + additionalMarkers.length === 0 && + 'geolocation' in navigator + ) { + newState = await new Promise(resolve => { + navigator.geolocation.getCurrentPosition( + position => { + resolve({ + mapCenter: [ + isNaN(position.coords.latitude) ? defaultLocation[0] : position.coords.latitude, + isNaN(position.coords.longitude) ? defaultLocation[1] : position.coords.longitude, + ], + }) + }, + () => { + resolve({ mapCenter: defaultLocation, zoom: 2 }) + }, + ) + }) } - this.setState(newState) - } - @bind - async handleSubmit(values, { setSubmitting }) { - const { onSubmit, entityId, validationSchema } = this.props - this.setState({ error: undefined }) + return newState + }, [additionalMarkers.length, initialValues]) - const castedValues = validationSchema.cast(values) + useEffect(() => { + getCurrentLocation().then(res => { + setMapCenter(res.mapCenter) + setZoom(res.zoom ?? 2) + setLoading(false) + }) + }, [getCurrentLocation]) - try { - await onSubmit(castedValues) - this.setState({ deleteAll: false }) - toast({ - title: entityId, - message: m.updateSuccess, - type: toast.types.SUCCESS, - }) - } catch (error) { - this.setState({ error }) - setSubmitting(false) - } - } + const handleSubmit = useCallback( + async (values, { setSubmitting }) => { + setError(undefined) - @bind - handleClick(event) { - const { updatesDisabled } = this.props - const { setValues, values } = this.form.current - const latitude = isNaN(event.latlng.lat) ? defaultLocation[0] : event.latlng.lat - const longitude = isNaN(event.latlng.lng) ? defaultLocation[1] : event.latlng.lng + const castedValues = validationSchema.cast(values) - if (updatesDisabled) { - return - } + try { + await onSubmit(castedValues) + setDeleteAll(false) + toast({ + title: entityId, + message: m.updateSuccess, + type: toast.types.SUCCESS, + }) + } catch (error) { + setError(error) + setSubmitting(false) + } + }, + [entityId, onSubmit, validationSchema], + ) - this.setState({ latitude, longitude }) - setValues({ - ...values, - latitude, - longitude, - altitude: values.altitude ? values.altitude : 0, - }) - } + const handleClick = useCallback( + event => { + const { setValues, values } = form.current + const latitude = isNaN(event.latlng.lat) ? defaultLocation[0] : event.latlng.lat + const longitude = isNaN(event.latlng.lng) ? defaultLocation[1] : event.latlng.lng - @bind - handleLatitudeChange(event) { - const { longitude } = this.state - const latitude = event.currentTarget.value - if (longitude) { - this.setState({ latitude, mapCenter: [Number(latitude), Number(longitude)] }) - } else { - this.setState({ latitude }) - } - } + if (updatesDisabled) { + return + } + setLatitude(latitude) + setLongitude(longitude) + setValues({ + ...values, + latitude, + longitude, + altitude: values.altitude ? values.altitude : 0, + }) + }, + [updatesDisabled], + ) - @bind - handleLongitudeChange(event) { - const { latitude } = this.state - const longitude = event.currentTarget.value - if (latitude) { - this.setState({ longitude, mapCenter: [Number(latitude), Number(longitude)] }) - } else { - this.setState({ longitude }) - } - } + const handleLatitudeChange = useCallback( + event => { + const latitude = event.currentTarget.value + setLatitude(latitude) + if (longitude) { + setMapCenter([Number(latitude), Number(longitude)]) + } + }, + [longitude], + ) + + const handleLongitudeChange = useCallback( + event => { + const longitude = event.currentTarget.value + setLongitude(longitude) + if (latitude) { + setMapCenter([Number(latitude), Number(longitude)]) + } + }, + [latitude], + ) - @bind - handleDeleteAllCheck(event) { + const handleDeleteAllCheck = useCallback(event => { if (!event || !event.target) { return } - this.setState({ deleteAll: event.target.checked }) - } - - @bind - async handleDelete() { - const { onDelete, entityId } = this.props - const { deleteAll } = this.state + setDeleteAll(event.target.checked) + }, []) + const handleDelete = useCallback(async () => { try { await onDelete(deleteAll) - this.form.current.resetForm({ values: emptyLocation }) - this.setState({ latitude: undefined, longitude: undefined }) + form.current.resetForm({ values: emptyLocation }) + setLatitude(undefined) + setLongitude(undefined) toast({ title: entityId, message: m.deleteSuccess, type: toast.types.SUCCESS, }) } catch (error) { - this.setState({ error }) + setError(error) } - } + }, [deleteAll, entityId, onDelete]) - render() { - const { - formTitle, - validationSchema, - children, - updatesDisabled, - additionalMarkers, - initialValues, - disabledInfo, - noLocationSetInfo, - } = this.props - const { error, latitude, longitude, mapCenter, zoom, loading, deleteAll } = this.state - - const entryExists = hasLocationSet(initialValues) - const automaticExists = Object.keys(additionalMarkers).length !== 0 - const anyEntryExists = entryExists || automaticExists - const onlyAutomaticExists = !entryExists && anyEntryExists - const markers = [...additionalMarkers] - if (typeof longitude === 'number' && typeof latitude === 'number') { - markers.push({ position: { longitude, latitude } }) - } - return ( - -
- - {children} - - {!entryExists && } - - - - - {updatesDisabled && disabledInfo && } - - - - - - - + + {children} + + {!entryExists && } + + + + + {updatesDisabled && disabledInfo && } + + + + + + + + {entryExists && automaticExists && ( + <> +
+
+ + - {entryExists && automaticExists && ( - <> -
-
- - - - )} - - ), - }} - onApprove={this.handleDelete} - disabled={updatesDisabled || !anyEntryExists} - naked - danger - /> -
- -
- ) - } + + )} + + ), + }} + onApprove={handleDelete} + disabled={updatesDisabled || !anyEntryExists} + naked + danger + /> + + + ) +} + +LocationForm.propTypes = { + additionalMarkers: PropTypes.markers, + /** Additional fields to be passed as children. */ + children: PropTypes.node, + disabledInfo: PropTypes.message, + entityId: PropTypes.string.isRequired, + /** The title message shown at the top of the form. */ + formTitle: PropTypes.message.isRequired, + initialValues: PropTypes.entityLocation, + noLocationSetInfo: PropTypes.message, + /** The handler for the delete function of the form. */ + onDelete: PropTypes.func.isRequired, + /** The handler for the submit function of the form. */ + onSubmit: PropTypes.func.isRequired, + updatesDisabled: PropTypes.bool, + validationSchema: PropTypes.shape({ + cast: PropTypes.func.isRequired, + }), +} + +LocationForm.defaultProps = { + additionalMarkers: [], + children: null, + disabledInfo: undefined, + initialValues: emptyLocation, + validationSchema, + updatesDisabled: false, + noLocationSetInfo: m.noLocationSetInfo, } export { LocationForm as default, hasLocationSet } diff --git a/pkg/webui/console/components/mac-settings-section/index.js b/pkg/webui/console/components/mac-settings-section/index.js index a8ab98a6d6..0c0260e4d4 100644 --- a/pkg/webui/console/components/mac-settings-section/index.js +++ b/pkg/webui/console/components/mac-settings-section/index.js @@ -40,32 +40,19 @@ import { const m = defineMessages({ delayValue: '{count, plural, one {{count} second} other {{count} seconds}}', factoryPresetFreqDescription: 'List of factory-preset frequencies. Note: order is respected.', - factoryPresetFreqTitle: 'Factory preset frequencies', - freqAdd: 'Add Frequency', - frequencyPlaceholder: 'e.g. 869525000 for 869,525 MHz', advancedMacSettings: 'Advanced MAC settings', - pingSlotFrequencyTitle: 'Ping slot frequency', desiredPingSlotFrequencyTitle: 'Desired ping slot frequency', pingSlotPeriodicityDescription: 'Periodicity of the class B ping slot', - pingSlotPeriodicityTitle: 'Ping slot periodicity', - pingSlotPeriodicityValue: '{count, plural, one {every second} other {every {count} seconds}}', pingSlotDataRateTitle: 'Ping slot data rate index', desiredPingSlotDataRateTitle: 'Desired ping slot data rate', resetWarning: 'Resetting is insecure and makes your device susceptible for replay attacks', - resetsFCnt: 'Resets frame counters', - rx1DataRateOffsetTitle: 'Rx1 data rate offset', desiredRx1DataRateOffsetTitle: 'Desired Rx1 data rate offset', - rx1DelayTitle: 'Rx1 delay', desiredRx1DelayTitle: 'Desired Rx1 delay', rx2DataRateIndexTitle: 'Rx2 data rate index', desiredRx2DataRateIndexTitle: 'Desired Rx2 data rate index', desiredRx2FrequencyTitle: 'Desired Rx2 frequency', - rx2FrequencyTitle: 'Rx2 frequency', updateSuccess: 'The MAC settings updated', - beaconFrequency: 'Beacon frequency', desiredBeaconFrequency: 'Desired beacon frequency', - classBTimeout: 'Class B timeout', - classCTimeout: 'Class C timeout', maxDutyCycle: 'Maximum duty cycle', desiredMaxDutyCycle: 'Desired maximum duty cycle', adrMargin: 'ADR margin', @@ -88,7 +75,7 @@ const pingSlotPeriodicityOptions = Array.from({ length: 8 }, (_, index) => { return { value: `PING_EVERY_${value}S`, - label: , + label: , } }) // 0...15 @@ -189,7 +176,7 @@ const MacSettingsSection = props => { {!isOTAA && ( } @@ -219,7 +206,7 @@ const MacSettingsSection = props => { {!isOTAA && ( { type="number" min={100000} step={100} - title={m.rx2FrequencyTitle} + title={sharedMessages.rx2Frequency} name="mac_settings.rx2_frequency" component={UnitInput.Hertz} tooltipId={tooltipIds.RX2_FREQUENCY} @@ -336,15 +323,15 @@ const MacSettingsSection = props => { indexAsKey name="mac_settings.factory_preset_frequencies" component={KeyValueMap} - title={m.factoryPresetFreqTitle} + title={sharedMessages.factoryPresetFrequencies} description={m.factoryPresetFreqDescription} - addMessage={m.freqAdd} - valuePlaceholder={m.frequencyPlaceholder} + addMessage={sharedMessages.freqAdd} + valuePlaceholder={sharedMessages.frequencyPlaceholder} tooltipId={tooltipIds.FACTORY_PRESET_FREQUENCIES} /> {isClassC && ( { {(isClassB || isMulticast) && ( <> { fieldWidth="xs" /> { { type="number" min={100000} title={m.desiredBeaconFrequency} - placeholder={m.frequencyPlaceholder} + placeholder={sharedMessages.frequencyPlaceholder} name="mac_settings.desired_beacon_frequency" tooltipId={tooltipIds.BEACON_FREQUENCY} component={UnitInput.Hertz} @@ -406,8 +393,8 @@ const MacSettingsSection = props => { type="number" min={100000} step={100} - title={m.pingSlotFrequencyTitle} - placeholder={m.frequencyPlaceholder} + title={sharedMessages.pingSlotFrequency} + placeholder={sharedMessages.frequencyPlaceholder} name="mac_settings.ping_slot_frequency" tooltipId={tooltipIds.PING_SLOT_FREQUENCY} component={UnitInput.Hertz} @@ -420,7 +407,7 @@ const MacSettingsSection = props => { min={100000} step={100} title={m.desiredPingSlotFrequencyTitle} - placeholder={m.frequencyPlaceholder} + placeholder={sharedMessages.frequencyPlaceholder} name="mac_settings.desired_ping_slot_frequency" tooltipId={tooltipIds.PING_SLOT_FREQUENCY} component={UnitInput.Hertz} diff --git a/pkg/webui/console/components/payload-formatters-form/index.js b/pkg/webui/console/components/payload-formatters-form/index.js index 05f015f360..ea7ec8d788 100644 --- a/pkg/webui/console/components/payload-formatters-form/index.js +++ b/pkg/webui/console/components/payload-formatters-form/index.js @@ -47,7 +47,6 @@ import TestForm from './test-form' import style from './payload-formatters-form.styl' const m = defineMessages({ - grpc: 'GRPC service', repository: 'Use Device Repository formatters', customJavascipt: 'Custom Javascript formatter', formatterType: 'Formatter type', @@ -57,7 +56,6 @@ const m = defineMessages({ grpcFieldDescription: 'The address of the service to connect to', appFormatter: 'Use application payload formatter', appFormatterWarning: 'This option will affect both uplink and downlink formatter', - setupSubTitle: 'Setup', defaultFormatter: 'Click here to modify the default payload formatter for this application. The payload formatter of this application is currently set to `{defaultFormatter}`', pasteRepositoryFormatter: 'Paste repository formatter', @@ -80,7 +78,7 @@ const formatterOptions = [ { label: m.appFormatter, value: TYPES.DEFAULT }, { label: m.repository, value: TYPES.REPOSITORY }, { label: m.customJavascipt, value: TYPES.JAVASCRIPT }, - { label: m.grpc, value: TYPES.GRPC }, + { label: sharedMessages.grpcService, value: TYPES.GRPC }, { label: 'CayenneLPP', value: TYPES.CAYENNELPP }, { label: sharedMessages.none, value: TYPES.NONE }, ] @@ -420,7 +418,7 @@ const PayloadFormattersForm = ({ > {() => ( <> - + false, - onDelete: () => null, - } - - constructor(props) { - super(props) - - this.form = React.createRef() - this.modalResolve = () => null - this.modalReject = () => null - - const { initialPubsubValue, update, mqttDisabled, natsDisabled } = this.props - - this.state = { - error: undefined, - mqttDisabled, - provider: blankValues._provider, - mqttUseCredentials: true, - natsUseCredentials: true, - natsDisabled, - displayOverwriteModal: false, - existingId: undefined, +const PubsubForm = props => { + const form = useRef(null) + const modalResolve = useRef(() => {}) + const modalReject = useRef(() => {}) + + const { + initialPubsubValue, + update, + mqttDisabled, + natsDisabled, + appId, + onSubmit, + existCheck, + onDelete, + } = props + const [error, setError] = useState(undefined) + const [provider, setProvider] = useState(blankValues._provider) + const [mqttSecure, setMqttSecure] = useState(true) + const [mqttUseCredentials, setMqttUseCredentials] = useState(true) + const [natsUseCredentials, setNatsUseCredentials] = useState(true) + const [displayOverwriteModal, setDisplayOverwriteModal] = useState(false) + const [existingId, setExistingId] = useState(undefined) + + const initialValues = useMemo(() => { + if (update && initialPubsubValue) { + return mapPubsubToFormValues(initialPubsubValue) + } + return { + ...blankValues, + _provider: provider, } + }, [initialPubsubValue, provider, update]) + useEffect(() => { if (natsDisabled && mqttDisabled) { - this.state.provider = blankValues._provider + setProvider(blankValues._provider) } else { - this.state.provider = natsDisabled ? providers.MQTT : providers.NATS + setProvider(natsDisabled ? providers.MQTT : providers.NATS) } if (update && 'nats' in initialPubsubValue) { const { password, username } = mapNatsFormValues(initialPubsubValue.nats) - this.state.provider = providers.NATS - this.state.natsUseCredentials = Boolean(password || username) + setProvider(providers.NATS) + setNatsUseCredentials(Boolean(password || username)) } else if (update && 'mqtt' in initialPubsubValue) { - this.state.provider = providers.MQTT - this.state.mqttSecure = initialPubsubValue.mqtt.use_tls - this.state.mqttUseCredentials = Boolean( - initialPubsubValue.mqtt.username || initialPubsubValue.mqtt.password, + setProvider(providers.MQTT) + setMqttSecure(initialPubsubValue.mqtt.use_tls) + setMqttUseCredentials( + Boolean(initialPubsubValue.mqtt.username || initialPubsubValue.mqtt.password), ) } - } - - @bind - async handleSubmit(values, { resetForm }) { - const { appId, onSubmit, existCheck, update } = this.props - - const castedValues = validationSchema.cast(values) - const pubsub = mapFormValuesToPubsub(castedValues, appId) - - this.setState({ error: '' }) - - try { - if (!update) { - const pubsubId = pubsub.ids.pub_sub_id - const exists = await existCheck(pubsubId) - if (exists) { - this.setState({ displayOverwriteModal: true, existingId: pubsubId }) - await new Promise((resolve, reject) => { - this.modalResolve = resolve - this.modalReject = reject - }) + }, [initialPubsubValue, mqttDisabled, natsDisabled, update]) + + const handleSubmit = useCallback( + async (values, { resetForm }) => { + const castedValues = validationSchema.cast(values) + const pubsub = mapFormValuesToPubsub(castedValues, appId) + setError('') + + try { + if (!update) { + const pubsubId = pubsub.ids.pub_sub_id + const exists = await existCheck(pubsubId) + if (exists) { + setDisplayOverwriteModal(true) + setExistingId(pubsubId) + await new Promise((resolve, reject) => { + modalResolve.current = resolve + modalReject.current = reject + }) + } } - } - await onSubmit(pubsub) + await onSubmit(pubsub) - resetForm({ values }) - } catch (error) { - resetForm({ values }) - - this.setState({ error }) - } - } + resetForm({ values }) + } catch (error) { + resetForm({ values }) + setError(error) + } + }, + [appId, existCheck, onSubmit, update], + ) - @bind - async handleDelete() { - const { onDelete } = this.props + const handleDelete = useCallback(async () => { try { await onDelete() - this.form.current.resetForm() + form.current.resetForm() } catch (error) { - this.setState({ error }) + setError(error) } - } + }, [onDelete]) - @bind - handleProviderSelect(event) { - this.setState({ provider: event.target.value }) - } + const handleProviderSelect = useCallback(event => { + setProvider(event.target.value) + }, []) - @bind - handleUseCredentialsChangeNats(event) { - this.setState({ natsUseCredentials: event.target.checked }) - } + const handleUseCredentialsChangeNats = useCallback(event => { + setNatsUseCredentials(event.target.checked) + }, []) - @bind - handleMqttUseTlsChange(event) { - this.setState({ mqttSecure: event.target.checked }) - } + const handleMqttUseTlsChange = useCallback(event => { + setMqttSecure(event.target.checked) + }, []) - @bind - handleUseCredentialsChangeMqtt(event) { - this.setState({ mqttUseCredentials: event.target.checked }) - } + const handleUseCredentialsChangeMqtt = useCallback(event => { + setMqttUseCredentials(event.target.checked) + }, []) - @bind - handleReplaceModalDecision(mayReplace) { + const handleReplaceModalDecision = useCallback(mayReplace => { if (mayReplace) { - this.modalResolve() + modalResolve.current() } else { - this.modalReject() + modalReject.current() } - this.setState({ displayOverwriteModal: false }) - } + setDisplayOverwriteModal(false) + }, []) - get natsSection() { - const { natsUseCredentials } = this.state - return ( + const natsSection = useMemo( + () => ( <> @@ -187,7 +173,7 @@ export default class PubsubForm extends Component { name="nats._use_credentials" label={m.useCredentials} component={Checkbox} - onChange={this.handleUseCredentialsChangeNats} + onChange={handleUseCredentialsChangeNats} /> - ) - } + ), + [handleUseCredentialsChangeNats, natsUseCredentials], + ) - get mqttSection() { - const { mqttSecure, mqttUseCredentials } = this.state - - return ( + const mqttSection = useMemo( + () => ( <> {mqttSecure && ( <> @@ -271,14 +256,14 @@ export default class PubsubForm extends Component { )} - ) - } + ), + [handleMqttUseTlsChange, handleUseCredentialsChangeMqtt, mqttSecure, mqttUseCredentials], + ) - get messageTypesSection() { - return ( + const messageTypesSection = useMemo( + () => ( <> @@ -441,93 +427,104 @@ export default class PubsubForm extends Component { description={sharedMessages.eventDownlinkReplaceDesc} /> - ) - } - - render() { - const { update, initialPubsubValue, mqttDisabled, natsDisabled } = this.props - const { error, provider, displayOverwriteModal, existingId } = this.state - let initialValues = blankValues - if (update && initialPubsubValue) { - initialValues = mapPubsubToFormValues(initialPubsubValue) - } - - return ( - <> - ( - - {val} - - ), - }} - component="p" + ), + [], + ) + + return ( + <> + ( + + {val} + + ), + }} + component="p" + /> +
+
+ -
- + + - + + + {provider === providers.NATS && natsSection} + {provider === providers.MQTT && mqttSection} + {messageTypesSection} + + - - - - - - - {provider === providers.NATS && this.natsSection} - {provider === providers.MQTT && this.mqttSection} - {this.messageTypesSection} - - - {update && ( - - )} - - - - ) - } + )} + + + + ) } +PubsubForm.propTypes = { + appId: PropTypes.string.isRequired, + existCheck: PropTypes.func, + initialPubsubValue: PropTypes.pubsub, + mqttDisabled: PropTypes.bool.isRequired, + natsDisabled: PropTypes.bool.isRequired, + onDelete: PropTypes.func, + onSubmit: PropTypes.func.isRequired, + update: PropTypes.bool.isRequired, +} + +PubsubForm.defaultProps = { + initialPubsubValue: undefined, + existCheck: () => false, + onDelete: () => null, +} + +export default PubsubForm diff --git a/pkg/webui/console/components/pubsub-form/messages.js b/pkg/webui/console/components/pubsub-form/messages.js index 0b99afbb3e..81457da324 100644 --- a/pkg/webui/console/components/pubsub-form/messages.js +++ b/pkg/webui/console/components/pubsub-form/messages.js @@ -21,9 +21,6 @@ export default defineMessages({ modalWarning: 'Are you sure you want to delete Pub/Sub "{pubsubId}"? Deleting a Pub/Sub cannot be undone.', headers: 'Headers', - headersKeyPlaceholder: 'Authorization', - headersValuePlaceholder: 'Bearer my-auth-token', - headersAdd: 'Add header entry', headersValidateRequired: 'All header entry values are required. Please remove empty entries.', usernamePlaceholder: 'my-username', passwordPlaceholder: 'my-password', @@ -33,9 +30,8 @@ export default defineMessages({ mqttConfig: 'MQTT configuration', mqttClientIdPlaceholder: 'my-client-id', mqttServerUrlPlaceholder: 'mqtts://example.com', - serverUrl: 'Server URL', - clientId: 'Client ID', subscribeQos: 'Subscribe QoS', + providerDescription: 'Changing the Pub/Sub provider has been disabled by an administrator', publishQos: 'Publish QoS', tlsCa: 'Root CA certificate', tlsClientCert: 'Client certificate', @@ -43,7 +39,6 @@ export default defineMessages({ selectPemFile: 'Select .pem file…', pemFileProvided: '.pem file has been provided', useCredentials: 'Use credentials', - alreadyExistsModalTitle: 'ID already exists', alreadyExistsModalMessage: 'A Pub/Sub with the ID "{id}" already exists. Do you wish to replace this Pub/Sub?', replacePubsub: 'Replace Pub/Sub', diff --git a/pkg/webui/console/components/routing-policy-form/index.js b/pkg/webui/console/components/routing-policy-form/index.js index 8ad08204e7..b000a2f304 100644 --- a/pkg/webui/console/components/routing-policy-form/index.js +++ b/pkg/webui/console/components/routing-policy-form/index.js @@ -37,9 +37,7 @@ import style from './routing-policy-form.styl' const m = defineMessages({ saveDefaultPolicy: 'Save default policy', - useDefaultPolicy: 'Use default routing policy for this network', useSpecificPolicy: 'Use network specific routing policy', - doNotUseADefaultPolicy: 'Do not use a default routing policy for this network', doNotUseAPolicy: 'Do not use a routing policy for this network', }) @@ -53,25 +51,15 @@ const validationSchema = Yup.object({ const policySourceEncode = val => val === 'default' const policySourceDecode = val => (val ? 'default' : 'specific') -const useDefaultEncode = val => val === 'default' -const useDefaultDecode = val => (val ? 'default' : 'no-default') -const RoutingPolicyForm = ({ - onSubmit, - initialValues, - error, - defaultPolicy, - networkLevel, - submitMessage, -}) => { +const RoutingPolicyForm = ({ onSubmit, initialValues, error, defaultPolicy, submitMessage }) => { const handleSubmit = useCallback(values => onSubmit(validationSchema.cast(values)), [onSubmit]) const [useDefault, setUseDefault] = useState(initialValues._use_default_policy || false) const handlePolicySourceChange = useCallback(setUseDefault, [setUseDefault]) const hasDefaultPolicy = isValidPolicy(defaultPolicy) - const showDefaultPolicySheet = networkLevel && useDefault && isValidPolicy(defaultPolicy) - const showPolicyCheckboxes = (useDefault && !networkLevel) || (!useDefault && networkLevel) - + const showDefaultPolicySheet = useDefault && isValidPolicy(defaultPolicy) + const showPolicyCheckboxes = !useDefault return (
- {networkLevel ? ( - - - - - ) : ( - - - - - )} + + + + {showDefaultPolicySheet && ( @@ -132,13 +106,13 @@ const RoutingPolicyForm = ({ @@ -196,14 +170,12 @@ RoutingPolicyForm.propTypes = { _use_default_policy: PropTypes.bool, policy: PropTypes.shape({}), }), - networkLevel: PropTypes.bool, onSubmit: PropTypes.func.isRequired, submitMessage: PropTypes.message, } RoutingPolicyForm.defaultProps = { error: undefined, - networkLevel: false, defaultPolicy: undefined, submitMessage: m.saveDefaultPolicy, initialValues: { diff --git a/pkg/webui/console/components/routing-policy/sheet.js b/pkg/webui/console/components/routing-policy/sheet.js index 010edd2c35..0f6addf5bd 100644 --- a/pkg/webui/console/components/routing-policy/sheet.js +++ b/pkg/webui/console/components/routing-policy/sheet.js @@ -65,13 +65,13 @@ const RoutingPolicySheet = ({ policy }) => { /> @@ -92,19 +92,19 @@ const RoutingPolicySheet = ({ policy }) => { diff --git a/pkg/webui/console/components/uplink-form/connect.js b/pkg/webui/console/components/uplink-form/connect.js deleted file mode 100644 index dac3cdf691..0000000000 --- a/pkg/webui/console/components/uplink-form/connect.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright © 2020 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. - -import { connect } from 'react-redux' - -import tts from '@console/api/tts' - -import { - selectSelectedApplicationId, - selectApplicationLinkSkipPayloadCrypto, -} from '@console/store/selectors/applications' -import { selectSelectedDeviceId, selectSelectedDevice } from '@console/store/selectors/devices' - -const mapStateToProps = state => { - const appId = selectSelectedApplicationId(state) - const devId = selectSelectedDeviceId(state) - const device = selectSelectedDevice(state) - const skipPayloadCrypto = selectApplicationLinkSkipPayloadCrypto(state) - - return { - appId, - devId, - device, - simulateUplink: uplink => tts.Applications.Devices.simulateUplink(appId, devId, uplink), - skipPayloadCrypto, - } -} - -export default UplinkForm => connect(mapStateToProps)(UplinkForm) diff --git a/pkg/webui/console/components/uplink-form/index.js b/pkg/webui/console/components/uplink-form/index.js index ffad4d8f9a..bda4643f75 100644 --- a/pkg/webui/console/components/uplink-form/index.js +++ b/pkg/webui/console/components/uplink-form/index.js @@ -12,9 +12,134 @@ // See the License for the specific language governing permissions and // limitations under the License. -import UplinkForm from './uplink-form' -import connect from './connect' +import React, { useCallback } from 'react' +import { defineMessages } from 'react-intl' +import { useSelector } from 'react-redux' -const ConnectedUplinkForm = connect(UplinkForm) +import tts from '@console/api/tts' -export { ConnectedUplinkForm as default, UplinkForm } +import Notification from '@ttn-lw/components/notification' +import SubmitButton from '@ttn-lw/components/submit-button' +import Input from '@ttn-lw/components/input' +import SubmitBar from '@ttn-lw/components/submit-bar' +import toast from '@ttn-lw/components/toast' +import Form from '@ttn-lw/components/form' + +import IntlHelmet from '@ttn-lw/lib/components/intl-helmet' + +import Yup from '@ttn-lw/lib/yup' +import sharedMessages from '@ttn-lw/lib/shared-messages' + +import { hexToBase64 } from '@console/lib/bytes' + +import { + selectApplicationLinkSkipPayloadCrypto, + selectSelectedApplicationId, +} from '@console/store/selectors/applications' +import { selectSelectedDevice, selectSelectedDeviceId } from '@console/store/selectors/devices' + +const m = defineMessages({ + simulateUplink: 'Simulate uplink', + payloadDescription: 'The desired payload bytes of the uplink message', + uplinkSuccess: 'Uplink sent', +}) + +const validationSchema = Yup.object({ + f_port: Yup.number() + .min(1, Yup.passValues(sharedMessages.validateNumberGte)) + .max(223, Yup.passValues(sharedMessages.validateNumberLte)) + .required(sharedMessages.validateRequired), + frm_payload: Yup.string().test( + 'len', + Yup.passValues(sharedMessages.validateHexLength), + payload => !Boolean(payload) || payload.length % 3 === 0, + ), +}) + +const initialValues = { f_port: 1, frm_payload: '' } + +const UplinkForm = () => { + const [error, setError] = React.useState('') + + const appId = useSelector(selectSelectedApplicationId) + const devId = useSelector(selectSelectedDeviceId) + const device = useSelector(selectSelectedDevice) + const skipPayloadCrypto = useSelector(selectApplicationLinkSkipPayloadCrypto) + + const simulateUplink = useCallback( + async uplink => await tts.Applications.Devices.simulateUplink(appId, devId, uplink), + [appId, devId], + ) + + const handleSubmit = React.useCallback( + async (values, { setSubmitting, resetForm }) => { + try { + await simulateUplink({ + f_port: values.f_port, + frm_payload: hexToBase64(values.frm_payload), + // `rx_metadata` and `settings` fields are required by the validation middleware in AS. + // These fields won't affect the result of simulating an uplink message. + rx_metadata: [ + { gateway_ids: { gateway_id: 'test' }, rssi: 42, channel_rssi: 42, snr: 4.2 }, + ], + settings: { + data_rate: { lora: { bandwidth: 125000, spreading_factor: 7 } }, + frequency: 868000000, + }, + }) + toast({ + title: sharedMessages.success, + type: toast.types.SUCCESS, + message: m.uplinkSuccess, + }) + setSubmitting(false) + } catch (error) { + setError(error) + resetForm({ values }) + } + }, + [simulateUplink], + ) + + const deviceSimulationDisabled = device.skip_payload_crypto_override ?? skipPayloadCrypto + + return ( + <> + {deviceSimulationDisabled && ( + + )} + + + + + + + + + + + ) +} + +export default UplinkForm diff --git a/pkg/webui/console/components/uplink-form/uplink-form.js b/pkg/webui/console/components/uplink-form/uplink-form.js deleted file mode 100644 index 827bfca706..0000000000 --- a/pkg/webui/console/components/uplink-form/uplink-form.js +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright © 2020 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. - -import React from 'react' -import { defineMessages } from 'react-intl' - -import Notification from '@ttn-lw/components/notification' -import SubmitButton from '@ttn-lw/components/submit-button' -import Input from '@ttn-lw/components/input' -import SubmitBar from '@ttn-lw/components/submit-bar' -import toast from '@ttn-lw/components/toast' -import Form from '@ttn-lw/components/form' - -import IntlHelmet from '@ttn-lw/lib/components/intl-helmet' - -import Yup from '@ttn-lw/lib/yup' -import PropTypes from '@ttn-lw/lib/prop-types' -import sharedMessages from '@ttn-lw/lib/shared-messages' - -import { hexToBase64 } from '@console/lib/bytes' - -const m = defineMessages({ - simulateUplink: 'Simulate uplink', - payloadDescription: 'The desired payload bytes of the uplink message', - uplinkSuccess: 'Uplink sent', -}) - -const validationSchema = Yup.object({ - f_port: Yup.number() - .min(1, Yup.passValues(sharedMessages.validateNumberGte)) - .max(223, Yup.passValues(sharedMessages.validateNumberLte)) - .required(sharedMessages.validateRequired), - frm_payload: Yup.string().test( - 'len', - Yup.passValues(sharedMessages.validateHexLength), - payload => !Boolean(payload) || payload.length % 3 === 0, - ), -}) - -const initialValues = { f_port: 1, frm_payload: '' } - -const UplinkForm = props => { - const { simulateUplink, device, skipPayloadCrypto } = props - - const [error, setError] = React.useState('') - - const handleSubmit = React.useCallback( - async (values, { setSubmitting, resetForm }) => { - try { - await simulateUplink({ - f_port: values.f_port, - frm_payload: hexToBase64(values.frm_payload), - // `rx_metadata` and `settings` fields are required by the validation middleware in AS. - // These fields won't affect the result of simulating an uplink message. - rx_metadata: [ - { gateway_ids: { gateway_id: 'test' }, rssi: 42, channel_rssi: 42, snr: 4.2 }, - ], - settings: { - data_rate: { lora: { bandwidth: 125000, spreading_factor: 7 } }, - frequency: 868000000, - }, - }) - toast({ - title: sharedMessages.success, - type: toast.types.SUCCESS, - message: m.uplinkSuccess, - }) - setSubmitting(false) - } catch (error) { - setError(error) - resetForm({ values }) - } - }, - [simulateUplink], - ) - - const deviceSimulationDisabled = device.skip_payload_crypto_override ?? skipPayloadCrypto - - return ( - <> - {deviceSimulationDisabled && ( - - )} - -
- - - - - - - - - ) -} - -UplinkForm.propTypes = { - device: PropTypes.device.isRequired, - simulateUplink: PropTypes.func.isRequired, - skipPayloadCrypto: PropTypes.bool, -} - -UplinkForm.defaultProps = { - skipPayloadCrypto: false, -} - -export default UplinkForm diff --git a/pkg/webui/console/components/webhook-form/index.js b/pkg/webui/console/components/webhook-form/index.js index 4fa389e191..8960f872c7 100644 --- a/pkg/webui/console/components/webhook-form/index.js +++ b/pkg/webui/console/components/webhook-form/index.js @@ -1,4 +1,4 @@ -// Copyright © 2021 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -12,9 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { Component } from 'react' +import React, { useCallback, useRef, useState } from 'react' import { defineMessages, FormattedRelativeTime } from 'react-intl' -import bind from 'autobind-decorator' import { uniq } from 'lodash' import tts from '@console/api/tts' @@ -70,9 +69,6 @@ const m = defineMessages({ modalWarning: 'Are you sure you want to delete webhook "{webhookId}"? Deleting a webhook cannot be undone.', additionalHeaders: 'Additional headers', - headersKeyPlaceholder: 'Authorization', - headersValuePlaceholder: 'Bearer my-auth-token', - headersAdd: 'Add header entry', downlinkAPIKey: 'Downlink API key', downlinkAPIKeyDesc: 'The API key will be provided to the endpoint using the "X-Downlink-Apikey" header', @@ -236,120 +232,97 @@ const validationSchema = Yup.object().shape({ .nullable(), }) -export default class WebhookForm extends Component { - static propTypes = { - error: PropTypes.error, - existCheck: PropTypes.func, - hasUnhealthyWebhookConfig: PropTypes.bool, - healthStatusEnabled: PropTypes.bool, - initialWebhookValue: PropTypes.shape({ - ids: PropTypes.shape({ - webhook_id: PropTypes.string, - }), - health_status: PropTypes.shape({ - healthy: PropTypes.shape({}), - unhealthy: PropTypes.shape({}), - }), - headers: PropTypes.shape({ - Authorization: PropTypes.string, - }), - }), - onDelete: PropTypes.func, - onDeleteFailure: PropTypes.func, - onDeleteSuccess: PropTypes.func, - onReactivate: PropTypes.func, - onReactivateSuccess: PropTypes.func, - onSubmit: PropTypes.func.isRequired, - update: PropTypes.bool.isRequired, - webhookRetryInterval: PropTypes.string, - webhookTemplate: PropTypes.webhookTemplate, +const WebhookForm = props => { + const { + update, + initialWebhookValue, + webhookTemplate, + healthStatusEnabled, + webhookRetryInterval, + hasUnhealthyWebhookConfig, + error: propsError, + existCheck, + onSubmit, + onDelete, + onDeleteSuccess, + onDeleteFailure, + onReactivate, + onReactivateSuccess, + } = props + + const form = useRef(null) + const modalResolve = useRef(() => {}) + const modalReject = useRef(() => {}) + const [shouldShowCredentialsInput, setShouldShowCredentialsInput] = useState( + Boolean(initialWebhookValue?.headers?.Authorization?.startsWith('Basic ')) && + Boolean(!decodeValues(initialWebhookValue)._headers.find(i => i.decodeError)?.decodeError), + ) + const [showDecodeError, setShowDecodeError] = useState( + Boolean(decodeValues(initialWebhookValue)._headers.find(i => i.decodeError)?.decodeError), + ) + const [displayOverwriteModal, setDisplayOverwriteModal] = useState(false) + const [existingId, setExistingId] = useState(undefined) + const [error, setError] = useState(undefined) + + const retryIntervalValue = webhookRetryInterval?.match(durationRegExp)[0] + const retryIntervalUnit = webhookRetryInterval?.match(durationRegExp)[1] + const retryIntervalIntlUnit = units[retryIntervalUnit] + + let initialValues = blankValues + if (update && initialWebhookValue) { + initialValues = decodeValues({ ...blankValues, ...initialWebhookValue }) } - static defaultProps = { - initialWebhookValue: undefined, - onReactivate: () => null, - onReactivateSuccess: () => null, - onDeleteFailure: () => null, - onDeleteSuccess: () => null, - onDelete: () => null, - webhookTemplate: undefined, - healthStatusEnabled: false, - error: undefined, - existCheck: () => null, - webhookRetryInterval: null, - hasUnhealthyWebhookConfig: false, - } + const hasTemplate = Boolean(webhookTemplate) - form = React.createRef() - - modalResolve = () => null - modalReject = () => null - - constructor(props) { - super(props) - const { initialWebhookValue } = this.props - - this.state = { - shouldShowCredentialsInput: - Boolean(initialWebhookValue?.headers?.Authorization?.startsWith('Basic ')) && - Boolean(!decodeValues(initialWebhookValue)._headers.find(i => i.decodeError)?.decodeError), - showDecodeError: Boolean( - decodeValues(initialWebhookValue)._headers.find(i => i.decodeError)?.decodeError, - ), - displayOverwriteModal: false, - existingId: undefined, - error: undefined, - } - } + const healthStatus = initialWebhookValue?.health_status + const mayReactivate = update && hasUnhealthyWebhookConfig && healthStatus?.unhealthy + const isPending = update && healthStatusEnabled && !healthStatus - @bind - handleReplaceModalDecision(mayReplace) { + const handleReplaceModalDecision = useCallback(mayReplace => { if (mayReplace) { - this.modalResolve() + modalResolve.current() } else { - this.modalReject() - } - this.setState({ displayOverwriteModal: false }) - } - - @bind - async handleSubmit(values, { setSubmitting, resetForm }) { - const { onSubmit, existCheck } = this.props - const castedWebhookValues = validationSchema.cast(values) - const encodedValues = encodeValues(castedWebhookValues) - const webhookId = encodedValues.ids.webhook_id - const exists = await existCheck(webhookId) - this.setState({ - showDecodeError: Boolean( - decodeValues(encodedValues)._headers.find(i => i.decodeError)?.decodeError, - ), - }) - if (exists) { - this.setState({ displayOverwriteModal: true, existingId: webhookId }) - await new Promise((resolve, reject) => { - this.modalResolve = resolve - this.modalReject = reject - }) + modalReject.current() } - await onSubmit(castedWebhookValues, encodedValues, { setSubmitting, resetForm }) - } + setDisplayOverwriteModal(false) + }, []) + + const handleSubmit = useCallback( + async (values, { setSubmitting, resetForm }) => { + const castedWebhookValues = validationSchema.cast(values) + const encodedValues = encodeValues(castedWebhookValues) + const webhookId = encodedValues.ids.webhook_id + const exists = await existCheck(webhookId) + setShowDecodeError( + Boolean(decodeValues(encodedValues)._headers.find(i => i.decodeError)?.decodeError), + ) - @bind - async handleDelete() { - const { onDelete, onDeleteSuccess, onDeleteFailure } = this.props + if (exists) { + setDisplayOverwriteModal(true) + setExistingId(webhookId) + await new Promise((resolve, reject) => { + modalResolve.current = resolve + modalReject.current = reject + }) + } + await onSubmit(castedWebhookValues, encodedValues, { setSubmitting, resetForm }) + }, + [existCheck, onSubmit], + ) + + const handleDelete = useCallback(async () => { try { await onDelete() - this.form.current.resetForm() + form.current.resetForm() onDeleteSuccess() } catch (error) { - this.setState({ error }) + setError(error) onDeleteFailure() } - } + }, [onDelete, onDeleteFailure, onDeleteSuccess]) - @bind - async handleReactivate() { - const { onReactivate, onReactivateSuccess } = this.props + const handleReactivate = useCallback(async () => { const healthStatus = { health_status: null, } @@ -358,342 +331,356 @@ export default class WebhookForm extends Component { await onReactivate(healthStatus) onReactivateSuccess() } catch (error) { - this.setState({ error }) + setError(error) } - } + }, [onReactivate, onReactivateSuccess]) - @bind - handleRequestAuthenticationChange(event) { - const currentHeaders = this.form.current.values._headers + const handleRequestAuthenticationChange = useCallback(event => { + const currentHeaders = form.current.values._headers if (!event.target.checked) { - this.form.current.setFieldValue( + form.current.setFieldValue( '_headers', currentHeaders.filter(i => !i.readOnly), ) } else { - this.form.current.setFieldValue('_headers', [ + form.current.setFieldValue('_headers', [ { key: 'Authorization', value: 'Basic ...', readOnly: true }, ]) } - this.setState({ shouldShowCredentialsInput: event.target.checked }) - } - - @bind - handleHeadersChange() { - this.setState({ showDecodeError: !hasNoEmptyEntry }) - } - - render() { - const { - update, - initialWebhookValue, - webhookTemplate, - healthStatusEnabled, - webhookRetryInterval, - hasUnhealthyWebhookConfig, - error, - } = this.props - - const retryIntervalValue = webhookRetryInterval?.match(durationRegExp)[0] - const retryIntervalUnit = webhookRetryInterval?.match(durationRegExp)[1] - const retryIntervalIntlUnit = units[retryIntervalUnit] - - let initialValues = blankValues - if (update && initialWebhookValue) { - initialValues = decodeValues({ ...blankValues, ...initialWebhookValue }) - } - - const hasTemplate = Boolean(webhookTemplate) - - const healthStatus = initialWebhookValue?.health_status - const mayReactivate = update && hasUnhealthyWebhookConfig && healthStatus?.unhealthy - const isPending = update && healthStatusEnabled && !healthStatus - - return ( - <> - {!hasTemplate && ( - <> - ( - - {val} - - ), - }} - component="p" + setShouldShowCredentialsInput(event.target.checked) + }, []) + + const handleHeadersChange = useCallback(() => { + setShowDecodeError(!hasNoEmptyEntry) + }, []) + + return ( + <> + {!hasTemplate && ( + <> + ( + + {val} + + ), + }} + component="p" + /> +
+ + )} + {mayReactivate && ( + + ), + }} + children={ +
{registerEnabled && ( )} - {registered && ( -
- {info.forwarder_enabled ? ( - - - - - ) : ( - - - - - )} - {info.home_network_enabled ? ( - - - - - ) : ( - - - - - )} -
- )} { {registered && ( <> - + - - - - - - - - + + + + } /> + + )} diff --git a/pkg/webui/console/views/admin-packet-broker/default-gateway-visibility.js b/pkg/webui/console/views/admin-packet-broker/default-gateway-visibility.js index ce1703ca42..1591346e9b 100644 --- a/pkg/webui/console/views/admin-packet-broker/default-gateway-visibility.js +++ b/pkg/webui/console/views/admin-packet-broker/default-gateway-visibility.js @@ -19,12 +19,16 @@ import { useSelector, useDispatch } from 'react-redux' import toast from '@ttn-lw/components/toast' import Message from '@ttn-lw/lib/components/message' +import RequireRequest from '@ttn-lw/lib/components/require-request' import GatewayVisibilityForm from '@console/components/gateway-visibility-form' import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' -import { setHomeNetworkDefaultGatewayVisibility } from '@console/store/actions/packet-broker' +import { + getHomeNetworkDefaultGatewayVisibility, + setHomeNetworkDefaultGatewayVisibility, +} from '@console/store/actions/packet-broker' import { selectHomeNetworkDefaultGatewayVisibility } from '@console/store/selectors/packet-broker' @@ -55,18 +59,20 @@ const DefaultGatewayVisibilityView = () => { ) return ( - - - - + + + + + + ) } diff --git a/pkg/webui/console/views/admin-packet-broker/default-routing-policy.js b/pkg/webui/console/views/admin-packet-broker/default-routing-policy.js index 7bfbb9bb44..63e4c4dc72 100644 --- a/pkg/webui/console/views/admin-packet-broker/default-routing-policy.js +++ b/pkg/webui/console/views/admin-packet-broker/default-routing-policy.js @@ -12,72 +12,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useCallback, useState } from 'react' +import React from 'react' import { Col } from 'react-grid-system' -import { useSelector, useDispatch } from 'react-redux' - -import toast from '@ttn-lw/components/toast' import Message from '@ttn-lw/lib/components/message' -import RoutingPolicyForm from '@console/components/routing-policy-form' - -import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' - -import { isValidPolicy } from '@console/lib/packet-broker/utils' - -import { - setHomeNetworkDefaultRoutingPolicy, - deleteHomeNetworkDefaultRoutingPolicy, -} from '@console/store/actions/packet-broker' - -import { selectHomeNetworkDefaultRoutingPolicy } from '@console/store/selectors/packet-broker' +import DefaultRoutingPolicyForm from '@console/components/default-routing-policy-form' import m from './messages' import style from './admin-packet-broker.styl' -const DefaultRoutingPolicyView = () => { - const dispatch = useDispatch() - const defaultRoutingPolicy = useSelector(selectHomeNetworkDefaultRoutingPolicy) - const initialValues = { _use_default_policy: isValidPolicy(defaultRoutingPolicy) } - initialValues.policy = initialValues._use_default_policy - ? defaultRoutingPolicy - : { uplink: {}, downlink: {} } - const [formError, setFormError] = useState(undefined) - const handleDefaultRoutingPolicySubmit = useCallback( - async ({ _use_default_policy, policy }) => { - try { - if (_use_default_policy) { - await dispatch(attachPromise(setHomeNetworkDefaultRoutingPolicy(policy))) - } else { - await dispatch(attachPromise(deleteHomeNetworkDefaultRoutingPolicy())) - } - toast({ - message: m.defaultRoutingPolicySet, - type: toast.types.SUCCESS, - }) - } catch (error) { - setFormError(error) - } - }, - [dispatch, setFormError], - ) - - return ( - - - - - ) -} +const DefaultRoutingPolicyView = () => ( + + + + +) export default DefaultRoutingPolicyView diff --git a/pkg/webui/console/views/admin-packet-broker/index.js b/pkg/webui/console/views/admin-packet-broker/index.js index e5054a38b8..825c6a7ac5 100644 --- a/pkg/webui/console/views/admin-packet-broker/index.js +++ b/pkg/webui/console/views/admin-packet-broker/index.js @@ -36,7 +36,10 @@ import NetworkRoutingPolicy from './network-routing-policy' const PacketBrokerRouter = () => { useBreadcrumbs( 'admin-panel.packet-broker', - , + , ) return ( @@ -44,7 +47,7 @@ const PacketBrokerRouter = () => { enabled', - homeNetworkDisabled: 'Home network disabled', - forwarderEnabled: 'Forwarder enabled', - forwarderDisabled: 'Forwarder disabled', - listNetwork: 'List network publicly', + listNetwork: 'List my network in Packet Broker publicly', listNetworkDesc: - 'Listing your network allows other network administrators to see your network. This allows them to easily configure routing policies with your network.', + 'Public listing will make it easier for other network operators to set up routing policies for your network. Hence public listing is generally recommended.', unlistNetwork: 'Unlist this network', confirmUnlist: 'Confirm unlist', unlistModal: @@ -42,11 +41,9 @@ export default defineMessages({ 'This will hide your network. Other network administrators will not be able to see your network to configure routing policies.', routingPolicyInformation: 'You can use the checkboxes below to control the default forwarding behavior of your network. You can additionally set up individual per-network routing policies via the Networks tab.', - defaultRoutingPolicySet: 'Default routing policy set', + defaultRoutingPolicySet: 'Default routing configuration set', routingPolicySet: 'Routing policy set', defaultRoutingPolicy: 'Default routing policy', - networks: 'Networks', - networkInformation: 'Network information', devAddressBlock: 'Device address block', devAddressBlocks: 'Device address blocks', lastPolicyChange: 'Last policy change', diff --git a/pkg/webui/console/views/admin-packet-broker/network-routing-policies.js b/pkg/webui/console/views/admin-packet-broker/network-routing-policies.js index 2ae67cfebf..d3799fc100 100644 --- a/pkg/webui/console/views/admin-packet-broker/network-routing-policies.js +++ b/pkg/webui/console/views/admin-packet-broker/network-routing-policies.js @@ -19,12 +19,15 @@ import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' import PacketBrokerNetworksTable from '@console/containers/packet-broker-networks-table' -import m from './messages' +import sharedMessages from '@ttn-lw/lib/shared-messages' const NetworkRoutingPoliciesView = () => { useBreadcrumbs( - 'admin-panel.packet-broker.networks', - , + 'admin-panel.packet-broker.routing-configuration.networks', + , ) return diff --git a/pkg/webui/console/views/admin-packet-broker/network-routing-policy.js b/pkg/webui/console/views/admin-packet-broker/network-routing-policy.js index c7384648f8..6f74b047ac 100644 --- a/pkg/webui/console/views/admin-packet-broker/network-routing-policy.js +++ b/pkg/webui/console/views/admin-packet-broker/network-routing-policy.js @@ -73,11 +73,16 @@ const NetworkRoutingPolicyViewInner = () => { const defaultRoutingPolicy = useSelector(selectHomeNetworkDefaultRoutingPolicy) useBreadcrumbs( - 'admin-panel.packet-broker.networks.single', + 'admin-panel.packet-broker.routing-configuration.networks.single', <> - + , @@ -120,7 +125,7 @@ const NetworkRoutingPolicyViewInner = () => { const homeNetworkData = [ { - header: m.networkInformation, + header: sharedMessages.networkInformation, items: [ { key: m.networkId, @@ -160,7 +165,11 @@ const NetworkRoutingPolicyViewInner = () => { - + @@ -228,7 +237,10 @@ const NetworkRoutingPolicyView = () => { const registered = useSelector(selectRegistered) return ( - + + isEqual(policy.uplink, fullyPermissiveNetworkPolicy.uplink) && + isEqual(policy.downlink, fullyPermissiveNetworkPolicy.downlink) + +const onlyTtn = policies => + Object.keys(policies).length === 1 && Object.keys(policies).includes(`${TTN_NET_ID}/ttn`) + +const RoutingConfigurationView = () => { + const dispatch = useDispatch() + const [activeTab, setActiveTab] = useState('default-routing-policy') + const tabs = [ + { + title: m.defaultRoutingPolicy, + link: '/admin-panel/packet-broker/routing-configuration', + name: 'default', + }, + { + title: sharedMessages.networks, + link: '/admin-panel/packet-broker/routing-configuration/networks', + name: 'networks', + exact: false, + }, + ] + + const defaultRoutingPolicy = useSelector(selectHomeNetworkDefaultRoutingPolicy) + const routingPolicies = useSelector(selectPacketBrokerHomeNetworkPoliciesStore) + + const initialValues = { + _routing_configuration: + peerWithEveryNetwork(defaultRoutingPolicy) && + Object.keys(routingPolicies).length === 0 && + isValidPolicy(defaultRoutingPolicy) + ? 'all_networks' + : onlyTtn(routingPolicies) && !isValidPolicy(defaultRoutingPolicy) + ? 'ttn' + : 'custom', + _use_default_policy: isValidPolicy(defaultRoutingPolicy), + } + initialValues.policy = isValidPolicy(defaultRoutingPolicy) + ? defaultRoutingPolicy + : { uplink: {}, downlink: {} } + + const [routingConfig, setRoutingConfig] = useState(undefined) + const [formError, setFormError] = useState(undefined) + + const handleDefaultRoutingPolicySubmit = useCallback( + async values => { + const vals = validationSchema.cast(values) + const { _routing_configuration, _use_default_policy, policy } = vals + const ids = Object.keys(routingPolicies) + + try { + if (_routing_configuration === 'ttn') { + await dispatch(attachPromise(deleteHomeNetworkDefaultRoutingPolicy())) + await dispatch(attachPromise(deleteAllHomeNetworkRoutingPolicies(ids))) + await dispatch(attachPromise(setHomeNetworkRoutingPolicy(`${TTN_NET_ID}/ttn`, policy))) + } else if (_routing_configuration === 'all_networks') { + await dispatch(attachPromise(deleteAllHomeNetworkRoutingPolicies(ids))) + await dispatch(attachPromise(setHomeNetworkDefaultRoutingPolicy(policy))) + } else if (_routing_configuration === 'custom' && _use_default_policy) { + await dispatch(attachPromise(setHomeNetworkDefaultRoutingPolicy(policy))) + } else if (_routing_configuration === 'custom' && !_use_default_policy) { + await dispatch(attachPromise(deleteHomeNetworkDefaultRoutingPolicy())) + } + + toast({ + message: m.defaultRoutingPolicySet, + type: toast.types.SUCCESS, + }) + } catch (error) { + setFormError(error) + } + }, + [dispatch, setFormError, routingPolicies], + ) + + const handleRoutingConfigChange = useCallback( + value => { + setRoutingConfig(value) + }, + [setRoutingConfig], + ) + + const handleSetPolicies = useCallback(({ setValues }, { value }) => { + if (value !== 'custom') { + return setValues(values => ({ + ...values, + _routing_configuration: value, + policy: fullyPermissiveNetworkPolicy, + })) + } + + return setValues(values => ({ + ...values, + _routing_configuration: value, + })) + }, []) + + const showPolicyCheckboxes = routingConfig + ? routingConfig === 'custom' + : initialValues._routing_configuration === 'custom' + + return ( + +
+ + + + + + {showPolicyCheckboxes && ( + <> + + + + + + + + )} + + + + +
+ ) +} + +export default RoutingConfigurationView diff --git a/pkg/webui/console/views/admin-panel-network-information/index.js b/pkg/webui/console/views/admin-panel-network-information/index.js index 64ad3e9617..9f01c14f0a 100644 --- a/pkg/webui/console/views/admin-panel-network-information/index.js +++ b/pkg/webui/console/views/admin-panel-network-information/index.js @@ -13,7 +13,6 @@ // limitations under the License. import React from 'react' -import { defineMessages } from 'react-intl' import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' import { useBreadcrumbs } from '@ttn-lw/components/breadcrumbs/context' @@ -24,19 +23,20 @@ import RequireRequest from '@ttn-lw/lib/components/require-request' import NetworkInformationContainer from '@console/containers/network-information-container' import DeploymentComponentStatus from '@console/containers/deployment-component-status' +import sharedMessages from '@ttn-lw/lib/shared-messages' + import { getApplicationsList } from '@console/store/actions/applications' import { getGatewaysList } from '@console/store/actions/gateways' import { getUsersList } from '@console/store/actions/users' import { getOrganizationsList } from '@console/store/actions/organizations' -const m = defineMessages({ - title: 'Network information', -}) - const NetworkInformation = () => { useBreadcrumbs( 'admin-panel.network-information', - , + , ) const requestActions = [ @@ -49,7 +49,7 @@ const NetworkInformation = () => { return ( <> - + diff --git a/pkg/webui/console/views/admin-panel/index.js b/pkg/webui/console/views/admin-panel/index.js index 3f87065112..fd2d130793 100644 --- a/pkg/webui/console/views/admin-panel/index.js +++ b/pkg/webui/console/views/admin-panel/index.js @@ -30,6 +30,8 @@ import UserManagement from '@console/views/admin-user-management' import PacketBrokerRouter from '@console/views/admin-packet-broker' import NetworkInformation from '@console/views/admin-panel-network-information' +import sharedMessages from '@ttn-lw/lib/shared-messages' + import { checkFromState, mayConfigurePacketBroker, @@ -38,25 +40,26 @@ import { } from '@console/lib/feature-checks' const m = defineMessages({ - adminPanel: 'Admin panel', - networkInformation: 'Network information', userManagement: 'User management', globalNetworkSettings: 'Global network settings', peeringSettings: 'Peering settings', }) const AdminPanel = () => { - useBreadcrumbs('admin-panel', ) + useBreadcrumbs( + 'admin-panel', + , + ) const showUserManagement = useSelector(state => checkFromState(mayManageUsers, state)) const showPacketBroker = useSelector(state => checkFromState(mayConfigurePacketBroker, state)) return ( - + } /> +const getScrollRestorationKey = location => { + // Preserve scroll position only when necessary. + // E.g. we don't want to scroll to top when changing tabs of a table, + // but we do want to scroll to top when changing pages. + const { pathname, search } = location + const params = new URLSearchParams(search) + const page = params.get('page') + + return `${pathname}${page ? `?page=${page}` : ''}` +} const Layout = () => { const user = useSelector(selectUser) @@ -70,7 +86,7 @@ const Layout = () => { return ( <> - +
{ const { appId } = useParams() @@ -42,7 +37,7 @@ const ApplicationData = () => { useBreadcrumbs( 'apps.single.data', - , + , ) return ( @@ -50,7 +45,7 @@ const ApplicationData = () => { featureCheck={mayViewApplicationEvents} otherwise={{ redirect: `/applications/${appId}` }} > - + ) diff --git a/pkg/webui/console/views/application-integrations-lora-cloud/index.js b/pkg/webui/console/views/application-integrations-lora-cloud/index.js index 96500d7a8c..07a4ce3994 100644 --- a/pkg/webui/console/views/application-integrations-lora-cloud/index.js +++ b/pkg/webui/console/views/application-integrations-lora-cloud/index.js @@ -1,4 +1,4 @@ -// Copyright © 2020 The Things Network Foundation, The Things Industries B.V. +// Copyright © 2023 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. @@ -23,7 +23,7 @@ import LoRaCloudImage from '@assets/misc/lora-cloud.png' import PageTitle from '@ttn-lw/components/page-title' import Breadcrumb from '@ttn-lw/components/breadcrumbs/breadcrumb' -import { useBreadcrumbs, withBreadcrumb } from '@ttn-lw/components/breadcrumbs/context' +import { useBreadcrumbs } from '@ttn-lw/components/breadcrumbs/context' import Link from '@ttn-lw/components/link' import Collapse from '@ttn-lw/components/collapse' @@ -52,7 +52,6 @@ const m = defineMessages({ loraCloudInfoText: 'Lora Cloud provides value added APIs that enable simple solutions for common tasks related to LoRaWAN networks and LoRa-based devices. You can setup our LoRaCloud integrations below.', officialLoRaCloudDocumentation: 'Official LoRa Cloud documentation', - setToken: 'Set LoRa Cloud token', dasDescription: 'With the LoRa Cloud Modem and Geolocation Services protocol, you can manage common device functionality at the application layer for LoRaWAN-enabled devices.', glsDescription: @@ -108,11 +107,11 @@ const LoRaCloud = () => {

- + - + @@ -124,13 +123,4 @@ const LoRaCloud = () => { ) } -export default withBreadcrumb('apps.single.integrations.lora-cloud', props => { - const { appId } = props - - return ( - - ) -})(LoRaCloud) +export default LoRaCloud diff --git a/pkg/webui/console/views/application-integrations-webhook-edit/index.js b/pkg/webui/console/views/application-integrations-webhook-edit/index.js index 5de814e94a..99ce00d393 100644 --- a/pkg/webui/console/views/application-integrations-webhook-edit/index.js +++ b/pkg/webui/console/views/application-integrations-webhook-edit/index.js @@ -14,7 +14,6 @@ import React from 'react' import { Container, Col, Row } from 'react-grid-system' -import { defineMessages } from 'react-intl' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' @@ -39,13 +38,6 @@ import { selectWebhookHasUnhealthyConfig, } from '@console/store/selectors/application-server' -const m = defineMessages({ - editWebhook: 'Edit webhook', - updateSuccess: 'Webhook updated', - deleteSuccess: 'Webhook deleted', - reactivateSuccess: 'Webhook activated', -}) - const ApplicationWebhookEditInner = () => { const { appId, webhookId } = useParams() const healthStatusEnabled = useSelector(selectWebhooksHealthStatusEnabled) @@ -64,7 +56,11 @@ const ApplicationWebhookEditInner = () => { return ( - +
{ useBreadcrumbs('apps', ) return ( - - - - } - /> - - + + + + + } + /> + + + ) } -export default withFeatureRequirement(mayViewApplications, { redirect: '/' })(Applications) +export default Applications diff --git a/pkg/webui/console/views/device-general-settings/join-server-form/index.js b/pkg/webui/console/views/device-general-settings/join-server-form/index.js index 48bdc9eae6..2c5f8a06c8 100644 --- a/pkg/webui/console/views/device-general-settings/join-server-form/index.js +++ b/pkg/webui/console/views/device-general-settings/join-server-form/index.js @@ -13,6 +13,7 @@ // limitations under the License. import React from 'react' +import { useDispatch } from 'react-redux' import SubmitButton from '@ttn-lw/components/submit-button' import SubmitBar from '@ttn-lw/components/submit-bar' @@ -29,6 +30,7 @@ import tooltipIds from '@ttn-lw/lib/constants/tooltip-ids' import diff from '@ttn-lw/lib/diff' import PropTypes from '@ttn-lw/lib/prop-types' import sharedMessages from '@ttn-lw/lib/shared-messages' +import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' import { parseLorawanMacVersion, generate16BytesKey } from '@console/lib/device-utils' @@ -79,9 +81,12 @@ const JoinServerForm = React.memo(props => { [device, validationContext], ) + const dispatch = useDispatch() + const appId = device.ids.application_ids.application_id + const devId = device.ids.device_id const handleUsedDevNoncesReset = React.useCallback(async () => { try { - await onUsedDevNoncesReset() + await dispatch(attachPromise(onUsedDevNoncesReset(appId, devId))) toast({ message: messages.resetSuccess, type: toast.types.SUCCESS, @@ -92,7 +97,7 @@ const JoinServerForm = React.memo(props => { type: toast.types.ERROR, }) } - }, [onUsedDevNoncesReset]) + }, [onUsedDevNoncesReset, appId, devId, dispatch]) // Setup and memoize callbacks for changes to `resets_join_nonces` for displaying the field warning. const handleResetsJoinNoncesChange = React.useCallback( diff --git a/pkg/webui/console/views/device-general-settings/messages.js b/pkg/webui/console/views/device-general-settings/messages.js index cff0c8f524..2059e366e0 100644 --- a/pkg/webui/console/views/device-general-settings/messages.js +++ b/pkg/webui/console/views/device-general-settings/messages.js @@ -38,10 +38,6 @@ const messages = defineMessages({ 'You do not have sufficient rights to view end device keys. Only overwriting is allowed.', unclaimFailure: 'An error occurred and the end device could not be unclaimed and deleted', validateSessionKey: '{field} must have non-zero value', - macSettingsError: - 'There was an error and the default MAC settings for the {freqPlan} frequency plan could not be loaded', - fpNotFoundError: - 'The LoRaWAN version {lorawanVersion} does not support the {freqPlan} frequency plan. Please choose a different MAC version or frequency plan.', resetUsedDevNonces: 'Reset used DevNonces', resetUsedDevNoncesModal: 'Are you sure you want to reset the used DevNonces of this end device?{break}{break}Resetting the used DevNonces enables replay attacks using past nonces. Do not use this option unless you have reset the end device NVRAM.', diff --git a/pkg/webui/console/views/device-general-settings/network-server-form/index.js b/pkg/webui/console/views/device-general-settings/network-server-form/index.js index 688cb93ffc..9ef64b2298 100644 --- a/pkg/webui/console/views/device-general-settings/network-server-form/index.js +++ b/pkg/webui/console/views/device-general-settings/network-server-form/index.js @@ -14,6 +14,7 @@ import React from 'react' import { defineMessages } from 'react-intl' +import { useDispatch } from 'react-redux' import Link from '@ttn-lw/components/link' import ModalButton from '@ttn-lw/components/button/modal-button' @@ -40,6 +41,7 @@ import { isBackend, getBackendErrorName } from '@ttn-lw/lib/errors/utils' import diff from '@ttn-lw/lib/diff' import sharedMessages from '@ttn-lw/lib/shared-messages' import PropTypes from '@ttn-lw/lib/prop-types' +import attachPromise from '@ttn-lw/lib/store/actions/attach-promise' import { parseLorawanMacVersion, @@ -173,7 +175,7 @@ const NetworkServerForm = React.memo(props => { if (isBackend(err) && getBackendErrorName(err) === 'no_band_version') { toast({ type: toast.types.ERROR, - message: messages.fpNotFoundError, + message: sharedMessages.fpNotFoundError, messageValues: { lorawanVersion, freqPlan, @@ -229,9 +231,13 @@ const NetworkServerForm = React.memo(props => { ), [device, initialActivationMode, isClassB, isClassC, macSettings, validationContext], ) + + const dispatch = useDispatch() + const appId = device.ids.application_ids.application_id + const devId = device.ids.device_id const handleMacReset = React.useCallback(async () => { try { - await onMacReset() + await dispatch(attachPromise(onMacReset(appId, devId))) toast({ message: m.resetSuccess, type: toast.types.SUCCESS, @@ -242,7 +248,7 @@ const NetworkServerForm = React.memo(props => { type: toast.types.ERROR, }) } - }, [onMacReset]) + }, [onMacReset, dispatch, devId, appId]) const handleSubmit = React.useCallback( async (values, { resetForm, setSubmitting }) => { diff --git a/pkg/webui/console/views/device-overview/index.js b/pkg/webui/console/views/device-overview/index.js index 47a50e5483..5cbc43ecf4 100644 --- a/pkg/webui/console/views/device-overview/index.js +++ b/pkg/webui/console/views/device-overview/index.js @@ -57,11 +57,10 @@ const m = defineMessages({ sessionInfo: 'Session information', pendingSessionInfo: 'Session information (pending)', latestData: 'Latest data', - rootKeys: 'Root keys', keysNotExposed: 'Keys are not exposed', failedAccessOtherHostDevice: 'The end device you attempted to visit is registered on a different cluster and needs to be accessed using its host Console.', - macData: 'Download MAC data', + downloadMacData: 'Download MAC data', sensitiveDataWarning: 'The MAC data can contain sensitive information such as session keys that can be used to decrypt messages. Do not share this information publicly.', noSessionWarning: @@ -194,7 +193,7 @@ const DeviceInfo = ({ frequencyPlans, device, onExport }) => { } } else if (supports_join) { activationInfoData.items.push({ - key: m.rootKeys, + key: sharedMessages.rootKeys, value: , }) } @@ -266,7 +265,7 @@ const DeviceInfo = ({ frequencyPlans, device, onExport }) => { }, }} onApprove={onExport} - message={m.macData} + message={m.downloadMacData} type="button" icon="file_download" /> @@ -308,14 +307,14 @@ const DeviceOverview = () => { if (!('mac_state' in result)) { toast({ - title: m.macData, + title: m.downloadMacData, message: m.macStateError, type: toast.types.ERROR, }) } } catch { toast({ - title: m.macData, + title: m.downloadMacData, message: m.macStateError, type: toast.types.ERROR, }) diff --git a/pkg/webui/console/views/gateway-general-settings/index.js b/pkg/webui/console/views/gateway-general-settings/index.js index d078194c56..47e5426945 100644 --- a/pkg/webui/console/views/gateway-general-settings/index.js +++ b/pkg/webui/console/views/gateway-general-settings/index.js @@ -77,14 +77,21 @@ const GatewayGeneralSettingsInner = () => { const handleSubmit = useCallback( async values => { const formValues = { ...values } - const { attributes } = formValues + const { attributes, frequency_plan_ids } = formValues if (isEqual(gateway.attributes || {}, attributes)) { delete formValues.attributes } - const changed = diff(gateway, formValues) - const update = 'attributes' in changed ? { ...changed, attributes } : changed + if (isEqual(gateway.frequency_plan_ids || {}, frequency_plan_ids)) { + delete formValues.frequency_plan_ids + } + + const changed = diff(gateway, formValues, { + patchArraysItems: false, + patchInFull: ['attributes', 'frequency_plan_ids'], + }) + try { - await dispatch(updateGateway(gtwId, update)) + await dispatch(updateGateway(gtwId, changed)) toast({ title: gtwId, message: m.updateSuccess, @@ -145,7 +152,7 @@ const GatewayGeneralSettingsInner = () => { /> { } } -const isEmptyFrequencyPlan = value => value === frequencyPlans.EMPTY_FREQ_PLAN +const isEmptyFrequencyPlan = value => value?.includes(frequencyPlans.EMPTY_FREQ_PLAN) const isNotValidDuration = value => { const { duration, unit } = decodeDelayValue(value) @@ -78,18 +78,10 @@ const LorawanSettingsForm = React.memo(props => { setShouldDisplayWarning(isNotValidDuration(value)) }, []) - const [showFrequencyPlanWarning, setShowFrequencyPlanWarning] = React.useState( - isEmptyFrequencyPlan(gateway.frequency_plan_id) || !gateway.frequency_plan_id, - ) - - const onFrequencyPlanChange = React.useCallback(freqPlan => { - setShowFrequencyPlanWarning(isEmptyFrequencyPlan(freqPlan.value)) - }, []) - const initialValues = React.useMemo( () => ({ ...validationSchema.cast(gateway), - frequency_plan_id: gateway.frequency_plan_id || frequencyPlans.EMPTY_FREQ_PLAN, + frequency_plan_ids: gateway.frequency_plan_ids || [frequencyPlans.EMPTY_FREQ_PLAN], }), [gateway], ) @@ -97,8 +89,8 @@ const LorawanSettingsForm = React.memo(props => { const onFormSubmit = React.useCallback( async (values, { resetForm, setSubmitting }) => { const castedValues = validationSchema.cast( - isEmptyFrequencyPlan(values.frequency_plan_id) - ? { ...values, frequency_plan_id: '' } + isEmptyFrequencyPlan(values.frequency_plan_ids) + ? { ...values, frequency_plan_ids: [''] } : values, ) @@ -122,13 +114,7 @@ const LorawanSettingsForm = React.memo(props => { error={error} enableReinitialize > - + ( - - - - - - - - -) - -export default withBreadcrumb('gateway.single.data', props => { - const { gtwId } = props - return -})( - withFeatureRequirement(mayViewOrEditGatewayLocation, { - redirect: ({ gtwId }) => `/gateways/${gtwId}`, - })(GatewayLocation), -) +const GatewayLocation = () => { + const { gtwId } = useParams() + + useBreadcrumbs( + 'gateway.single.data', + , + ) + + return ( + + + + + + + + + + + ) +} + +export default GatewayLocation diff --git a/pkg/webui/console/views/gateway-overview/index.js b/pkg/webui/console/views/gateway-overview/index.js index 045280b82f..a56b3abed3 100644 --- a/pkg/webui/console/views/gateway-overview/index.js +++ b/pkg/webui/console/views/gateway-overview/index.js @@ -22,7 +22,6 @@ import tts from '@console/api/tts' import Button from '@ttn-lw/components/button' import DataSheet from '@ttn-lw/components/data-sheet' -import Tag from '@ttn-lw/components/tag' import toast from '@ttn-lw/components/toast' import Message from '@ttn-lw/lib/components/message' @@ -62,7 +61,7 @@ const GatewayOverview = () => { const { gtwId } = useParams() const mayViewGatewayConf = useSelector(state => checkFromState(mayViewGatewayConfJson, state)) const gateway = useSelector(selectSelectedGateway) - const { ids, description, created_at, updated_at, frequency_plan_id, gateway_server_address } = + const { ids, description, created_at, updated_at, frequency_plan_ids, gateway_server_address } = gateway const handleGlobalConfDownload = useCallback(async () => { @@ -122,7 +121,10 @@ const GatewayOverview = () => { items: [ { key: sharedMessages.frequencyPlan, - value: frequency_plan_id ? : undefined, + value: + frequency_plan_ids.length !== 0 ? ( + + ) : undefined, }, ], } @@ -130,16 +132,17 @@ const GatewayOverview = () => { if (mayViewGatewayConf) { lorawanInfo.items.push({ key: m.globalConf, - value: Boolean(frequency_plan_id) ? ( -