commonMain.internal.FormManagerEventsBus.kt Maven / Gradle / Ivy
package io.kform.internal
import io.kform.*
import io.kform.collections.MutablePathMultimap
import io.kform.collections.PathMultimapEntryId
import io.kform.collections.mutablePathMultimapOf
import io.kform.collections.set
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
/** Number of events to process before allowing the browser to "breathe". */
private const val BREATHING_COUNT = 10_000
/** Bus used to emit events to the user. */
internal class FormManagerEventsBus {
private val subscriptionsMutex = Mutex()
private val subscriptions: MutablePathMultimap = mutablePathMultimapOf()
private var delayCounter = 0
suspend fun emit(event: FormManagerEvent<*>) {
// Allow browser to "breathe" every [BREATHING_COUNT] events
if (++delayCounter % BREATHING_COUNT == 0) delayImmediate()
subscriptionsMutex.withLock {
FormManager.logger.trace {
val subscriptionPaths = subscriptions.entries(event.path).map { it.path }.toList()
"Emitting event to subscriptions $subscriptionPaths: $event"
}
for (handler in subscriptions[event.path]) {
handler(event)
}
}
}
suspend fun subscribe(
path: AbsolutePath,
onSubscription: OnSubscription? = null,
eventsHandler: EventHandler
): Unsubscribe =
subscriptionsMutex.withLock {
val id = subscriptions.set(path, eventsHandler)
FormManager.logger.trace {
"Subscribed to '$path' (total subscriptions: ${subscriptions.size})"
}
onSubscription?.invoke()
return@withLock { unsubscribe(id, path) }
}
private suspend fun unsubscribe(id: PathMultimapEntryId, path: AbsolutePath) =
subscriptionsMutex.withLock {
subscriptions.removeEntry(id)
FormManager.logger.trace {
"Unsubscribed from '$path' (total subscriptions: ${subscriptions.size})"
}
}
}