Skip to content

Commit 69379d2

Browse files
committed
make the eventing provider specific instead of being singletone
Signed-off-by: vahid torkaman <[email protected]>
1 parent 4d19a0a commit 69379d2

File tree

10 files changed

+122
-91
lines changed

10 files changed

+122
-91
lines changed

OpenFeature/src/main/java/dev/openfeature/sdk/FeatureProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package dev.openfeature.sdk
22

3-
interface FeatureProvider {
3+
import dev.openfeature.sdk.events.ProviderEventObserver
4+
5+
interface FeatureProvider : ProviderEventObserver {
46
val hooks: List<Hook<*>>
57
val metadata: ProviderMetadata
68

OpenFeature/src/main/java/dev/openfeature/sdk/NoOpProvider.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package dev.openfeature.sdk
22

3+
import dev.openfeature.sdk.events.OpenFeatureEvents
4+
import kotlinx.coroutines.flow.Flow
5+
import kotlinx.coroutines.flow.flow
6+
import kotlin.reflect.KClass
7+
38
class NoOpProvider(override val hooks: List<Hook<*>> = listOf()) : FeatureProvider {
49
override val metadata: ProviderMetadata = NoOpProviderMetadata("No-op provider")
510
override fun initialize(initialContext: EvaluationContext?) {
@@ -57,5 +62,9 @@ class NoOpProvider(override val hooks: List<Hook<*>> = listOf()) : FeatureProvid
5762
return ProviderEvaluation(defaultValue, "Passed in default", Reason.DEFAULT.toString())
5863
}
5964

65+
override fun <T : OpenFeatureEvents> observe(kClass: KClass<T>): Flow<T> = flow { }
66+
67+
override fun isProviderReady(): Boolean = true
68+
6069
data class NoOpProviderMetadata(override val name: String?) : ProviderMetadata
6170
}

OpenFeature/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.kt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
package dev.openfeature.sdk
22

3-
import dev.openfeature.sdk.events.EventHandler
4-
import dev.openfeature.sdk.events.OpenFeatureEvents
5-
import dev.openfeature.sdk.events.observe
6-
import kotlinx.coroutines.CoroutineDispatcher
7-
83
@Suppress("TooManyFunctions")
94
object OpenFeatureAPI {
105
private var provider: FeatureProvider? = null
@@ -23,10 +18,6 @@ object OpenFeatureAPI {
2318
return provider
2419
}
2520

26-
inline fun <reified T : OpenFeatureEvents> observeEvents(dispatcher: CoroutineDispatcher) =
27-
EventHandler.eventsObserver(dispatcher)
28-
.observe<T>()
29-
3021
fun clearProvider() {
3122
provider = null
3223
}

OpenFeature/src/main/java/dev/openfeature/sdk/async/AsyncClient.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dev.openfeature.sdk.async
22

3-
import dev.openfeature.sdk.OpenFeatureClient
3+
import dev.openfeature.sdk.Client
4+
import dev.openfeature.sdk.FeatureProvider
45
import dev.openfeature.sdk.Value
56
import kotlinx.coroutines.CoroutineDispatcher
67
import kotlinx.coroutines.flow.Flow
@@ -16,10 +17,12 @@ interface AsyncClient {
1617
}
1718

1819
internal class AsyncClientImpl(
19-
private val client: OpenFeatureClient,
20+
private val client: Client,
21+
private val provider: FeatureProvider,
2022
private val dispatcher: CoroutineDispatcher
2123
) : AsyncClient {
22-
private fun <T> observeEvents(callback: () -> T) = observeProviderReady(dispatcher)
24+
private fun <T> observeEvents(callback: () -> T) = provider
25+
.observeProviderReady(dispatcher)
2326
.map { callback() }
2427
.distinctUntilChanged()
2528

OpenFeature/src/main/java/dev/openfeature/sdk/async/Extensions.kt

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package dev.openfeature.sdk.async
22

3+
import dev.openfeature.sdk.OpenFeatureAPI
34
import dev.openfeature.sdk.OpenFeatureClient
4-
import dev.openfeature.sdk.events.EventHandler
55
import dev.openfeature.sdk.events.OpenFeatureEvents
6+
import dev.openfeature.sdk.events.ProviderEventObserver
67
import dev.openfeature.sdk.events.observe
78
import kotlinx.coroutines.CoroutineDispatcher
89
import kotlinx.coroutines.CoroutineScope
@@ -13,21 +14,36 @@ import kotlinx.coroutines.flow.take
1314
import kotlinx.coroutines.launch
1415
import kotlinx.coroutines.suspendCancellableCoroutine
1516

16-
fun OpenFeatureClient.toAsync(dispatcher: CoroutineDispatcher = Dispatchers.IO): AsyncClient {
17-
return AsyncClientImpl(this, dispatcher)
17+
fun OpenFeatureClient.toAsync(
18+
dispatcher: CoroutineDispatcher = Dispatchers.IO
19+
): AsyncClient {
20+
val provider = OpenFeatureAPI.getProvider()
21+
requireNotNull(provider)
22+
return AsyncClientImpl(
23+
this,
24+
provider,
25+
dispatcher
26+
)
1827
}
1928

20-
internal fun observeProviderReady(
29+
internal fun ProviderEventObserver.observeProviderReady(
2130
dispatcher: CoroutineDispatcher = Dispatchers.IO
22-
) = EventHandler.eventsObserver(dispatcher)
23-
.observe<OpenFeatureEvents.ProviderReady>()
31+
) = observe<OpenFeatureEvents.ProviderReady>()
2432
.onStart {
25-
if (EventHandler.providerStatus().isProviderReady()) {
33+
if (isProviderReady()) {
2634
this.emit(OpenFeatureEvents.ProviderReady)
2735
}
2836
}
2937

30-
suspend fun awaitProviderReady(
38+
suspend fun OpenFeatureAPI.awaitProviderReady(
39+
dispatcher: CoroutineDispatcher = Dispatchers.IO
40+
) {
41+
val provider = getProvider()
42+
requireNotNull(provider)
43+
return provider.awaitProviderReady(dispatcher)
44+
}
45+
46+
suspend fun ProviderEventObserver.awaitProviderReady(
3147
dispatcher: CoroutineDispatcher = Dispatchers.IO
3248
) = suspendCancellableCoroutine { continuation ->
3349
val coroutineScope = CoroutineScope(dispatcher)
@@ -40,8 +56,7 @@ suspend fun awaitProviderReady(
4056
}
4157

4258
coroutineScope.launch {
43-
EventHandler.eventsObserver()
44-
.observe<OpenFeatureEvents.ProviderError>()
59+
observe<OpenFeatureEvents.ProviderError>()
4560
.take(1)
4661
.collect {
4762
continuation.resumeWith(Result.failure(it.error))

OpenFeature/src/main/java/dev/openfeature/sdk/events/EventHandler.kt

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package dev.openfeature.sdk.events
22

33
import kotlinx.coroutines.CoroutineDispatcher
44
import kotlinx.coroutines.CoroutineScope
5-
import kotlinx.coroutines.Dispatchers
65
import kotlinx.coroutines.Job
76
import kotlinx.coroutines.cancelChildren
87
import kotlinx.coroutines.flow.Flow
@@ -12,21 +11,18 @@ import kotlinx.coroutines.flow.filterIsInstance
1211
import kotlinx.coroutines.launch
1312
import kotlin.reflect.KClass
1413

15-
interface ProviderStatus {
16-
fun isProviderReady(): Boolean
17-
}
18-
19-
interface EventObserver {
14+
interface ProviderEventObserver {
2015
fun <T : OpenFeatureEvents> observe(kClass: KClass<T>): Flow<T>
16+
fun isProviderReady(): Boolean
2117
}
2218

2319
interface EventsPublisher {
2420
fun publish(event: OpenFeatureEvents)
2521
}
2622

27-
inline fun <reified T : OpenFeatureEvents> EventObserver.observe() = observe(T::class)
23+
inline fun <reified T : OpenFeatureEvents> ProviderEventObserver.observe() = observe(T::class)
2824

29-
class EventHandler(dispatcher: CoroutineDispatcher) : EventObserver, EventsPublisher, ProviderStatus {
25+
class EventHandler(dispatcher: CoroutineDispatcher) : ProviderEventObserver, EventsPublisher {
3026
private val sharedFlow: MutableSharedFlow<OpenFeatureEvents> = MutableSharedFlow()
3127
private val isProviderReady = MutableStateFlow(false)
3228
private val job = Job()
@@ -62,23 +58,4 @@ class EventHandler(dispatcher: CoroutineDispatcher) : EventObserver, EventsPubli
6258
override fun isProviderReady(): Boolean {
6359
return isProviderReady.value
6460
}
65-
66-
companion object {
67-
@Volatile
68-
private var instance: EventHandler? = null
69-
70-
private fun getInstance(dispatcher: CoroutineDispatcher) =
71-
instance ?: synchronized(this) {
72-
instance ?: create(dispatcher).also { instance = it }
73-
}
74-
75-
fun eventsObserver(dispatcher: CoroutineDispatcher = Dispatchers.IO): EventObserver =
76-
getInstance(dispatcher)
77-
internal fun providerStatus(dispatcher: CoroutineDispatcher = Dispatchers.IO): ProviderStatus =
78-
getInstance(dispatcher)
79-
fun eventsPublisher(dispatcher: CoroutineDispatcher = Dispatchers.IO): EventsPublisher =
80-
getInstance(dispatcher)
81-
82-
private fun create(dispatcher: CoroutineDispatcher) = EventHandler(dispatcher)
83-
}
8461
}

0 commit comments

Comments
 (0)