feat: add TeamSpeak address resolver
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# chanora_resolver
|
||||
|
||||
The library accepts the same kind of raw server input a client UI receives and returns a final `host:port` address suitable for `tsclientlib::Connection::build` or Chanora's `ConnectConfig.address`.
|
||||
|
||||
## Resolution Flow
|
||||
|
||||
Use `ChanoraResolver::resolve_client_request` or `resolve_client_address` for app code. The resolver owns the decision tree:
|
||||
|
||||
1. Normalize raw client input, including `ts3server://host?port=...`.
|
||||
2. For dotless names such as `6666` or `wwb`, query the myTeamSpeak server-name endpoint first. If it returns a hostname, restart normal resolution with that hostname. If it returns `ip:port`, use that final address.
|
||||
3. Start plain A/AAAA DNS as the final fallback address.
|
||||
4. Prefer `_ts3._udp.<host>` SRV. Its target host and port override the user input port, then the target is resolved to a final IP.
|
||||
5. Try `_tsdns._tcp.<candidate>` SRV on candidate parent/full hosts and query the returned TSDNS server over TCP.
|
||||
6. Try direct TSDNS TCP on candidate parent/full hosts at port `41144`.
|
||||
7. Fall back to the A/AAAA result with the user-supplied port, or default TeamSpeak port `9987`.
|
||||
|
||||
The older explicit API (`Args { host, service, protocol }`) is still available for diagnostic example use.
|
||||
|
||||
## DNS Setup Guide
|
||||
|
||||
This chart is for choosing DNS records when operating a TeamSpeak 3 server. It is not the client lookup order; the library still implements the client-side resolver behavior above.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["Which DNS type fits your TeamSpeak 3 server?"]
|
||||
|
||||
A --> X["Don't do this!"]
|
||||
X --> X1["Do not use simple TSDNS<br/>without SRV TSDNS"]
|
||||
|
||||
A --> B{"How many servers do you have?"}
|
||||
|
||||
B -->|One virtual server| C{"Does your server use<br/>the default port 9987?"}
|
||||
|
||||
C -->|Yes| D{"Do all services under this domain<br/>run on the same server<br/>as the TS3 server?"}
|
||||
D -->|Yes| E1["Use A/AAAA or CNAME"]
|
||||
D -->|No| E2["Use SRV TS3"]
|
||||
|
||||
C -->|No| F{"Are you okay with<br/>entering the port manually?"}
|
||||
F -->|No| E3["Use SRV TS3"]
|
||||
F -->|Yes| G{"Do all services under this domain<br/>run on the same server<br/>as the TS3 server?"}
|
||||
G -->|Yes| E4["Use A/AAAA or CNAME"]
|
||||
G -->|No| E5["Use SRV TSDNS"]
|
||||
|
||||
B -->|More than one virtual server| H{"Are you okay with port numbers?"}
|
||||
|
||||
H -->|No| I1["Use subdomains with SRV TS3<br/>for each subdomain"]
|
||||
|
||||
H -->|Yes| I{"On how many servers<br/>do you run TS3 servers?"}
|
||||
I -->|Only one| J{"Do all services under this domain<br/>run on the same server<br/>as the TS3 server?"}
|
||||
J -->|Yes| K1["Use A/AAAA or CNAME"]
|
||||
J -->|No| K2["Use SRV TSDNS"]
|
||||
|
||||
I -->|More than one| K3["Use subdomains with A/AAAA<br/>or CNAME for each server"]
|
||||
```
|
||||
|
||||
## Library Example
|
||||
|
||||
```rust
|
||||
use chanora_resolver::ChanoraResolver;
|
||||
|
||||
let client = ChanoraResolver::new()?;
|
||||
let address = client.resolve_client_address("voice.teamspeak.com").await?;
|
||||
|
||||
// tsclientlib:
|
||||
// let mut connection = tsclientlib::Connection::build(address).connect()?;
|
||||
|
||||
// Chanora:
|
||||
// let cfg = chanora_core::ConnectConfig {
|
||||
// address,
|
||||
// nickname,
|
||||
// password,
|
||||
// identity,
|
||||
// ready_timeout,
|
||||
// };
|
||||
// let snapshot = session.connect(cfg).await?;
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
cargo run --example library -- voice.teamspeak.com
|
||||
cargo run --example library -- 6666
|
||||
cargo run --example library -- wwb
|
||||
cargo run --example library -- kr.teamspeak.app
|
||||
cargo run --example library -- 'ts3server://voice.teamspeak.com?port=9987'
|
||||
cargo run --example cli -- -host voice.teamspeak.com -service ts3
|
||||
```
|
||||
|
||||
`example_log` contains live sample outputs for TS3 SRV, DNS fallback, server-name lookup, and unsuccessful TSDNS attempts that must remain non-fatal.
|
||||
|
||||
## Fail-Safes
|
||||
|
||||
- Bare numeric names such as `6666` are treated as server names first, avoiding OS DNS coercion into numeric IPv4 addresses.
|
||||
- SRV targets and TSDNS responses are resolved to final IP addresses before handoff, so Chanora can pass a concrete `SocketAddr`-style `host:port` to `tsclientlib`.
|
||||
- TSDNS TCP lookups use short timeouts and are non-fatal; DNS fallback remains available when TSDNS is absent or unreachable.
|
||||
- Android uses an explicit SRV resolver configuration instead of relying on system resolver initialization in a raw binary context.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
cargo fmt --all -- --check
|
||||
cargo test
|
||||
cargo clippy --all-targets --all-features -- -D warnings
|
||||
```
|
||||
Reference in New Issue
Block a user