154 lines
7.0 KiB
Go
154 lines
7.0 KiB
Go
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
|
|||
|
|
}
|