Skip to content

feat(native): integrate all native platforms via MQTT 3.1.1 over ktor-network#427

Draft
Copilot wants to merge 13 commits intomasterfrom
copilot/integrate-native-platforms
Draft

feat(native): integrate all native platforms via MQTT 3.1.1 over ktor-network#427
Copilot wants to merge 13 commits intomasterfrom
copilot/integrate-native-platforms

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 12, 2026

Native targets (Linux, macOS, iOS, Windows, watchOS, tvOS) were completely absent — commented out in the build with no actual implementation. This PR enables them using ktor-network 3.4.1 (pure Kotlin, no system deps) as the transport layer with a hand-rolled MQTT 3.1.1 implementation.

Build changes

  • Enable kotlin.native.ignoreDisabledTargets=true so unsupported targets are silently skipped per host
  • Call applyDefaultHierarchyTemplate() and register all native targets: linuxX64, linuxArm64, mingwX64, macosX64/Arm64, iosArm64, iosSimulatorArm64, watchosArm32/64/SimulatorArm64, tvosArm64/SimulatorArm64
  • Add ktor-network + ktor-network-tls (3.4.1) to nativeMain source set

Native implementation (NativeMkttClient)

  • Full MQTT 3.1.1 over ktor TCP/TLS sockets, implementing the complete MkttClient interface
  • QoS 0/1/2 including the full PUBREC → PUBREL → PUBCOMP exchange on both publish and receive paths
  • Keep-alive PINGREQ loop, +/# topic-filter matching, and all MqttConnectionState transitions
  • Coroutine-safe serialised writes via Mutex; all pending ACK Deferreds are cancelled on disconnect

ktor 3.x API compatibility

ByteReadChannel.readByte(), ByteWriteChannel.writeByte(), and writeFully() were removed in ktor 3.x. Replaced with:

  • Reads: private readOneByte() helper using the still-available readFully(ByteArray, 0, 1)
  • Writes: buildFullPacket() assembles the complete frame (fixed-header + variable-length remaining-length + payload) into a ByteArray via MqttBuffer, then written in one wc.write(size) { buf -> buf.write(packet, 0, packet.size) } call
val client = MkttClient(Dispatchers.Default) {
    brokerUrl = "broker.emqx.io"
    clientId  = "native-client"
    ssl       = true  // uses ktor-network-tls (OpenSSL / SecureTransport / SChannel)
}
client.connect()
client.subscribe("sensors/#", MqttQoS.AtLeastOnce).collect { println(it.payloadAsString()) }

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • download.jetbrains.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED -XX:MaxMetaspaceSize=2g -Xmx2g -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en (dns block)
  • scans-in.gradle.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED --add-opens=java.base/java.time=ALL-UNNAMED -XX:MaxMetaspaceSize=2g -Xmx2g -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

… implementation

Co-authored-by: nicolasfara <11615611+nicolasfara@users.noreply.github.com>
Copilot AI changed the title [WIP] Integrate all native platforms using async paho.mqtt feat(native): integrate all native platforms via MQTT 3.1.1 over ktor-network Mar 12, 2026
…ternatives

Co-authored-by: nicolasfara <11615611+nicolasfara@users.noreply.github.com>
@gitguardian
Copy link
Copy Markdown

gitguardian bot commented Mar 24, 2026

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
29153006 Triggered Generic Password fb7cb34 src/nativeMain/kotlin/io/github/nicolasfara/NativeMqttProtocol.kt View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants