feat(protocol): per-platform TS3 client_version selection
ConnectOptions previously took tsclientlib's default Version. Servers that strictly check the announced client signature could refuse or downgrade those sessions. Add pick_client_version() that selects a stable signed descriptor matching the runtime OS: Windows -> Version::Windows_5_0_0_beta51 Linux -> Version::Linux_5_0_0_beta51 macOS -> Version::macOS_5_0_0_beta51 Android -> Version::Android_3_5_0__7 iOS -> Version::iOS_3_5_6 other -> Linux fallback All five variants are guaranteed to exist in the vendored tsproto-types enum at compile time; build fails loudly if upstream removes one. Wired into Connection::build(...).version(pick_client_version()) on every connect. Emits 'selected TS3 client_version' info log line so the choice is visible in chanora.log.
This commit is contained in:
@@ -28,13 +28,68 @@ use tsclientlib::data::{self, Channel, Client};
|
||||
use tsclientlib::prelude::*;
|
||||
use tsclientlib::{
|
||||
ChannelId as TsChannelId, Connection, DisconnectOptions, Identity, MessageHandle,
|
||||
OutCommandExt, StreamItem,
|
||||
OutCommandExt, StreamItem, Version,
|
||||
};
|
||||
use tsproto_packets::packets::{InAudioBuf, OutPacket};
|
||||
|
||||
use crate::dto::{ChannelId, ChannelInfo, ClientId, ClientInfo, ServerSnapshot};
|
||||
use crate::ProtocolError;
|
||||
|
||||
/// Pick the TeamSpeak `client_version`/platform/signature triple
|
||||
/// (sourced from `ReSpeak/tsdeclarations/Versions.csv`, baked into
|
||||
/// `tsproto-types` at vendor-time) that best matches the *runtime*
|
||||
/// platform Chanora is executing on.
|
||||
///
|
||||
/// Per-platform selection (set by the project owner):
|
||||
///
|
||||
/// * Windows / Linux / macOS desktops announce as TeamSpeak **5
|
||||
/// beta51** — the latest TS5 desktop signature in the vendored
|
||||
/// `tsproto-types` enum. TS5 servers expect this shape; TS3
|
||||
/// servers are happy to accept any well-formed signed client
|
||||
/// descriptor and have no codec-version coupling.
|
||||
/// * Android announces as **3.5.0__7** (the latest Android
|
||||
/// signature in the vendored enum).
|
||||
/// * iOS announces as **3.5.6** (latest iOS signature in the
|
||||
/// vendored enum).
|
||||
///
|
||||
/// All five variants are guaranteed to exist in the generated
|
||||
/// `Version` enum at compile time; if upstream rotates the CSV the
|
||||
/// build will fail loudly here rather than silently fall back.
|
||||
fn pick_client_version() -> Version {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Version::Windows_5_0_0_beta51
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Version::macOS_5_0_0_beta51
|
||||
}
|
||||
#[cfg(target_os = "ios")]
|
||||
{
|
||||
Version::iOS_3_5_6
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
{
|
||||
Version::Android_3_5_0__7
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
Version::Linux_5_0_0_beta51
|
||||
}
|
||||
#[cfg(not(any(
|
||||
target_os = "windows",
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android",
|
||||
target_os = "linux"
|
||||
)))]
|
||||
{
|
||||
// Last-ditch fallback for unanticipated targets (BSDs,
|
||||
// Solaris-likes). Linux signature is the closest analogue.
|
||||
Version::Linux_5_0_0_beta51
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed configuration for a connection attempt.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConnectConfig {
|
||||
@@ -331,7 +386,15 @@ async fn connection_task(
|
||||
// Pass the resolved SocketAddr directly to tsclientlib so it
|
||||
// skips its own resolver entirely (tsclientlib accepts
|
||||
// SocketAddr via the From<SocketAddr> for ServerAddress impl).
|
||||
let mut builder = Connection::build(resolved).name(cfg.nickname.clone());
|
||||
let client_version = pick_client_version();
|
||||
info!(
|
||||
target: "chanora_protocol",
|
||||
client_version = %client_version,
|
||||
"selected TS3 client_version for this platform"
|
||||
);
|
||||
let mut builder = Connection::build(resolved)
|
||||
.name(cfg.nickname.clone())
|
||||
.version(client_version);
|
||||
|
||||
let identity = match cfg.identity.as_deref() {
|
||||
Some(s) => match Identity::new_from_str(s) {
|
||||
|
||||
Reference in New Issue
Block a user