From 9e87fd4ac04ea1d1a00a6efc081beae17d335afd Mon Sep 17 00:00:00 2001
From: Peyman Mohtashami
Date: Thu, 7 Dec 2023 13:09:47 +0100
Subject: [PATCH 01/16] define hrv, br, skin-temp in config
---
.DS_Store | Bin 0 -> 8196 bytes
.../FitbitRestSourceConnectorConfig.java | 33 ++++++++++++++++++
2 files changed, 33 insertions(+)
create mode 100644 .DS_Store
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..1765e0788397301b4252f190d8c349b07f56cc5e
GIT binary patch
literal 8196
zcmeHMyKWOf6g?A6us{hZjgVlGA`nPMq)EL*i)bTRf+9`g2Tp{|THd(dhB^g5Km*kL
z0Yc&vQX=sWC_QH$wr6&;E*u4ra>trEtGRdXoINw1^<4u{JCp7f&;U?p)wpqs%{fKe
zbuE<@*Ao#H$79gnYIV}#sN^XfqJStM3Wx%tfGF_4D8Og7F7=A%zO_m#3Wx$%QUQHF
zM64QPhq*;_bg(fg0I|kyQ+U0hFNl%D*kNvw78YfP675jsQVeB>vp;fvvBTV=9S-G^
z59MZ7E<;gfcE*p4J5+2@T2Vk0C@T=LtA?lO;|Rw={{Ha#E8jLulcYUJ+w7}1c5lD`
z{QAf9(B55WA02w{1|B`*P~4c#i$hG%4ra%LFJ%v(!}i(QltUrTFr720_6qpG@TsFs
z9!D6Uix$S{1dLWszmZYN$LF-UwtI52XLLEoZ_a9wU%>08;k8OWDLQzI9>xJD-1|gM
zf!*h`zPUctsNgf_Qsooyz&@wpJbkKiKsE#PLLR^OigusJ_s1R&FNVKTRXza^d%EAH
z5(ju=+9q{L@s6J!ua41VKX)=$QnyWHv`+L|78tL5{6NM_M)L11OJ?`BbhPE8t_lXPT1~QQ)!_xMnA4==}dh_51(JrXle~0a4%|Dxhjf
zE7>6dms^*p=v+Hu-DlNB`{fqR5H=n{TQJVc)V
LW(}mddJ6mjk?CWq
literal 0
HcmV?d00001
diff --git a/kafka-connect-fitbit-source/src/main/java/org/radarbase/connect/rest/fitbit/FitbitRestSourceConnectorConfig.java b/kafka-connect-fitbit-source/src/main/java/org/radarbase/connect/rest/fitbit/FitbitRestSourceConnectorConfig.java
index 36017b23..ee978b10 100644
--- a/kafka-connect-fitbit-source/src/main/java/org/radarbase/connect/rest/fitbit/FitbitRestSourceConnectorConfig.java
+++ b/kafka-connect-fitbit-source/src/main/java/org/radarbase/connect/rest/fitbit/FitbitRestSourceConnectorConfig.java
@@ -331,6 +331,39 @@ public String toString() {
Width.SHORT,
FITBIT_INTRADAY_HEART_RATE_TOPIC_DISPLAY)
+ .define(FITBIT_INTRADAY_HEART_RATE_VARIABILITY_TOPIC_CONFIG,
+ Type.STRING,
+ FITBIT_INTRADAY_HEART_RATE_VARIABILITY_TOPIC_DEFAULT,
+ nonControlChar,
+ Importance.LOW,
+ FITBIT_INTRADAY_HEART_RATE_VARIABILITY_TOPIC_DOC,
+ group,
+ ++orderInGroup,
+ Width.SHORT,
+ FITBIT_INTRADAY_HEART_RATE_VARIABILITY_TOPIC_DISPLAY)
+
+ .define(FITBIT_BREATHING_RATE_TOPIC_CONFIG,
+ Type.STRING,
+ FITBIT_BREATHING_RATE_TOPIC_DEFAULT,
+ nonControlChar,
+ Importance.LOW,
+ FITBIT_BREATHING_RATE_TOPIC_DOC,
+ group,
+ ++orderInGroup,
+ Width.SHORT,
+ FITBIT_BREATHING_RATE_TOPIC_DISPLAY)
+
+ .define(FITBIT_SKIN_TEMPERATURE_TOPIC_CONFIG,
+ Type.STRING,
+ FITBIT_SKIN_TEMPERATURE_TOPIC_DEFAULT,
+ nonControlChar,
+ Importance.LOW,
+ FITBIT_SKIN_TEMPERATURE_TOPIC_DOC,
+ group,
+ ++orderInGroup,
+ Width.SHORT,
+ FITBIT_SKIN_TEMPERATURE_TOPIC_DISPLAY)
+
.define(FITBIT_RESTING_HEART_RATE_TOPIC_CONFIG,
Type.STRING,
FITBIT_RESTING_HEART_RATE_TOPIC_DEFAULT,
From fc3b97952e77905fdf0ed5bf27ef9e0d83cfd501 Mon Sep 17 00:00:00 2001
From: Pauline
Date: Wed, 13 Dec 2023 04:09:09 +0800
Subject: [PATCH 02/16] Add backoff time when request successful to space out
requests
---
.../kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/oura-library/src/main/kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt b/oura-library/src/main/kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt
index 9a74ef4e..84bceba9 100644
--- a/oura-library/src/main/kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt
+++ b/oura-library/src/main/kotlin/org/radarbase/oura/request/OuraRequestGenerator.kt
@@ -111,6 +111,7 @@ constructor(
request.user,
Instant.ofEpochSecond(offset).plus(Duration.ofMillis(500)),
)
+ userNextRequest[request.user.versionedId] = Instant.now().plus(SUCCESS_BACK_OFF_TIME)
} else {
if (request.startDate.plus(TIME_AFTER_REQUEST).isBefore(Instant.now())) {
ouraOffsetManager.updateOffsets(
@@ -196,6 +197,7 @@ constructor(
private val ONE_DAY = 1L
private val TIME_AFTER_REQUEST = Duration.ofDays(30)
private val USER_BACK_OFF_TIME = Duration.ofMinutes(2L)
+ private val SUCCESS_BACK_OFF_TIME = Duration.ofSeconds(3L)
private val USER_MAX_REQUESTS = 20
val JSON_FACTORY = JsonFactory()
val JSON_READER = ObjectMapper(JSON_FACTORY).registerModule(JavaTimeModule()).reader()
From 5750bc05a1b8b965b212963a10f905ad53285168 Mon Sep 17 00:00:00 2001
From: Pauline
Date: Wed, 13 Dec 2023 04:11:13 +0800
Subject: [PATCH 03/16] Fix null handling in OuraRingConfigurationConverter
---
.../OuraRingConfigurationConverter.kt | 21 ++++++++++++-------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/oura-library/src/main/kotlin/org/radarbase/oura/converter/OuraRingConfigurationConverter.kt b/oura-library/src/main/kotlin/org/radarbase/oura/converter/OuraRingConfigurationConverter.kt
index 53d321fc..242bd60e 100644
--- a/oura-library/src/main/kotlin/org/radarbase/oura/converter/OuraRingConfigurationConverter.kt
+++ b/oura-library/src/main/kotlin/org/radarbase/oura/converter/OuraRingConfigurationConverter.kt
@@ -17,12 +17,18 @@ class OuraRingConfigurationConverter(
root: JsonNode,
user: User,
): Sequence> {
- val array = root.get("data")
- ?: return emptySequence()
+ val array =
+ root.get("data")
+ ?: return emptySequence()
return array.asSequence()
.mapCatching {
- val setupTime = OffsetDateTime.parse(it["set_up_at"].textValue())
- val setupTimeInstant = setupTime.toInstant()
+ val setUpAt = it["set_up_at"]
+ val setupTimeInstant =
+ setUpAt?.textValue()?.let {
+ OffsetDateTime.parse(
+ it,
+ )
+ }?.toInstant()
TopicData(
key = user.observationKey,
topic = topic,
@@ -32,9 +38,7 @@ class OuraRingConfigurationConverter(
}
}
- private fun JsonNode.toRingConfiguration(
- setupTime: Instant,
- ): OuraRingConfiguration {
+ private fun JsonNode.toRingConfiguration(setupTime: Instant?): OuraRingConfiguration {
val data = this
return OuraRingConfiguration.newBuilder().apply {
time = System.currentTimeMillis() / 1000.0
@@ -44,7 +48,7 @@ class OuraRingConfigurationConverter(
design = data.get("design").textValue()?.classifyDesign()
firmwareVersion = data.get("firmware_version").textValue()
hardwareType = data.get("hardware_type").textValue()?.classifyHardware()
- setUpAt = setupTime.toEpochMilli() / 1000.0
+ setUpAt = if (setupTime == null) null else setupTime.toEpochMilli() / 1000.0
size = data.get("size").intValue()
}.build()
}
@@ -77,6 +81,7 @@ class OuraRingConfigurationConverter(
else -> OuraRingHardwareType.UNKNOWN
}
}
+
companion object {
val logger = LoggerFactory.getLogger(OuraRingConfigurationConverter::class.java)
}
From 57e02978e0180b1593a98f84f4e51bd15c804322 Mon Sep 17 00:00:00 2001
From: Pauline
Date: Thu, 18 Jan 2024 11:31:41 +0000
Subject: [PATCH 04/16] Add back previous version of OuraServiceRepository
---
buildSrc/src/main/kotlin/Versions.kt | 12 +
kafka-connect-oura-source/build.gradle.kts | 3 +-
.../oura/OuraRestSourceConnectorConfig.java | 25 +-
.../rest/oura/offset/KafkaOffsetManager.java | 6 +-
.../oura/user/OuraServiceUserRepository.java | 257 ++++++++++++++++++
...ry.kt => OuraServiceUserRepositoryKtor.kt} | 209 +++++++-------
.../oura/request/OuraRequestGenerator.kt | 5 +-
7 files changed, 398 insertions(+), 119 deletions(-)
create mode 100644 kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/user/OuraServiceUserRepository.java
rename kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/user/{OuraServiceUserRepository.kt => OuraServiceUserRepositoryKtor.kt} (57%)
diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index ed0e7679..1cd990fa 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -1,5 +1,15 @@
@Suppress("ConstPropertyName", "MemberVisibilityCanBePrivate")
object Versions {
+
+ object Plugins {
+ const val kotlin = "1.9.10"
+ const val kotlinSerialization = kotlin
+ const val kotlinAllOpen = kotlin
+ const val avro = "1.8.0"
+ const val gradle = "8.3"
+ }
+
+
const val project = "0.4.2-SNAPSHOT"
const val java = 11
@@ -11,6 +21,8 @@ object Versions {
const val kafka = "$confluent-ce"
const val avro = "1.11.0"
+ const val managementPortal = "2.0.0"
+
// From image
const val jackson = "2.14.2"
diff --git a/kafka-connect-oura-source/build.gradle.kts b/kafka-connect-oura-source/build.gradle.kts
index b80d4801..e0acc8d7 100644
--- a/kafka-connect-oura-source/build.gradle.kts
+++ b/kafka-connect-oura-source/build.gradle.kts
@@ -4,7 +4,8 @@ dependencies {
api(project(":oura-library"))
api("io.confluent:kafka-connect-avro-converter:${Versions.confluent}")
api("org.radarbase:radar-schemas-commons:${Versions.radarSchemas}")
- implementation("org.radarbase:radar-commons-kotlin:${Versions.radarCommons}")
+ implementation("org.radarbase:radar-commons-kotlin:1.1.1")
+ implementation("org.radarbase:oauth-client-util:${Versions.managementPortal}")
api("com.squareup.okhttp3:okhttp:${Versions.okhttp}")
implementation(platform("com.fasterxml.jackson:jackson-bom:${Versions.jackson}"))
diff --git a/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/OuraRestSourceConnectorConfig.java b/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/OuraRestSourceConnectorConfig.java
index 41ae3f0e..0acf9e89 100644
--- a/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/OuraRestSourceConnectorConfig.java
+++ b/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/OuraRestSourceConnectorConfig.java
@@ -19,7 +19,6 @@
import static org.apache.kafka.common.config.ConfigDef.NO_DEFAULT_VALUE;
-import static io.ktor.http.URLUtilsKt.URLBuilder;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
@@ -45,8 +44,6 @@
import org.apache.kafka.common.config.ConfigException;
import org.apache.kafka.connect.errors.ConnectException;
import org.radarbase.connect.rest.oura.user.OuraServiceUserRepository;
-import io.ktor.http.URLParserException;
-import io.ktor.http.Url;
public class OuraRestSourceConnectorConfig extends AbstractConfig {
public static final Pattern COLON_PATTERN = Pattern.compile(":");
@@ -283,18 +280,18 @@ public OuraServiceUserRepository createUserRepository() {
}
}
- public Url getOuraUserRepositoryUrl() {
+ public HttpUrl getOuraUserRepositoryUrl() {
String urlString = getString(OURA_USER_REPOSITORY_URL_CONFIG).trim();
if (urlString.charAt(urlString.length() - 1) != '/') {
urlString += '/';
}
- try {
- return URLBuilder(urlString).build();
- } catch (URLParserException ex) {
+ HttpUrl url = HttpUrl.parse(urlString);
+ if (url == null) {
throw new ConfigException(OURA_USER_REPOSITORY_URL_CONFIG,
getString(OURA_USER_REPOSITORY_URL_CONFIG),
- "User repository URL " + urlString + " cannot be parsed as URL: " + ex);
+ "User repository URL " + urlString + " cannot be parsed as URL.");
}
+ return url;
}
public Headers getClientCredentials() {
@@ -317,18 +314,16 @@ public String getOuraUserRepositoryClientSecret() {
return getPassword(OURA_USER_REPOSITORY_CLIENT_SECRET_CONFIG).value();
}
- public Url getOuraUserRepositoryTokenUrl() {
+ public URL getOuraUserRepositoryTokenUrl() {
String value = getString(OURA_USER_REPOSITORY_TOKEN_URL_CONFIG);
if (value == null || value.isEmpty()) {
return null;
} else {
try {
- return URLBuilder(value).build();
- } catch (URLParserException ex) {
- throw new ConfigException(OURA_USER_REPOSITORY_TOKEN_URL_CONFIG,
- getString(OURA_USER_REPOSITORY_TOKEN_URL_CONFIG),
- "Oura user repository token URL " + value + " cannot be parsed as URL: " + ex);
+ return new URL(getString(OURA_USER_REPOSITORY_TOKEN_URL_CONFIG));
+ } catch (MalformedURLException e) {
+ throw new ConfigException("Oura user repository token URL is invalid.");
}
}
}
-}
+}
\ No newline at end of file
diff --git a/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/offset/KafkaOffsetManager.java b/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/offset/KafkaOffsetManager.java
index 360d5f82..fbb4329b 100644
--- a/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/offset/KafkaOffsetManager.java
+++ b/kafka-connect-oura-source/src/main/java/org/radarbase/connect/rest/oura/offset/KafkaOffsetManager.java
@@ -31,11 +31,15 @@ public KafkaOffsetManager(
}
public void initialize(List