Skip to content

SegmentDestination refactor and add cdnHost config option #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.segment.analytics.kotlin.core.platform.DestinationPlugin
import com.segment.analytics.kotlin.core.platform.Plugin
import com.segment.analytics.kotlin.core.platform.Timeline
import com.segment.analytics.kotlin.core.platform.plugins.ContextPlugin
import com.segment.analytics.kotlin.core.platform.plugins.SegmentDestination
import com.segment.analytics.kotlin.core.platform.plugins.StartupQueue
import com.segment.analytics.kotlin.core.platform.plugins.log
import kotlinx.coroutines.CoroutineDispatcher
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.segment.analytics.kotlin.core

import com.segment.analytics.kotlin.core.Constants.DEFAULT_API_HOST
import com.segment.analytics.kotlin.core.Constants.DEFAULT_CDN_HOST
import com.segment.analytics.kotlin.core.utilities.ConcreteStorageProvider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -42,7 +44,8 @@ data class Configuration(
var flushInterval: Int = 30,
val defaultSettings: Settings = Settings(),
var autoAddSegmentDestination: Boolean = true,
var apiHost: String = "api.segment.io/v1"
var apiHost: String = DEFAULT_API_HOST,
var cdnHost: String = DEFAULT_CDN_HOST
) {
fun isValid(): Boolean {
return writeKey.isNotBlank() && application != null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ package com.segment.analytics.kotlin.core

object Constants {
const val LIBRARY_VERSION = "1.2.0"
const val DEFAULT_API_HOST = "api.segment.io/v1"
const val DEFAULT_CDN_HOST = "cdn-settings.segment.com/v1"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import java.util.zip.GZIPOutputStream
class HTTPClient(private val writeKey: String) {
internal val authHeader = authorizationHeader(writeKey)

fun settings(): Connection {
fun settings(cdnHost: String): Connection {
val connection: HttpURLConnection =
openConnection("https://cdn-settings.segment.com/v1/projects/$writeKey/settings")
openConnection("https://$cdnHost/projects/$writeKey/settings")
val responseCode = connection.responseCode
if (responseCode != HttpURLConnection.HTTP_OK) {
connection.disconnect()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ internal fun Analytics.update(settings: Settings, type: Plugin.UpdateType) {
*/
fun Analytics.checkSettings() {
val writeKey = configuration.writeKey
val cdnHost = configuration.cdnHost

// stop things; queue in case our settings have changed.
store.dispatch(System.ToggleRunningAction(running = false), System::class)

analyticsScope.launch(ioDispatcher) {
log("Fetching settings on ${Thread.currentThread().name}")
val settingsObj: Settings? = try {
val connection = HTTPClient(writeKey).settings()
val connection = HTTPClient(writeKey).settings(cdnHost)
val settingsString =
connection.inputStream?.bufferedReader()?.use(BufferedReader::readText) ?: ""
log("Fetched Settings: $settingsString")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,7 @@ class ConfigurationBuilder (writeKey: String) {

fun setApiHost(apiHost: String) = apply { configuration.apiHost = apiHost}

fun setCdnHost(cdnHost: String) = apply { configuration.cdnHost = cdnHost}

fun build() = configuration
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
package com.segment.analytics.kotlin.core

package com.segment.analytics.kotlin.core.platform.plugins

import com.segment.analytics.kotlin.core.AliasEvent
import com.segment.analytics.kotlin.core.Analytics
import com.segment.analytics.kotlin.core.BaseEvent
import com.segment.analytics.kotlin.core.Constants.DEFAULT_API_HOST
import com.segment.analytics.kotlin.core.GroupEvent
import com.segment.analytics.kotlin.core.HTTPClient
import com.segment.analytics.kotlin.core.HTTPException
import com.segment.analytics.kotlin.core.IdentifyEvent
import com.segment.analytics.kotlin.core.ScreenEvent
import com.segment.analytics.kotlin.core.Settings
import com.segment.analytics.kotlin.core.Storage
import com.segment.analytics.kotlin.core.TrackEvent
import com.segment.analytics.kotlin.core.emptyJsonObject
import com.segment.analytics.kotlin.core.parseFilePaths
import com.segment.analytics.kotlin.core.platform.DestinationPlugin
import com.segment.analytics.kotlin.core.platform.Plugin
import com.segment.analytics.kotlin.core.platform.plugins.LogType
import com.segment.analytics.kotlin.core.platform.plugins.log
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToJsonElement
Expand All @@ -19,6 +32,12 @@ import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger

@Serializable
data class SegmentSettings(
var apiKey: String,
var apiHost: String = DEFAULT_API_HOST,
)

/**
* Segment Analytics plugin that is used to send events to Segment's tracking api, in the choice of region.
* How it works
Expand All @@ -30,7 +49,7 @@ class SegmentDestination(
private var apiKey: String,
private val flushCount: Int = 20,
private val flushIntervalInMillis: Long = 30 * 1000, // 30s
private var apiHost: String = "api.segment.io/v1"
private var apiHost: String = DEFAULT_API_HOST
) : DestinationPlugin() {

override val key: String = "Segment.io"
Expand Down Expand Up @@ -66,10 +85,11 @@ class SegmentDestination(

private inline fun <reified T : BaseEvent> enqueue(payload: T) {
// needs to be inline reified for encoding using Json
val jsonVal = EncodeDefaultsJson.encodeToJsonElement(payload).jsonObject.filterNot { (k, v) ->
// filter out empty userId and traits values
(k == "userId" && v.jsonPrimitive.content.isBlank()) || (k == "traits" && v == emptyJsonObject)
}
val jsonVal = EncodeDefaultsJson.encodeToJsonElement(payload)
.jsonObject.filterNot { (k, v) ->
// filter out empty userId and traits values
(k == "userId" && v.jsonPrimitive.content.isBlank()) || (k == "traits" && v == emptyJsonObject)
}

val stringVal = Json.encodeToString(jsonVal)
analytics.log("$key running $stringVal")
Expand Down Expand Up @@ -109,9 +129,11 @@ class SegmentDestination(
}

override fun update(settings: Settings, type: Plugin.UpdateType) {
settings.integrations[key]?.jsonObject?.let {
apiKey = it["apiKey"]?.jsonPrimitive?.content ?: apiKey
apiHost = it["apiHost"]?.jsonPrimitive?.content ?: apiHost
if (settings.isDestinationEnabled(key)) {
settings.destinationSettings<SegmentSettings>(key)?.let {
apiKey = it.apiKey
apiHost = it.apiHost
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class HTTPClientTests {

@Test
fun `upload connection has correct configuration`() {
httpClient.settings().connection.let {
httpClient.settings("cdn-settings.segment.com/v1").connection.let {
assertEquals(
"https://cdn-settings.segment.com/v1/projects/1vNgUqwJeCHmqgI9S1sOm9UHCyfYqbaQ/settings",
it.url.toString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.segment.analytics.kotlin.core

import com.segment.analytics.kotlin.core.platform.plugins.LogType
import com.segment.analytics.kotlin.core.platform.plugins.Logger
import com.segment.analytics.kotlin.core.platform.plugins.SegmentDestination
import com.segment.analytics.kotlin.core.utilities.ConcreteStorageProvider
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
import com.segment.analytics.kotlin.core.utilities.StorageImpl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SettingsTests {
)
val httpConnection: HttpURLConnection = mockk()
val connection = object : Connection(httpConnection, settingsStream, null) {}
every { anyConstructed<HTTPClient>().settings() } returns connection
every { anyConstructed<HTTPClient>().settings("cdn-settings.segment.com/v1") } returns connection
}

@BeforeEach
Expand All @@ -55,7 +55,7 @@ class SettingsTests {
fun `checkSettings updates settings`() = runBlocking {
val system = analytics.store.currentState(System::class)
val curSettings = system?.settings
Assertions.assertEquals(
assertEquals(
Settings(
integrations = buildJsonObject {
put(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ internal class ConfigurationBuilderTest {
assertEquals(expected, config.apiHost)
}

@Test
fun setCdnHost() {
val expected = "test"
val config = builder.setCdnHost(expected).build()

assertEquals(expected, config.cdnHost)
}

@Test
fun build() {
val expected = Configuration(
Expand All @@ -130,7 +138,8 @@ internal class ConfigurationBuilderTest {
flushAt = 100,
flushInterval = 200,
autoAddSegmentDestination = false,
apiHost = "test"
apiHost = "test",
cdnHost = "testCdn"
)

val config = builder.setApplication(expected.application)
Expand All @@ -145,6 +154,7 @@ internal class ConfigurationBuilderTest {
.setFlushInterval(expected.flushInterval)
.setAutoAddSegmentDestination(expected.autoAddSegmentDestination)
.setApiHost(expected.apiHost)
.setCdnHost(expected.cdnHost)
.build()

assertEquals(expected, config)
Expand Down
2 changes: 1 addition & 1 deletion samples/kotlin-jvm-app/src/main/kotlin/main.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import com.segment.analytics.kotlin.core.Analytics
import com.segment.analytics.kotlin.core.BaseEvent
import com.segment.analytics.kotlin.core.SegmentDestination
import com.segment.analytics.kotlin.core.platform.plugins.SegmentDestination
import com.segment.analytics.kotlin.core.platform.plugins.LogType
import com.segment.analytics.kotlin.core.platform.plugins.Logger
import kotlinx.coroutines.*
Expand Down