All Downloads are FREE. Search and download functionalities are using the official Maven repository.

orbit.client.execution.AddressableDeactivator.kt Maven / Gradle / Ivy

/*
 Copyright (C) 2015 - 2020 Electronic Arts Inc.  All rights reserved.
 This file is part of the Orbit Project .
 See license in LICENSE.
 */

package orbit.client.execution

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.toList
import mu.KotlinLogging
import orbit.util.di.ExternallyConfigured
import orbit.util.time.highResolutionTicker

typealias Deactivator = suspend (handle: Deactivatable) -> Unit

@OptIn(FlowPreview::class)
abstract class AddressableDeactivator() {
    protected val logger = KotlinLogging.logger { }

    abstract suspend fun deactivate(addressables: List, deactivate: Deactivator)

    @OptIn(ExperimentalCoroutinesApi::class)
    protected suspend fun deactivateItems(
        addressables: List,
        concurrency: Int,
        deactivationsPerSecond: Long,
        deactivate: Deactivator
    ) {
        val ticker = highResolutionTicker(deactivationsPerSecond.toDouble())

        addressables.asFlow().onEach { ticker.receive() }
            .flatMapMerge(concurrency) { a ->
                flow { emit(deactivate(a)) }
            }.toList()
    }

    class Concurrent(private val config: Config) : AddressableDeactivator() {
        data class Config(val concurrentDeactivations: Int) :
            ExternallyConfigured {
            override val instanceType: Class = Concurrent::class.java
        }

        override suspend fun deactivate(addressables: List, deactivate: Deactivator) {
            deactivateItems(addressables, config.concurrentDeactivations, Long.MAX_VALUE, deactivate)
        }
    }

    class RateLimited(private val config: Config) : AddressableDeactivator() {
        data class Config(val deactivationsPerSecond: Long) :
            ExternallyConfigured {
            override val instanceType: Class = RateLimited::class.java
        }

        override suspend fun deactivate(addressables: List, deactivate: Deactivator) {
            deactivateItems(addressables, Int.MAX_VALUE, config.deactivationsPerSecond, deactivate)
        }
    }

    class TimeSpan(private val config: Config) : AddressableDeactivator() {
        data class Config(val deactivationTimeMilliseconds: Long) :
            ExternallyConfigured {
            override val instanceType: Class = TimeSpan::class.java
        }

        override suspend fun deactivate(addressables: List, deactivate: Deactivator) {
            val deactivationsPerSecond = addressables.count() * 1000 / config.deactivationTimeMilliseconds

            deactivateItems(addressables, Int.MAX_VALUE, deactivationsPerSecond, deactivate)
        }
    }

    class Instant : AddressableDeactivator() {
        class Config : ExternallyConfigured {
            override val instanceType: Class = Instant::class.java
        }

        override suspend fun deactivate(addressables: List, deactivate: Deactivator) {
            deactivateItems(addressables, Int.MAX_VALUE, Long.MAX_VALUE, deactivate)
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy