mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-02 06:24:16 +02:00
5ec6d80f61
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
165 lines
6.6 KiB
Markdown
165 lines
6.6 KiB
Markdown
# `:core:takserver`
|
|
|
|
## Overview
|
|
|
|
The `:core:takserver` module implements the **Meshtastic ↔ TAK (Team Awareness Kit) bridge**. It embeds an mTLS TCP server (port 8089) compatible with ATAK (Android), iTAK (iOS), and WinTAK clients, enabling mesh-networked position sharing and GeoChat with TAK-enabled devices.
|
|
|
|
**Targets:** Android · JVM (Desktop) · iOS — fully multiplatform with `expect`/`actual` splits for compression, file I/O, and the TCP server itself.
|
|
|
|
## Key Responsibilities
|
|
|
|
- Serve an mTLS TCP listener (port 8089) compatible with the CoT (Cursor-on-Target) protocol
|
|
- Convert Meshtastic protobuf packets (`TAKPacketV2`) to CoT XML events and vice versa
|
|
- Generate ATAK Data Package `.zip` exports (team contacts, map overlays)
|
|
- Compress CoT payloads using Zstd (TAK SDK format) with `expect`/`actual` platform implementations
|
|
- Buffer up to 50 CoT messages for 5 minutes when no TAK clients are connected; drain on reconnect
|
|
- Provide Crowdin-localised TAK preference XML for ATAK client provisioning
|
|
|
|
## Source Structure
|
|
|
|
```
|
|
src/
|
|
├── commonMain/kotlin/org/meshtastic/core/takserver/
|
|
│ ├── TAKServer.kt ← interface + expect createTAKServer()
|
|
│ ├── TAKServerManager.kt ← interface + TAKServerManagerImpl (offline queue)
|
|
│ ├── TAKMeshIntegration.kt ← bridges mesh service ↔ TAK server
|
|
│ ├── CoTConversion.kt ← Position/User → CoTMessage extension fns
|
|
│ ├── CoTXml.kt / CoTXmlParser.kt / CoTXmlFrameBuffer.kt
|
|
│ ├── CoTXmlDataClasses.kt
|
|
│ ├── CoTDetailStripper.kt
|
|
│ ├── TAKModels.kt ← CoTMessage, TAKClientInfo, TAKConnectionEvent
|
|
│ ├── TAKPacketConversion.kt
|
|
│ ├── TAKPacketV2Conversion.kt
|
|
│ ├── TAKDefaults.kt
|
|
│ ├── TAKDataPackageGenerator.kt
|
|
│ ├── RouteDataPackageGenerator.kt
|
|
│ ├── TAKPrefXmlDataClasses.kt
|
|
│ ├── TakV2TypeMapper.kt
|
|
│ ├── TakConversionHelpers.kt
|
|
│ ├── XmlUtils.kt
|
|
│ ├── AtakFileWriter.kt ← expect
|
|
│ ├── TakSdkCompressor.kt ← expect (Zstd TAK-SDK frame)
|
|
│ ├── TakV2Compressor.kt ← expect (Zstd TAKPacketV2 frame)
|
|
│ ├── ZipArchiver.kt ← expect
|
|
│ ├── TakFixtureLoader.kt ← expect (test fixtures)
|
|
│ ├── TakMeshTestRunner.kt
|
|
│ └── di/
|
|
│ └── CoreTakServerModule.kt
|
|
├── jvmAndroidMain/kotlin/ ← actual TAKServerJvm, TAKClientConnection, TakCertLoader
|
|
├── androidMain/kotlin/ ← actual AtakFileWriter (Android)
|
|
├── jvmMain/kotlin/ ← actual AtakFileWriter (Desktop), XML pull-parser
|
|
└── iosMain/kotlin/ ← actual TAKServerIos, actual compression impls
|
|
```
|
|
|
|
## Notable APIs
|
|
|
|
### `TAKServer` (interface)
|
|
|
|
```kotlin
|
|
interface TAKServer {
|
|
val connectionCount: StateFlow<Int>
|
|
var onMessage: ((CoTMessage, TAKClientInfo?) -> Unit)?
|
|
var onClientConnected: (() -> Unit)?
|
|
|
|
suspend fun start(scope: CoroutineScope): Result<Unit>
|
|
fun stop()
|
|
suspend fun broadcast(cotMessage: CoTMessage)
|
|
suspend fun broadcastRawXml(xml: String)
|
|
suspend fun hasConnections(): Boolean
|
|
}
|
|
```
|
|
|
|
The mTLS listener binds on port 8089 using a bundled `server.p12` / `ca.pem` identity, compatible with the ATAK Data Package provisioning flow.
|
|
|
|
### `TAKServerManager` (interface)
|
|
|
|
```kotlin
|
|
interface TAKServerManager {
|
|
val isRunning: StateFlow<Boolean>
|
|
val connectionCount: StateFlow<Int>
|
|
val inboundMessages: SharedFlow<InboundCoTMessage>
|
|
|
|
suspend fun start(scope: CoroutineScope)
|
|
fun stop()
|
|
suspend fun broadcast(cotMessage: CoTMessage)
|
|
suspend fun broadcastRawXml(xml: String)
|
|
}
|
|
```
|
|
|
|
`TAKServerManagerImpl` adds an **offline queue**: buffers up to 50 CoT messages for 5 minutes when no clients are connected and drains them automatically on the next `onClientConnected` callback.
|
|
|
|
### `CoTMessage`
|
|
|
|
```kotlin
|
|
@Serializable
|
|
data class CoTMessage(
|
|
val uid: String,
|
|
val type: String, // e.g. "a-f-G-U-C" (friendly ground unit)
|
|
val time: Instant,
|
|
val lat: Double, val lon: Double, val hae: Double,
|
|
val contact: CoTContact?,
|
|
val group: CoTGroup?,
|
|
val track: CoTTrack?,
|
|
val chat: CoTChat?,
|
|
val remarks: String?,
|
|
// ...
|
|
)
|
|
|
|
// Factory helpers
|
|
CoTMessage.pli(uid, callsign, lat, lon, ...) // Position Location Information
|
|
CoTMessage.chat(senderUid, callsign, message, chatroom)
|
|
```
|
|
|
|
### CoT Conversion
|
|
|
|
```kotlin
|
|
// Meshtastic proto → CoT
|
|
org.meshtastic.proto.Position.toCoTMessage(uid, callsign, team, role, battery): CoTMessage
|
|
org.meshtastic.proto.User.toCoTMessage(position, team, role, battery): CoTMessage
|
|
```
|
|
|
|
## Dependency Graph
|
|
|
|
```
|
|
core:takserver
|
|
├── api → core:repository (exported)
|
|
├── core:common, core:di, core:model, core:proto
|
|
├── okio, kotlinx.serialization.json
|
|
├── xmlutil-core, xmlutil-serialization
|
|
├── ktor-client-core, ktor-network (TCP socket)
|
|
└── zstd-jni (jvmAndroid/jvm), kotlinx.datetime
|
|
```
|
|
|
|
## Local TAK Server Feature
|
|
|
|
The Local TAK Server can be enabled from the app's Settings screen. When running, ATAK/iTAK clients on the same network can connect to `<device-ip>:8089` and their position reports are automatically bridged onto the mesh. Mesh node positions are broadcast to all connected TAK clients in real time.
|
|
|
|
## Dependency Graph
|
|
|
|
<!--region graph-->
|
|
```mermaid
|
|
graph TB
|
|
:core:takserver[takserver]:::kmp-library
|
|
:core:takserver --> :core:repository
|
|
:core:takserver -.-> :core:common
|
|
:core:takserver -.-> :core:di
|
|
:core:takserver -.-> :core:model
|
|
:core:takserver -.-> :core:proto
|
|
:core:takserver -.-> :core:testing
|
|
|
|
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
|
|
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;
|
|
|
|
```
|
|
<!--endregion-->
|