chore: KMP audit — commonize code, centralize utilities, eliminate dead abstractions (#5133)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich 2026-04-14 21:17:50 -05:00 committed by GitHub
parent 50ade01e55
commit 72b981f73b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
132 changed files with 2186 additions and 916 deletions

View file

@ -28,4 +28,7 @@ object HttpClientDefaults {
/** Maximum number of automatic retries on server errors (5xx). */
const val MAX_RETRIES = 3
/** Base URL for the Meshtastic public API. Installed via the `DefaultRequest` plugin. */
const val API_BASE_URL = "https://api.meshtastic.org/"
}

View file

@ -326,8 +326,8 @@ class MockRadioTransport(
user =
User(
id = DataPacket.nodeNumToDefaultId(numIn),
long_name = "Sim " + numIn.toString(16),
short_name = getInitials("Sim " + numIn.toString(16)),
long_name = "Sim ${numIn.toString(16)}",
short_name = getInitials("Sim ${numIn.toString(16)}"),
hw_model = HardwareModel.ANDROID_SIM,
),
position =

View file

@ -35,14 +35,14 @@ interface ApiService {
/**
* Ktor-based [ApiService] implementation.
*
* Uses relative paths the base URL is set via the `DefaultRequest` plugin in the platform Koin modules.
*
* Registered with `binds = []` to prevent Koin from auto-binding to [ApiService]; host modules (`app`, `desktop`)
* provide their own explicit `ApiService` binding to allow platform-specific `HttpClient` engines.
*/
@Single(binds = [])
class ApiServiceImpl(private val client: HttpClient) : ApiService {
override suspend fun getDeviceHardware(): List<NetworkDeviceHardware> =
client.get("https://api.meshtastic.org/resource/deviceHardware").body()
override suspend fun getDeviceHardware(): List<NetworkDeviceHardware> = client.get("resource/deviceHardware").body()
override suspend fun getFirmwareReleases(): NetworkFirmwareReleases =
client.get("https://api.meshtastic.org/github/firmware/list").body()
override suspend fun getFirmwareReleases(): NetworkFirmwareReleases = client.get("github/firmware/list").body()
}

View file

@ -17,12 +17,12 @@
package org.meshtastic.core.network.repository
import co.touchlab.kermit.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOn
import org.koin.core.annotation.Single
import org.meshtastic.core.di.CoroutineDispatchers
import java.io.IOException
import java.net.InetAddress
import java.net.NetworkInterface
@ -31,7 +31,7 @@ import javax.jmdns.ServiceEvent
import javax.jmdns.ServiceListener
@Single
class JvmServiceDiscovery : ServiceDiscovery {
class JvmServiceDiscovery(private val dispatchers: CoroutineDispatchers) : ServiceDiscovery {
@Suppress("TooGenericExceptionCaught")
override val resolvedServices: Flow<List<DiscoveredService>> =
callbackFlow {
@ -98,7 +98,7 @@ class JvmServiceDiscovery : ServiceDiscovery {
}
}
}
.flowOn(Dispatchers.IO)
.flowOn(dispatchers.io)
companion object {
/**

View file

@ -17,16 +17,23 @@
package org.meshtastic.core.network.repository
import app.cash.turbine.test
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.meshtastic.core.di.CoroutineDispatchers
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class JvmServiceDiscoveryTest {
private val testDispatchers =
UnconfinedTestDispatcher().let { dispatcher ->
CoroutineDispatchers(io = dispatcher, main = dispatcher, default = dispatcher)
}
@Test
fun `resolvedServices emits initial empty list immediately`() = runTest {
val discovery = JvmServiceDiscovery()
val discovery = JvmServiceDiscovery(testDispatchers)
discovery.resolvedServices.test {
val first = awaitItem()
assertNotNull(first, "First emission should not be null")