Final piece that lets the vendor extension framework introduced in
0e6f120 actually take effect on real frames.
Decoder (Gb32960MessageDecoder):
- Adds an overload decode(ByteBuffer, String platformAccount) alongside
the existing decode(ByteBuffer). Realtime/resend frames build a
Gb32960ParserContext(version, vin, platformAccount) and pass it to
bodyParser.parse(ctx, body) so the selector can pick a vendor profile.
- The legacy decode(ByteBuffer) delegates with a null account and is
preserved for tests and any caller that doesn't care about routing.
Channel handler (Gb32960ChannelHandler):
- Defines AttributeKey<String> PLATFORM_ACCOUNT_ATTR.
- On a successful 0x05 PLATFORM_LOGIN, stores the authenticated username
on ctx.channel().attr(PLATFORM_ACCOUNT_ATTR).
- On every channelRead0, reads the attribute (null for vehicle-direct
connections) and passes it to decoder.decode(buffer, account).
Autoconfig (Gb32960AutoConfiguration):
- Replaces the old single-registry wiring with three new beans:
* VendorExtensionCatalog with the built-in `guangdong-fc` entry
(the 6 GdFc* parsers from 957a86d)
* Gb32960ProfileRegistry, built from the union of all standard
InfoBlockParser beans plus, for each entry referenced in
lingniu.ingest.gb32960.vendor-extensions, a per-extension registry
that adds the catalog parsers on top of the defaults
* VendorExtensionSelector — RuleBasedVendorExtensionSelector when
vendor-extensions is non-empty, otherwise VendorExtensionSelector.NONE
- gb32960BodyParser now takes (Gb32960ProfileRegistry, VendorExtensionSelector).
Net effect: with the following yml fragment, lingniu account or any VIN
starting with LNVFC routes to the guangdong-fc profile and the previously
"unknown 0x30+" warns become real GdFc* InfoBlock entries:
lingniu.ingest.gb32960.vendor-extensions:
- name: guangdong-fc
match:
platform-accounts: [lingniu]
vin-prefixes: [LNVFC, LZG]
All existing 18 tests + 12 new tests (selector + vendor parsers) pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>