Skip to content

Commit

Permalink
Move observation handling to common source set
Browse files Browse the repository at this point in the history
  • Loading branch information
twyatt committed Nov 24, 2021
1 parent defa3a1 commit 340576b
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 343 deletions.
5 changes: 0 additions & 5 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@ fun uuid(
version: String = "0.3.1"
): String = "com.benasher44:$artifact:$version"

fun stately(
module: String,
version: String = "1.1.10-a1"
): String = "co.touchlab:stately-$module:$version"

fun wrappers(
version: String = "1.0.1-pre.264-kotlin-1.5.31"
) = "org.jetbrains.kotlin-wrappers:kotlin-extensions:$version"
Expand Down
12 changes: 8 additions & 4 deletions core/api/core.api
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public final class com/juul/kable/AndroidPeripheral : com/juul/kable/Peripheral
public fun disconnect (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun getMtu ()Lkotlinx/coroutines/flow/StateFlow;
public fun getServices ()Ljava/util/List;
public fun getState ()Lkotlinx/coroutines/flow/Flow;
public fun getState ()Lkotlinx/coroutines/flow/StateFlow;
public fun observe (Lcom/juul/kable/Characteristic;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
public fun read (Lcom/juul/kable/Characteristic;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun read (Lcom/juul/kable/Descriptor;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down Expand Up @@ -58,7 +58,7 @@ public final class com/juul/kable/CharacteristicKt {
public static final fun characteristicOf (Ljava/lang/String;Ljava/lang/String;)Lcom/juul/kable/Characteristic;
}

public final class com/juul/kable/ConnectionLostException : java/io/IOException {
public final class com/juul/kable/ConnectionLostException : com/juul/kable/NotConnectedException {
public fun <init> ()V
}

Expand Down Expand Up @@ -154,7 +154,11 @@ public final class com/juul/kable/ManufacturerData {
public final fun getData ()[B
}

public final class com/juul/kable/NotReadyException : java/io/IOException {
public class com/juul/kable/NotConnectedException : java/io/IOException {
public fun <init> ()V
}

public final class com/juul/kable/NotReadyException : com/juul/kable/NotConnectedException {
public fun <init> ()V
}

Expand All @@ -168,7 +172,7 @@ public abstract interface class com/juul/kable/Peripheral {
public abstract fun connect (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun disconnect (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getServices ()Ljava/util/List;
public abstract fun getState ()Lkotlinx/coroutines/flow/Flow;
public abstract fun getState ()Lkotlinx/coroutines/flow/StateFlow;
public abstract fun observe (Lcom/juul/kable/Characteristic;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/Flow;
public abstract fun read (Lcom/juul/kable/Characteristic;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun read (Lcom/juul/kable/Descriptor;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
3 changes: 0 additions & 3 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,6 @@ kotlin {

val appleMain by creating {
dependsOn(commonMain)
dependencies {
implementation(stately("isolate"))
}
}

val appleTest by creating
Expand Down
2 changes: 1 addition & 1 deletion core/src/androidMain/kotlin/Connection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.juul.kable

import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGatt.GATT_SUCCESS
import com.juul.kable.AndroidObservationEvent.CharacteristicChange
import com.juul.kable.ObservationEvent.CharacteristicChange
import com.juul.kable.gatt.Callback
import com.juul.kable.gatt.GattStatus
import kotlinx.coroutines.CoroutineDispatcher
Expand Down
11 changes: 11 additions & 0 deletions core/src/androidMain/kotlin/Observations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.juul.kable

internal actual fun Peripheral.observationHandler(): Observation.Handler = object : Observation.Handler {
override suspend fun startObservation(characteristic: Characteristic) {
(this@observationHandler as AndroidPeripheral).startObservation(characteristic)
}

override suspend fun stopObservation(characteristic: Characteristic) {
(this@observationHandler as AndroidPeripheral).stopObservation(characteristic)
}
}
11 changes: 8 additions & 3 deletions core/src/androidMain/kotlin/Peripheral.kt
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public enum class Priority { Low, Balanced, High }

public class AndroidPeripheral internal constructor(
parentCoroutineContext: CoroutineContext,
internal val bluetoothDevice: BluetoothDevice,
private val bluetoothDevice: BluetoothDevice,
private val transport: Transport,
private val phy: Phy,
private val onServicesDiscovered: ServicesDiscoveredAction,
Expand All @@ -137,8 +137,10 @@ public class AndroidPeripheral internal constructor(

private val logger = Logger(logging, tag = "Kable/Peripheral", identifier = bluetoothDevice.address)

internal val platformIdentifier = bluetoothDevice.address

private val _state = MutableStateFlow<State>(State.Disconnected())
public override val state: Flow<State> = _state.asStateFlow()
public override val state: StateFlow<State> = _state.asStateFlow()

private val receiver = registerBluetoothStateBroadcastReceiver { state ->
if (state == STATE_OFF) {
Expand Down Expand Up @@ -168,7 +170,7 @@ public class AndroidPeripheral internal constructor(
*/
public val mtu: StateFlow<Int?> = _mtu.asStateFlow()

private val observers = Observers(this, _state, logging)
private val observers = Observers<ByteArray>(this, logging)

@Volatile
private var _platformServices: List<PlatformService>? = null
Expand Down Expand Up @@ -509,3 +511,6 @@ private fun checkBluetoothAdapterState(
throw BluetoothDisabledException("Bluetooth adapter state is $actualName ($actual), but $expectedName ($expected) was required.")
}
}

internal actual val Peripheral.identifier: String
get() = (this as AndroidPeripheral).platformIdentifier
11 changes: 11 additions & 0 deletions core/src/appleMain/kotlin/Observations.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.juul.kable

internal actual fun Peripheral.observationHandler(): Observation.Handler = object : Observation.Handler {
override suspend fun startObservation(characteristic: Characteristic) {
(this@observationHandler as ApplePeripheral).startNotifications(characteristic)
}

override suspend fun stopObservation(characteristic: Characteristic) {
(this@observationHandler as ApplePeripheral).stopNotifications(characteristic)
}
}
158 changes: 0 additions & 158 deletions core/src/appleMain/kotlin/Observers.kt

This file was deleted.

19 changes: 14 additions & 5 deletions core/src/appleMain/kotlin/Peripheral.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -100,7 +101,11 @@ public class ApplePeripheral internal constructor(
private val logger = Logger(logging, identifier = cbPeripheral.identifier.UUIDString)

private val _state = MutableStateFlow<State>(State.Disconnected())
override val state: Flow<State> = _state.asStateFlow()
override val state: StateFlow<State> = _state.asStateFlow()

private val observers = Observers<NSData>(this, logging)

internal val platformIdentifier = cbPeripheral.identifier.UUIDString

init {
centralManager.delegate
Expand All @@ -112,13 +117,14 @@ public class ApplePeripheral internal constructor(
detail("state", event.toString())
}
}
.onEach { event ->
if (event is DidFailToConnect || event is DidDisconnect) observers.onConnectionLost()
}
.map { event -> event.toState() }
.onEach { _state.value = it }
.launchIn(scope)
}

private val observers = Observers(this, logger)

private val _platformServices = atomic<List<PlatformService>?>(null)
private val platformServices: List<PlatformService>
get() = checkNotNull(_platformServices.value) {
Expand Down Expand Up @@ -164,7 +170,7 @@ public class ApplePeripheral internal constructor(
.takeWhile { it !== Closed }
.mapNotNull { it as? Data }
.map {
AppleObservationEvent.CharacteristicChange(
ObservationEvent.CharacteristicChange(
characteristic = it.cbCharacteristic.toLazyCharacteristic(),
data = it.data
)
Expand All @@ -180,7 +186,7 @@ public class ApplePeripheral internal constructor(

_state.value = State.Connecting.Observes
logger.verbose { message = "Configuring characteristic observations" }
observers.rewire()
observers.onConnected()
} catch (t: Throwable) {
logger.error(t) { message = "Failed to connect" }
withContext(NonCancellable) {
Expand Down Expand Up @@ -408,3 +414,6 @@ private fun NSError.toStatus(): State.Disconnected.Status = when (code) {
CBErrorEncryptionTimedOut -> EncryptionTimedOut
else -> Unknown(code.toInt())
}

internal actual val Peripheral.identifier: String
get() = (this as ApplePeripheral).platformIdentifier
File renamed without changes.
25 changes: 25 additions & 0 deletions core/src/commonMain/kotlin/ObservationEvent.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.juul.kable

internal sealed class ObservationEvent<T> {

abstract val characteristic: Characteristic

data class CharacteristicChange<T>(
override val characteristic: Characteristic,
val data: T,
) : ObservationEvent<T>()

data class Error<T>(
override val characteristic: Characteristic,
val cause: Throwable,
) : ObservationEvent<T>()
}

internal fun <T> dematerialize(event: ObservationEvent<T>): T = when (event) {
is ObservationEvent.Error -> throw event.cause
is ObservationEvent.CharacteristicChange -> event.data
}

internal fun <T> ObservationEvent<T>.isAssociatedWith(characteristic: Characteristic): Boolean =
this.characteristic.characteristicUuid == characteristic.characteristicUuid &&
this.characteristic.serviceUuid == characteristic.serviceUuid
Loading

0 comments on commit 340576b

Please sign in to comment.