Files
ts-mobile-go/go/teamspeak/contract.go
T

154 lines
7.0 KiB
Go
Raw Normal View History

package teamspeak
// bridge-contract.md —— Go ↔ Kotlin 跨语言契约的单一事实来源。
//
// 为什么需要这个文件:
// gomobile 不能导出 []string / []*T / Go error,所以复杂数据全部走 JSON 字符串。
// 代价是**编译器无法校验字段名**:Go 侧把 `channelId` 写成 `channelID`,
// Kotlin 侧不会编译失败,只会在运行时静默拿到默认值("" / 0 / false),
// 而 Kotlin 的 `Json { ignoreUnknownKeys = true }` 让这个失效模式更隐蔽。
//
// 边界上的三种数据类型(按保护强度递减,文档必须写清属于哪一类):
//
// A 类|gomobile 导出 struct(TextMsg / PokeEvent / Channel / Client)
// 字段是编译期检查的,Go 侧改名 → Kotlin 侧编译失败。**不需要**常量保护。
//
// B 类|JSON 字符串(channelJSON / clientJSON / serverInfoJSON / ...)
// 完全无编译期保护,就是本文件存在的理由。字段名集中声明在下方常量里,
// contract_test.go 断言常量与 struct tag 永远一致——改 tag 会让测试变红。
//
// C 类|广告过但无消费方的契约(channelDetailedJSON / clientDetailedInfoJSON /
// initialSyncJSON)
// 已被 GetInitialSyncJSON 等导出,但 Kotlin 侧当前不解析。
// 声明字段名是为了钉住形状,避免「文档说有、实际对不上」。
// 若将来要消费,先跑 contract_test.go 确认字段名。
//
// 字段名的运行时事实仍是 bridge.go / kotlin_api.go 中的 `json:"..."` tag
// (encoding/json 只认 tag);本文件是声明,测试是保证两者不漂移的机制。
// BridgeContractVersion 跨语言契约版本。
//
// 递增规则:任何**不兼容**变更(字段改名、类型变更、字段删除)都必须 +1。
// 只新增 Optional 字段(Kotlin 侧有默认值)不需要 +1。
// 递增后必须同步更新:
// - android/.../TSBridge.kt 的 EXPECTED_CONTRACT_VERSION
// - docs/bridge-contract.md
const BridgeContractVersion = "1"
// ─── B 类:channelJSON ⇄ ChannelInfo ──────────────────────────
// 生产方 GetChannelsJSON();消费方 Repository.fetchChannels()。
const (
FieldChannelID = "id"
FieldChannelName = "name"
FieldChannelParentID = "parentId"
FieldChannelDescription = "description"
FieldChannelIsPassword = "isPassword"
)
// ─── B 类:clientJSON ⇄ ClientInfo ────────────────────────────
// 生产方 GetClientsJSON();消费方 Repository.fetchClients()。
const (
FieldClientID = "id"
FieldClientNickname = "nickname"
FieldClientUID = "uid"
FieldClientChannelID = "channelId"
FieldClientServerGroups = "serverGroups"
FieldClientIsSelf = "isSelf"
)
// ─── B 类:serverInfoJSON ⇄ ServerInfo ────────────────────────
// 生产方 GetServerInfoJSON();消费方 Repository / ServerViewModel。
const (
FieldServerName = "name"
FieldServerWelcomeMessage = "welcomeMessage"
FieldServerMaxClients = "maxClients"
FieldServerClientsOnline = "clientsOnline"
FieldServerChannelsOnline = "channelsOnline"
FieldServerUptime = "uptime"
FieldServerVersion = "version"
FieldServerPlatform = "platform"
FieldServerCreated = "created"
FieldServerIconID = "iconId"
FieldServerDefaultServerGroup = "defaultServerGroup"
FieldServerDefaultChannelGroup = "defaultChannelGroup"
)
// ─── B 类:DownloadFileBytesJSON ⇄ TSBridge.downloadFileBytes ─
// 生产方 DownloadFileBytesJSON();消费方 FileDownloadManager。
// 失败时返回 "{}"(而非空串),消费方以 data 为空判定失败。
const (
FieldFileData = "data"
FieldFileSize = "size"
)
// ─── C 类:channelDetailedJSON(GetChannelsDetailedJSON)──────
// 当前无 Kotlin 消费方。字段名在此钉住形状。
const (
FieldChannelDetailTopic = "topic"
FieldChannelDetailOrder = "order"
FieldChannelDetailCodec = "codec"
FieldChannelDetailCodecQuality = "codecQuality"
FieldChannelDetailNeededTalkPower = "neededTalkPower"
FieldChannelDetailMaxClients = "maxClients"
FieldChannelDetailMaxFamilyClients = "maxFamilyClients"
FieldChannelDetailIsMaxClientsUnlimited = "isMaxClientsUnlimited"
FieldChannelDetailIsMaxFamilyClientsUnlimited = "isMaxFamilyClientsUnlimited"
FieldChannelDetailIsPermanent = "isPermanent"
FieldChannelDetailIsSemiPermanent = "isSemiPermanent"
FieldChannelDetailIsDefault = "isDefault"
FieldChannelDetailIsOrdered = "isOrdered"
FieldChannelDetailIconID = "iconId"
FieldChannelDetailNeededModifyPower = "neededModifyPower"
)
// ─── C 类:clientDetailedInfoJSON(GetClientDetailInfoJSON)───
// 当前无 Kotlin 消费方。
const (
FieldClientDetailType = "type"
FieldClientDetailAway = "away"
FieldClientDetailAwayMessage = "awayMessage"
FieldClientDetailInputMuted = "inputMuted"
FieldClientDetailOutputMuted = "outputMuted"
FieldClientDetailPlatform = "platform"
FieldClientDetailVersion = "version"
FieldClientDetailIP = "ip"
FieldClientDetailCreated = "created"
FieldClientDetailLastConnected = "lastConnected"
FieldClientDetailTotalConnections = "totalConnections"
FieldClientDetailDescription = "description"
FieldClientDetailIconID = "iconId"
)
// ─── C 类:initialSyncJSON(GetInitialSyncJSON)────────────────
// 一次性返回全部初始数据的聚合契约。当前无 Kotlin 消费方
// (Repository.performInitialSync 走的是三个独立 getter 串行请求)。
const (
FieldSyncChannels = "channels"
FieldSyncClients = "clients"
FieldSyncSelfID = "selfId"
FieldSyncSelfChannelID = "selfChannelId"
FieldSyncServer = "server"
)
// 消息 targetMode 取值。
//
// ⚠️ 收发能力不对称(重要,别再读成三种都支持):
//
// TargetModePrivate(1) 仅接收。发送侧未实现——TSBridge.sendTextMessage 只实现 mode=2,
// 其余返回"暂不支持该消息类型"。SDK 的 SendTextMessage 走的也是
// mode=2 路径,私聊回复需要另找 API。
// TargetModeChannel(2) 收发均支持。
// TargetModeServer(3) 仅接收。
const (
TargetModePrivate = 1
TargetModeChannel = 2
TargetModeServer = 3
)
// GetContractVersion 返回当前 bridge 契约版本。
// Kotlin 侧在建立连接前调用并与本地期望值比对。
// gomobile 不支持返回 error,版本不匹配由 Kotlin 侧抛错处理。
func GetContractVersion() string {
return BridgeContractVersion
}