Skip to content

Commit 799660c

Browse files
feat: update to latest version of okhttp-eventsource (#214)
* feat: update to latest version of okhttp-eventsource * feat: update retry settings, rename Handler to SSEEventHandler Signed-off-by: Jonathan Norris <[email protected]> * pull out to constant Signed-off-by: Jonathan Norris <[email protected]> * fix: cleanup example Signed-off-by: Jonathan Norris <[email protected]> --------- Signed-off-by: Jonathan Norris <[email protected]>
1 parent 845e99c commit 799660c

16 files changed

+41
-2288
lines changed

android-client-sdk/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ ext {
109109
mockk_version = '1.13.10'
110110
hamcrest_version = "2.2"
111111
okhttp_version = "4.9.3"
112+
okhttp_eventsource_version = "4.1.1"
112113
kotlin_version = '1.9.0'
113114

114115
android_core_version = "2.2.0"
@@ -118,6 +119,7 @@ ext {
118119

119120
dependencies {
120121
implementation("com.squareup.okhttp3:okhttp:$okhttp_version")
122+
implementation("com.launchdarkly:okhttp-eventsource:$okhttp_eventsource_version")
121123

122124
implementation("com.squareup.retrofit2:retrofit:$retrofit_version") {
123125
exclude group: 'com.squareup.okhttp3', module: 'okhttp'
@@ -155,4 +157,5 @@ dependencies {
155157

156158
androidTestImplementation("androidx.test.ext:junit:$androidx_junit_version")
157159
androidTestImplementation("androidx.test.espresso:espresso-core:$espresso_core_version")
160+
158161
}

android-client-sdk/src/main/java/com/devcycle/sdk/android/api/DevCycleClient.kt

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,25 @@ import com.devcycle.sdk.android.model.*
1010
import com.devcycle.sdk.android.util.DevCycleLogger
1111
import com.devcycle.sdk.android.util.DVCSharedPrefs
1212
import com.devcycle.sdk.android.util.LogLevel
13+
import com.launchdarkly.eventsource.ConnectStrategy
14+
import com.launchdarkly.eventsource.EventSource
15+
import com.launchdarkly.eventsource.background.BackgroundEventSource
16+
import com.launchdarkly.eventsource.MessageEvent
17+
import com.launchdarkly.eventsource.ReadyState
1318
import kotlinx.coroutines.*
1419
import kotlinx.coroutines.sync.Mutex
1520
import kotlinx.coroutines.sync.withLock
16-
import org.jetbrains.annotations.TestOnly
1721
import org.json.JSONArray
1822
import org.json.JSONObject
1923
import java.lang.ref.WeakReference
2024
import java.net.URI
2125
import java.util.concurrent.ConcurrentLinkedQueue
22-
import java.util.concurrent.ExecutorService
23-
import java.util.concurrent.Executors
26+
import java.util.concurrent.TimeUnit
2427
import java.util.concurrent.atomic.AtomicBoolean
2528
import kotlin.coroutines.CoroutineContext
2629

30+
private const val EVENT_SOURCE_RETRY_DELAY_MIN: Long = 5
31+
2732
/**
2833
* Main entry point for SDK user
2934
* The class is constructed by calling DevCycleClient.builder(){builder options}.build()
@@ -43,8 +48,7 @@ class DevCycleClient private constructor(
4348
private val coroutineContext: CoroutineContext = Dispatchers.Default
4449
) {
4550
private var config: BucketedUserConfig? = null
46-
private var eventSource: EventSource? = null
47-
private var executorService: ExecutorService? = null
51+
private var backgroundEventSource: BackgroundEventSource? = null
4852
private val defaultIntervalInMs: Long = 10000
4953
private val flushInMs: Long = options?.flushEventsIntervalMs ?: defaultIntervalInMs
5054
private val dvcSharedPrefs: DVCSharedPrefs = DVCSharedPrefs(context)
@@ -90,8 +94,11 @@ class DevCycleClient private constructor(
9094
initEventSource()
9195
val application : Application = context.applicationContext as Application
9296

93-
val lifecycleCallbacks = DVCLifecycleCallbacks(onPauseApplication, onResumeApplication,
94-
config?.sse?.inactivityDelay?.toLong(), customLifecycleHandler
97+
val lifecycleCallbacks = DVCLifecycleCallbacks(
98+
onPauseApplication,
99+
onResumeApplication,
100+
config?.sse?.inactivityDelay?.toLong(),
101+
customLifecycleHandler
95102
)
96103
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
97104
}
@@ -114,16 +121,16 @@ class DevCycleClient private constructor(
114121
coroutineScope.launch {
115122
withContext(Dispatchers.IO) {
116123
DevCycleLogger.d("Closing Realtime Updates connection")
117-
eventSource?.close()
124+
backgroundEventSource?.close()
118125
}
119126
}
120127
}
121128

122129
private val onResumeApplication = fun () {
123-
if (eventSource?.state != ReadyState.OPEN) {
130+
if (backgroundEventSource?.eventSource?.state != ReadyState.OPEN) {
124131
coroutineScope.launch {
125132
withContext(Dispatchers.IO) {
126-
eventSource?.close()
133+
backgroundEventSource?.close()
127134
DevCycleLogger.d("Attempting to restart Realtime Updates connection")
128135
initEventSource()
129136
refetchConfig(false, null, null)
@@ -138,11 +145,16 @@ class DevCycleClient private constructor(
138145
return
139146
}
140147
if (config?.sse?.url == null) { return }
141-
eventSource = EventSource.Builder(Handler(fun(messageEvent: MessageEvent?) {
142-
if (messageEvent == null) { return }
148+
149+
val handler = SSEEventHandler(fun(messageEvent: MessageEvent?) {
150+
if (messageEvent == null) {
151+
return
152+
}
143153

144154
val data = JSONObject(messageEvent.data)
145-
if (!data.has("data")) { return }
155+
if (!data.has("data")) {
156+
return
157+
}
146158

147159
val innerData = JSONObject(data.get("data") as String)
148160
val lastModified = if (innerData.has("lastModified")) {
@@ -156,17 +168,17 @@ class DevCycleClient private constructor(
156168
} else null
157169

158170
if (type == "refetchConfig" || type == "") { // Refetch the config if theres no type
171+
DevCycleLogger.d("SSE Message: Refetching config")
159172
refetchConfig(true, lastModified, etag)
160173
}
161-
}), URI(config?.sse?.url)).executor(this.getValidExecutorService()).build()
162-
eventSource?.start()
163-
}
174+
})
175+
val builder = EventSource.Builder(
176+
ConnectStrategy.http(URI(config?.sse?.url))
177+
.readTimeout(EVENT_SOURCE_RETRY_DELAY_MIN, TimeUnit.MINUTES)
178+
)
164179

165-
private fun getValidExecutorService(): ExecutorService? {
166-
if (executorService == null || executorService?.isTerminated == true) {
167-
executorService = Executors.newSingleThreadExecutor()
168-
}
169-
return executorService
180+
backgroundEventSource = BackgroundEventSource.Builder(handler, builder).build()
181+
backgroundEventSource?.start()
170182
}
171183

172184
fun onInitialized(callback: DevCycleCallback<String>) {
@@ -267,7 +279,7 @@ class DevCycleClient private constructor(
267279
fun close(callback: DevCycleCallback<String>? = null) {
268280
coroutineScope.launch {
269281
withContext(Dispatchers.IO) {
270-
eventSource?.close()
282+
backgroundEventSource?.close()
271283
}
272284
withContext(coroutineContext) {
273285
eventQueue.close(callback)

android-client-sdk/src/main/java/com/devcycle/sdk/android/eventsource/AsyncEventHandler.java

Lines changed: 0 additions & 122 deletions
This file was deleted.

0 commit comments

Comments
 (0)