From e89b04e2f62c2d3fcf6bdc0ab97334dd32f78c63 Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Fri, 25 Feb 2022 16:29:36 +0100 Subject: [PATCH] feat: unify state holder api --- build.gradle.kts | 2 +- .../client/session/BaseInitHandler.kt | 14 ++++------- .../client/session/ClientSession.kt | 14 ++++------- .../protocol/io/CoroutineChannel.kt | 14 ++++------- .../protocol/syncables/HeartBeatHandler.kt | 13 +++++----- .../protocol/syncables/ObjectRepository.kt | 14 ++++------- .../syncables/StatefulSyncableObject.kt | 14 ++++------- .../libquassel/protocol/util/StateHolder.kt | 17 +++++++++++++ .../protocol/util/StateHolderExtensions.kt | 25 +++++++++++++++++++ 9 files changed, 74 insertions(+), 53 deletions(-) create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolder.kt create mode 100644 libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolderExtensions.kt diff --git a/build.gradle.kts b/build.gradle.kts index c8b02b8..63be78d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,4 +15,4 @@ plugins { } group = "de.justjanne.libquassel" -version = "0.7.0" +version = "0.8.0" diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/BaseInitHandler.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/BaseInitHandler.kt index 1b14319..90dadc8 100644 --- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/BaseInitHandler.kt +++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/BaseInitHandler.kt @@ -12,13 +12,14 @@ package de.justjanne.libquassel.client.session import de.justjanne.libquassel.client.util.CoroutineQueue import de.justjanne.libquassel.protocol.syncables.ObjectIdentifier import de.justjanne.libquassel.protocol.syncables.SyncableStub +import de.justjanne.libquassel.protocol.util.StateHolder import de.justjanne.libquassel.protocol.util.update import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow class BaseInitHandler( private val session: ClientSession -) { +) : StateHolder<BaseInitHandlerState> { private val coroutineQueue = CoroutineQueue<Unit>() fun sync(stub: SyncableStub) { @@ -45,12 +46,7 @@ class BaseInitHandler( coroutineQueue.wait() } else Unit - @Suppress("NOTHING_TO_INLINE") - inline fun state(): BaseInitHandlerState = state.value - - @Suppress("NOTHING_TO_INLINE") - inline fun flow(): Flow<BaseInitHandlerState> = state - - @PublishedApi - internal val state = MutableStateFlow(BaseInitHandlerState()) + override fun state(): BaseInitHandlerState = state.value + override fun flow(): Flow<BaseInitHandlerState> = state + private val state = MutableStateFlow(BaseInitHandlerState()) } diff --git a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/ClientSession.kt b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/ClientSession.kt index f9d4448..58d4c6b 100644 --- a/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/ClientSession.kt +++ b/libquassel-client/src/main/kotlin/de/justjanne/libquassel/client/session/ClientSession.kt @@ -38,6 +38,7 @@ import de.justjanne.libquassel.protocol.syncables.common.Network import de.justjanne.libquassel.protocol.syncables.common.NetworkConfig import de.justjanne.libquassel.protocol.syncables.state.CertManagerState import de.justjanne.libquassel.protocol.syncables.state.NetworkState +import de.justjanne.libquassel.protocol.util.StateHolder import de.justjanne.libquassel.protocol.util.log.info import de.justjanne.libquassel.protocol.util.update import de.justjanne.libquassel.protocol.variant.QVariantMap @@ -51,7 +52,7 @@ class ClientSession( protocolFeatures: ProtocolFeatures, protocols: List<ProtocolMeta>, sslContext: SSLContext -) : Session { +) : Session, StateHolder<ClientSessionState> { override val side = ProtocolSide.CLIENT override val rpcHandler = ClientRpcHandler(this) @@ -202,14 +203,9 @@ class ClientSession( override val networkConfig get() = state().networkConfig - @Suppress("NOTHING_TO_INLINE") - inline fun state(): ClientSessionState = state.value - - @Suppress("NOTHING_TO_INLINE") - inline fun flow(): Flow<ClientSessionState> = state - - @PublishedApi - internal val state = MutableStateFlow( + override fun state(): ClientSessionState = state.value + override fun flow(): Flow<ClientSessionState> = state + private val state = MutableStateFlow( ClientSessionState( networks = mapOf(), identities = mapOf(), diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/CoroutineChannel.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/CoroutineChannel.kt index 9ac7289..22e3de9 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/CoroutineChannel.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/io/CoroutineChannel.kt @@ -9,6 +9,7 @@ package de.justjanne.libquassel.protocol.io +import de.justjanne.libquassel.protocol.util.StateHolder import de.justjanne.libquassel.protocol.util.update import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher @@ -21,7 +22,7 @@ import java.nio.ByteBuffer import java.util.concurrent.Executors import javax.net.ssl.SSLContext -class CoroutineChannel { +class CoroutineChannel : StateHolder<CoroutineChannelState> { private lateinit var channel: StreamChannel private val writeContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher() private val readContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher() @@ -81,12 +82,7 @@ class CoroutineChannel { } } - @Suppress("NOTHING_TO_INLINE") - inline fun state(): CoroutineChannelState = state.value - - @Suppress("NOTHING_TO_INLINE") - inline fun flow(): Flow<CoroutineChannelState> = state - - @PublishedApi - internal val state = MutableStateFlow(CoroutineChannelState()) + override fun state(): CoroutineChannelState = state.value + override fun flow(): Flow<CoroutineChannelState> = state + private val state = MutableStateFlow(CoroutineChannelState()) } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HeartBeatHandler.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HeartBeatHandler.kt index 5435687..268c0c5 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HeartBeatHandler.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/HeartBeatHandler.kt @@ -9,11 +9,12 @@ package de.justjanne.libquassel.protocol.syncables +import de.justjanne.libquassel.protocol.util.StateHolder import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import org.threeten.bp.Instant -class HeartBeatHandler { +class HeartBeatHandler : StateHolder<Long?> { private var lastReceived: Instant? = null /** @@ -30,14 +31,12 @@ class HeartBeatHandler { fun recomputeLatency(current: Instant, force: Boolean) { val last = lastReceived?.toEpochMilli() ?: return val roundtripLatency = current.toEpochMilli() - last - if (force || roundtripLatency > this.roundtripLatency.value ?: return) { + if (force || roundtripLatency > (this.roundtripLatency.value ?: return)) { this.roundtripLatency.value = roundtripLatency } } - @Suppress("NOTHING_TO_INLINE") - inline fun flow(): Flow<Long?> = roundtripLatency - - @PublishedApi - internal val roundtripLatency = MutableStateFlow<Long?>(null) + override fun flow(): Flow<Long?> = roundtripLatency + override fun state(): Long? = roundtripLatency.value + private val roundtripLatency = MutableStateFlow<Long?>(null) } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/ObjectRepository.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/ObjectRepository.kt index eeab61c..a783468 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/ObjectRepository.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/ObjectRepository.kt @@ -9,11 +9,12 @@ package de.justjanne.libquassel.protocol.syncables +import de.justjanne.libquassel.protocol.util.StateHolder import de.justjanne.libquassel.protocol.util.update import de.justjanne.libquassel.protocol.variant.QVariantMap import kotlinx.coroutines.flow.MutableStateFlow -class ObjectRepository { +class ObjectRepository : StateHolder<ObjectRepositoryState> { fun add(syncable: SyncableStub): Boolean { val identifier = ObjectIdentifier(syncable) if (syncable is StatefulSyncableStub) { @@ -78,12 +79,7 @@ class ObjectRepository { return find(T::class.java.simpleName, objectName) as? T } - @Suppress("NOTHING_TO_INLINE") - inline fun state() = flow().value - - @Suppress("NOTHING_TO_INLINE") - inline fun flow() = state - - @PublishedApi - internal val state = MutableStateFlow(ObjectRepositoryState()) + override fun state() = flow().value + override fun flow() = state + private val state = MutableStateFlow(ObjectRepositoryState()) } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt index 0b10671..e3260e3 100644 --- a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/syncables/StatefulSyncableObject.kt @@ -10,6 +10,7 @@ package de.justjanne.libquassel.protocol.syncables import de.justjanne.libquassel.protocol.session.Session +import de.justjanne.libquassel.protocol.util.StateHolder import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -17,7 +18,7 @@ abstract class StatefulSyncableObject<T>( session: Session?, className: String, state: T -) : SyncableObject(session, className), StatefulSyncableStub { +) : SyncableObject(session, className), StatefulSyncableStub, StateHolder<T> { override fun toString(): String { return "$className(objectName=$objectName, state=${state()})" } @@ -38,12 +39,7 @@ abstract class StatefulSyncableObject<T>( return result } - @Suppress("NOTHING_TO_INLINE") - inline fun state(): T = state.value - - @Suppress("NOTHING_TO_INLINE") - inline fun flow(): Flow<T> = state - - @PublishedApi - internal val state = MutableStateFlow(state) + override fun state(): T = state.value + override fun flow(): Flow<T> = state + protected val state = MutableStateFlow(state) } diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolder.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolder.kt new file mode 100644 index 0000000..03284a9 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolder.kt @@ -0,0 +1,17 @@ +/* + * libquassel + * Copyright (c) 2022 Janne Mareike Koschinski + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at https://mozilla.org/MPL/2.0/. + */ + +package de.justjanne.libquassel.protocol.util + +import kotlinx.coroutines.flow.Flow + +interface StateHolder<T> { + fun state(): T + fun flow(): Flow<T> +} diff --git a/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolderExtensions.kt b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolderExtensions.kt new file mode 100644 index 0000000..780c6d2 --- /dev/null +++ b/libquassel-protocol/src/main/kotlin/de/justjanne/libquassel/protocol/util/StateHolderExtensions.kt @@ -0,0 +1,25 @@ +/* + * libquassel + * Copyright (c) 2022 Janne Mareike Koschinski + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at https://mozilla.org/MPL/2.0/. + */ + +package de.justjanne.libquassel.protocol.util + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMapLatest + +@ExperimentalCoroutinesApi +@Suppress("NOTHING_TO_INLINE") +inline fun <T> Flow<StateHolder<T>?>.flatMap(): Flow<T?> = + flatMapLatest { it?.flow() ?: emptyFlow() } + +@ExperimentalCoroutinesApi +inline fun <reified T> Flow<Iterable<StateHolder<T>>?>.combineLatest(): Flow<List<T>> = + flatMapLatest { combine(it?.map(StateHolder<T>::flow).orEmpty(), ::listOf) } -- GitLab