refactor(nests): split MoqLiteMessages.kt by concern (Audit-11)
The original `MoqLiteMessages.kt` mixed three categories of declaration:
- One `MoqLiteAlpn` object — the WebTransport sub-protocol
advertisement strings.
- Four enums — `MoqLiteControlType`, `MoqLiteDataType`,
`MoqLiteAnnounceStatus`, `MoqLiteSubscribeResponseType` — that
are wire-format discriminators the codec reads at message
boundaries to choose which body to decode.
- Eight data classes / objects — `MoqLiteAnnouncePlease`,
`MoqLiteAnnounce`, `MoqLiteSubscribe`, `MoqLiteSubscribeOk`,
`MoqLiteSubscribeDrop`, `MoqLiteSubscribeDropCode`,
`MoqLiteGroupHeader`, `MoqLiteProbe` — the body shapes themselves.
317 lines, three concerns, one file. Split by responsibility:
- `MoqLiteAlpn.kt` — the ALPN object alone.
- `MoqLiteControlCodes.kt` — the four discriminator enums.
- `MoqLiteMessages.kt` — body data classes only.
Same package, same visibility, identical wire behaviour. Imports
across the codebase resolve to the new locations automatically
since everything stayed in `com.vitorpamplona.nestsclient.moq.lite`.
Tests pass unchanged.
https://claude.ai/code/session_014JfZJHSTvyYYWJbC9VbB47
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.nestsclient.moq.lite
|
||||
|
||||
/**
|
||||
* moq-lite ALPN strings. ONLY [LITE_03] is wire-compatible with the
|
||||
* codec in [MoqLiteCodec]; the other constants are kept for
|
||||
* documentation and future codec upgrades.
|
||||
*
|
||||
* Subscribe / Group framing is identical across Lite-03 and Lite-04,
|
||||
* but Lite-04 reshapes Announce.hops into an `OriginList`
|
||||
* (`kixelated/moq` commit 45db108, "moq-lite/moq-relay: hop-based
|
||||
* clustering"), adds an `exclude_hop` field to AnnounceInterest, and
|
||||
* adds an `rtt` field to Probe. A relay that picks Lite-04 with our
|
||||
* Lite-03 codec on the wire desyncs on the first Announce exchange.
|
||||
* Don't add [LITE_04] to `wt-available-protocols` until
|
||||
* [MoqLiteCodec] is version-aware and [MoqLiteAnnounce.hops] is a
|
||||
* list rather than a single varint.
|
||||
*
|
||||
* `"moql"` is the legacy combined ALPN that requires an in-band SETUP
|
||||
* exchange — kept here for completeness; not advertised by the
|
||||
* factory.
|
||||
*
|
||||
* Source: `kixelated/moq/rs/moq-lite/src/lite/version.rs`,
|
||||
* `kixelated/moq/rs/moq-lite/src/lite/announce.rs:11-105`,
|
||||
* `kixelated/moq/rs/moq-lite/src/lite/probe.rs:9-55`.
|
||||
*/
|
||||
object MoqLiteAlpn {
|
||||
const val LITE_03: String = "moq-lite-03"
|
||||
|
||||
/**
|
||||
* `moq-lite-04` ALPN string. Wire-incompatible with [MoqLiteCodec]
|
||||
* today — see the object kdoc for the codec diff. Defined here so
|
||||
* a future patch that lands version-aware Announce / Probe codecs
|
||||
* can drop it into the [QuicWebTransportFactory] sub-protocol list
|
||||
* without re-deriving the constant.
|
||||
*/
|
||||
const val LITE_04: String = "moq-lite-04"
|
||||
const val LEGACY: String = "moql"
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.nestsclient.moq.lite
|
||||
|
||||
// Wire-format discriminators for moq-lite control flow.
|
||||
//
|
||||
// The four enums below share a common job: they're varint / byte tags
|
||||
// the wire-format parser (`MoqLiteCodec`) reads at message boundaries to
|
||||
// decide which body to decode next. None of them carry payload data
|
||||
// themselves; the data classes that DO live in `MoqLiteMessages.kt`.
|
||||
//
|
||||
// Source: `kixelated/moq/rs/moq-lite/src/lite/{stream,announce,subscribe}.rs`.
|
||||
|
||||
/**
|
||||
* ControlType varint discriminator written as the first datum on every
|
||||
* client-initiated bidi stream. Selects which message body the peer
|
||||
* should expect to read next.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/stream.rs:7-15`.
|
||||
*/
|
||||
enum class MoqLiteControlType(
|
||||
val code: Long,
|
||||
) {
|
||||
/** Lite-01/02 only — unused on Lite-03. Reserved here for completeness. */
|
||||
Session(0L),
|
||||
Announce(1L),
|
||||
Subscribe(2L),
|
||||
Fetch(3L),
|
||||
Probe(4L),
|
||||
|
||||
/**
|
||||
* Graceful relay-shutdown signal. moq-rs's `Publisher::run` accepts
|
||||
* `ControlType::Goaway = 5` (`rs/moq-lite/src/lite/publisher.rs`)
|
||||
* to migrate a publisher to a different relay node. We don't act
|
||||
* on it today — recognising the type code prevents
|
||||
* [MoqLiteSession.handleInboundBidi] from silently FINing the
|
||||
* bidi as an unknown control type, which would lose the relay's
|
||||
* shutdown notification. Wire body decoding is left as a follow-up.
|
||||
*/
|
||||
Goaway(5L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteControlType? = byCode[code]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DataType varint written as the first byte of every uni stream that
|
||||
* carries payload. Lite-03 currently uses `Group=0` only.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/stream.rs:32-36`.
|
||||
*/
|
||||
enum class MoqLiteDataType(
|
||||
val code: Long,
|
||||
) {
|
||||
Group(0L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteDataType? = byCode[code]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status byte at the head of an [MoqLiteAnnounce] payload. `Active=1`
|
||||
* is sent on first publish; `Ended=0` on explicit unannounce. Disconnect
|
||||
* is NOT signalled with `Ended` — the bidi just closes.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/announce.rs:84-90`.
|
||||
*/
|
||||
enum class MoqLiteAnnounceStatus(
|
||||
val code: Int,
|
||||
) {
|
||||
Ended(0),
|
||||
Active(1),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: Int): MoqLiteAnnounceStatus? =
|
||||
when (code) {
|
||||
0 -> Ended
|
||||
1 -> Active
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type discriminator at the head of a SubscribeResponse on the response
|
||||
* side of a Subscribe bidi. Wire layout (Lite-03+):
|
||||
*
|
||||
* type varint (0 = Ok, 1 = Drop)
|
||||
* body size-prefixed bytes
|
||||
*
|
||||
* The type sits OUTSIDE the body size prefix — see
|
||||
* `rs/moq-lite/src/lite/subscribe.rs::SubscribeResponse::encode` (the
|
||||
* `_` arm covers Lite03+). Earlier drafts wrapped type+body in one
|
||||
* outer size prefix; Lite03 split them.
|
||||
*/
|
||||
enum class MoqLiteSubscribeResponseType(
|
||||
val code: Long,
|
||||
) {
|
||||
Ok(0L),
|
||||
Drop(1L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteSubscribeResponseType? = byCode[code]
|
||||
}
|
||||
}
|
||||
+7
-141
@@ -20,147 +20,13 @@
|
||||
*/
|
||||
package com.vitorpamplona.nestsclient.moq.lite
|
||||
|
||||
/**
|
||||
* moq-lite ALPN strings. ONLY [LITE_03] is wire-compatible with the
|
||||
* codec in [MoqLiteCodec]; the other constants are kept for
|
||||
* documentation and future codec upgrades.
|
||||
*
|
||||
* Subscribe / Group framing is identical across Lite-03 and Lite-04,
|
||||
* but Lite-04 reshapes Announce.hops into an `OriginList`
|
||||
* (`kixelated/moq` commit 45db108, "moq-lite/moq-relay: hop-based
|
||||
* clustering"), adds an `exclude_hop` field to AnnounceInterest, and
|
||||
* adds an `rtt` field to Probe. A relay that picks Lite-04 with our
|
||||
* Lite-03 codec on the wire desyncs on the first Announce exchange.
|
||||
* Don't add [LITE_04] to `wt-available-protocols` until
|
||||
* [MoqLiteCodec] is version-aware and [MoqLiteAnnounce.hops] is a
|
||||
* list rather than a single varint.
|
||||
*
|
||||
* `"moql"` is the legacy combined ALPN that requires an in-band SETUP
|
||||
* exchange — kept here for completeness; not advertised by the
|
||||
* factory.
|
||||
*
|
||||
* Source: `kixelated/moq/rs/moq-lite/src/lite/version.rs`,
|
||||
* `kixelated/moq/rs/moq-lite/src/lite/announce.rs:11-105`,
|
||||
* `kixelated/moq/rs/moq-lite/src/lite/probe.rs:9-55`.
|
||||
*/
|
||||
object MoqLiteAlpn {
|
||||
const val LITE_03: String = "moq-lite-03"
|
||||
|
||||
/**
|
||||
* `moq-lite-04` ALPN string. Wire-incompatible with [MoqLiteCodec]
|
||||
* today — see the object kdoc for the codec diff. Defined here so
|
||||
* a future patch that lands version-aware Announce / Probe codecs
|
||||
* can drop it into the [QuicWebTransportFactory] sub-protocol list
|
||||
* without re-deriving the constant.
|
||||
*/
|
||||
const val LITE_04: String = "moq-lite-04"
|
||||
const val LEGACY: String = "moql"
|
||||
}
|
||||
|
||||
/**
|
||||
* ControlType varint discriminator written as the first datum on every
|
||||
* client-initiated bidi stream. Selects which message body the peer
|
||||
* should expect to read next.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/stream.rs:7-15`.
|
||||
*/
|
||||
enum class MoqLiteControlType(
|
||||
val code: Long,
|
||||
) {
|
||||
/** Lite-01/02 only — unused on Lite-03. Reserved here for completeness. */
|
||||
Session(0L),
|
||||
Announce(1L),
|
||||
Subscribe(2L),
|
||||
Fetch(3L),
|
||||
Probe(4L),
|
||||
|
||||
/**
|
||||
* Graceful relay-shutdown signal. moq-rs's `Publisher::run` accepts
|
||||
* `ControlType::Goaway = 5` (`rs/moq-lite/src/lite/publisher.rs`)
|
||||
* to migrate a publisher to a different relay node. We don't act
|
||||
* on it today — recognising the type code prevents
|
||||
* [MoqLiteSession.handleInboundBidi] from silently FINing the
|
||||
* bidi as an unknown control type, which would lose the relay's
|
||||
* shutdown notification. Wire body decoding is left as a follow-up.
|
||||
*/
|
||||
Goaway(5L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteControlType? = byCode[code]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DataType varint written as the first byte of every uni stream that
|
||||
* carries payload. Lite-03 currently uses `Group=0` only.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/stream.rs:32-36`.
|
||||
*/
|
||||
enum class MoqLiteDataType(
|
||||
val code: Long,
|
||||
) {
|
||||
Group(0L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteDataType? = byCode[code]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Status byte at the head of an [MoqLiteAnnounce] payload. `Active=1`
|
||||
* is sent on first publish; `Ended=0` on explicit unannounce. Disconnect
|
||||
* is NOT signalled with `Ended` — the bidi just closes.
|
||||
*
|
||||
* Source: `rs/moq-lite/src/lite/announce.rs:84-90`.
|
||||
*/
|
||||
enum class MoqLiteAnnounceStatus(
|
||||
val code: Int,
|
||||
) {
|
||||
Ended(0),
|
||||
Active(1),
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: Int): MoqLiteAnnounceStatus? =
|
||||
when (code) {
|
||||
0 -> Ended
|
||||
1 -> Active
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type discriminator at the head of a SubscribeResponse on the response
|
||||
* side of a Subscribe bidi. Wire layout (Lite-03+):
|
||||
*
|
||||
* type varint (0 = Ok, 1 = Drop)
|
||||
* body size-prefixed bytes
|
||||
*
|
||||
* The type sits OUTSIDE the body size prefix — see
|
||||
* `rs/moq-lite/src/lite/subscribe.rs::SubscribeResponse::encode` (the
|
||||
* `_` arm covers Lite03+). Earlier drafts wrapped type+body in one
|
||||
* outer size prefix; Lite03 split them.
|
||||
*/
|
||||
enum class MoqLiteSubscribeResponseType(
|
||||
val code: Long,
|
||||
) {
|
||||
Ok(0L),
|
||||
Drop(1L),
|
||||
;
|
||||
|
||||
companion object {
|
||||
private val byCode = entries.associateBy { it.code }
|
||||
|
||||
fun fromCode(code: Long): MoqLiteSubscribeResponseType? = byCode[code]
|
||||
}
|
||||
}
|
||||
// Wire-format payload data classes for moq-lite messages.
|
||||
//
|
||||
// The discriminator enums (which message-body to expect at the top of
|
||||
// a bidi / uni stream) live in `MoqLiteControlCodes.kt`; the ALPN
|
||||
// negotiation strings live in `MoqLiteAlpn.kt`. This file holds only
|
||||
// the body shapes the codec encodes / decodes once a discriminator
|
||||
// has selected one.
|
||||
|
||||
/**
|
||||
* "I'm interested in broadcasts under this prefix" — the first message
|
||||
|
||||
Reference in New Issue
Block a user