react-native-mytatva-rn-sdk 1.2.93 → 1.2.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +20 -7
- package/android/src/main/java/com/mytatvarnsdk/CgmTrackyLibModule.kt +594 -232
- package/android/src/main/java/com/mytatvarnsdk/activity/PermissionActivity.kt +276 -87
- package/android/src/main/res/layout/activity_permission.xml +0 -1
- package/android/src/main/res/layout/layout_green_solid_button.xml +43 -0
- package/android/src/main/res/layout/permission_disclosure_bottomsheet.xml +70 -0
- package/android/src/main/res/values/strings.xml +12 -0
- package/ios/Support/Converter/DataConverter.swift +62 -29
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
package com.mytatvarnsdk
|
|
1
|
+
package com.mytatvarnsdk
|
|
2
2
|
|
|
3
3
|
import android.app.Application
|
|
4
4
|
import android.bluetooth.BluetoothAdapter
|
|
@@ -12,6 +12,9 @@ import androidx.lifecycle.Observer
|
|
|
12
12
|
import androidx.lifecycle.ViewModelProvider
|
|
13
13
|
import androidx.lifecycle.ViewModelStore
|
|
14
14
|
import cgmblelib.Enum.enumError
|
|
15
|
+
import cgmblelib.Enum.enumGlucoseStatus
|
|
16
|
+
import cgmblelib.Enum.enumSound
|
|
17
|
+
import cgmblelib.Enum.enumTrend
|
|
15
18
|
import cgmblelib.base.BApplication
|
|
16
19
|
import cgmblelib.database.entity.PocDevice
|
|
17
20
|
import cgmblelib.database.entity.PocGlucose
|
|
@@ -33,19 +36,23 @@ import com.mytatvarnsdk.activity.HelpActivity
|
|
|
33
36
|
import com.mytatvarnsdk.activity.StartCGMActivity
|
|
34
37
|
import com.mytatvarnsdk.model.AllCGMLogRequest
|
|
35
38
|
import com.mytatvarnsdk.model.CgmLog
|
|
39
|
+
import com.mytatvarnsdk.model.ErrorObject
|
|
40
|
+
import com.mytatvarnsdk.model.GlucoseStatusObject
|
|
41
|
+
import com.mytatvarnsdk.model.TrendObject
|
|
36
42
|
import com.mytatvarnsdk.model.CgmSensorResponse
|
|
37
43
|
import com.mytatvarnsdk.model.GlucoseLog
|
|
38
|
-
import com.mytatvarnsdk.model.GlucoseLog.ErrorObject
|
|
39
|
-
import com.mytatvarnsdk.model.GlucoseLog.GlucoseStatusObject
|
|
40
|
-
import com.mytatvarnsdk.model.GlucoseLog.TrendObject
|
|
41
44
|
import com.mytatvarnsdk.model.GlucoseLogRequest
|
|
42
45
|
import com.mytatvarnsdk.model.MainActivityModel
|
|
43
46
|
import com.mytatvarnsdk.network.AuthenticateSDKService
|
|
44
47
|
import com.mytatvarnsdk.network.AuthenticateSDKService.LoaderListener
|
|
45
48
|
import com.mytatvarnsdk.utils.DeviceStatus
|
|
46
49
|
import com.mytatvarnsdk.utils.TATVA_ENVIRONMENT
|
|
50
|
+
import io.sentry.ScopeCallback
|
|
47
51
|
import io.sentry.Sentry
|
|
52
|
+
import io.sentry.SentryAttributes
|
|
48
53
|
import io.sentry.SentryLevel
|
|
54
|
+
import io.sentry.SentryLogLevel
|
|
55
|
+
import io.sentry.logger.SentryLogParameters
|
|
49
56
|
import kotlinx.coroutines.CoroutineScope
|
|
50
57
|
import kotlinx.coroutines.Dispatchers
|
|
51
58
|
import kotlinx.coroutines.Job
|
|
@@ -116,79 +123,186 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
116
123
|
return "CgmTrackyLib"
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
private fun clipForSentry(text: String, maxChars: Int = MAX_SENTRY_DATA_EXTRA_CHARS): String =
|
|
127
|
+
try {
|
|
128
|
+
if (text.length <= maxChars) text else text.take(maxChars) + "…"
|
|
129
|
+
} catch (_: Throwable) {
|
|
130
|
+
""
|
|
131
|
+
}
|
|
132
|
+
|
|
119
133
|
/**
|
|
134
|
+
* Structured Sentry log (like RN `Sentry.logger.info/warn/error`).
|
|
120
135
|
* Uses the host app's Sentry client (never call Sentry.init here).
|
|
121
|
-
*
|
|
122
|
-
*
|
|
136
|
+
*
|
|
137
|
+
* Sentry 8.x: `Sentry.logger()` sends to **Explore → Logs** and requires native
|
|
138
|
+
* `enableLogs: true` (mapped from parent `@sentry/react-native` init). It is NOT a
|
|
139
|
+
* drop-in replacement for `captureException` / `captureMessage` (Issues tab).
|
|
140
|
+
*
|
|
141
|
+
* When logs are disabled or unavailable, falls back to captureMessage/captureException
|
|
142
|
+
* so operational telemetry still reaches Sentry Issues (same as Sentry 6.x behaviour).
|
|
123
143
|
*/
|
|
124
|
-
private fun
|
|
144
|
+
private fun logModuleEvent(
|
|
125
145
|
where: String,
|
|
126
|
-
|
|
127
|
-
level:
|
|
146
|
+
message: String = "",
|
|
147
|
+
level: SentryLogLevel = SentryLogLevel.INFO,
|
|
148
|
+
jsonPayload: String? = null,
|
|
149
|
+
throwable: Throwable? = null,
|
|
150
|
+
attributes: Map<String, String> = emptyMap()
|
|
128
151
|
) {
|
|
129
152
|
try {
|
|
130
|
-
Sentry.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
153
|
+
if (!Sentry.isEnabled()) {
|
|
154
|
+
Log.w("logModuleEvent", "Sentry not initialized — skipping [$where]")
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
val resolvedMessage = when {
|
|
159
|
+
message.isNotEmpty() -> message
|
|
160
|
+
throwable != null -> {
|
|
161
|
+
val typeName = throwable.javaClass.simpleName ?: "Throwable"
|
|
162
|
+
"$typeName: ${throwable.message ?: ""}"
|
|
135
163
|
}
|
|
164
|
+
else -> where
|
|
165
|
+
}
|
|
166
|
+
val mergedAttributes = try {
|
|
167
|
+
attributes.toMutableMap()
|
|
168
|
+
} catch (_: Throwable) {
|
|
169
|
+
mutableMapOf()
|
|
170
|
+
}
|
|
171
|
+
throwable?.let {
|
|
172
|
+
mergedAttributes["exception"] = it.javaClass.simpleName ?: "Throwable"
|
|
173
|
+
mergedAttributes["exception_message"] = it.message ?: ""
|
|
174
|
+
}
|
|
136
175
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
176
|
+
val clippedJson = jsonPayload?.let { clipForSentry(it) }
|
|
177
|
+
val logMessage = clipForSentry(
|
|
178
|
+
"CgmTrackyLib: $where | $resolvedMessage",
|
|
179
|
+
MAX_SENTRY_MESSAGE_DATA_CHARS
|
|
180
|
+
)
|
|
142
181
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
scope.setExtra("data", clipped)
|
|
155
|
-
Sentry.captureException(data)
|
|
156
|
-
}
|
|
182
|
+
val sentryAttributes = mutableMapOf<String, Any>(
|
|
183
|
+
"cgm_tracky_lib" to "true",
|
|
184
|
+
"location" to where,
|
|
185
|
+
)
|
|
186
|
+
if (env.isNotEmpty()) {
|
|
187
|
+
sentryAttributes["tatva_env"] = env
|
|
188
|
+
}
|
|
189
|
+
clippedJson?.let { sentryAttributes["json"] = it }
|
|
190
|
+
mergedAttributes.forEach { (key, value) ->
|
|
191
|
+
sentryAttributes[key] = clipForSentry(value, 500)
|
|
192
|
+
}
|
|
157
193
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
val clipped =
|
|
164
|
-
if (text.length > MAX_SENTRY_DATA_EXTRA_CHARS) {
|
|
165
|
-
text.take(MAX_SENTRY_DATA_EXTRA_CHARS) + "…"
|
|
166
|
-
} else {
|
|
167
|
-
text
|
|
168
|
-
}
|
|
169
|
-
scope.setExtra("data", clipped)
|
|
170
|
-
// Duplicate under a more explicit key so it is easy to find in Sentry UI.
|
|
171
|
-
scope.setExtra("json", clipped)
|
|
172
|
-
|
|
173
|
-
// Also include a prefix in the message itself so it appears in the main event row.
|
|
174
|
-
// (In some Sentry views, extra fields are not shown by default.)
|
|
175
|
-
val messageData =
|
|
176
|
-
if (clipped.length > MAX_SENTRY_MESSAGE_DATA_CHARS) {
|
|
177
|
-
clipped.take(MAX_SENTRY_MESSAGE_DATA_CHARS) + "…"
|
|
178
|
-
} else {
|
|
179
|
-
clipped
|
|
180
|
-
}
|
|
194
|
+
val logsEnabled = try {
|
|
195
|
+
Sentry.getCurrentScopes()?.options?.logs?.isEnabled == true
|
|
196
|
+
} catch (_: Throwable) {
|
|
197
|
+
false
|
|
198
|
+
}
|
|
181
199
|
|
|
182
|
-
|
|
183
|
-
|
|
200
|
+
if (logsEnabled) {
|
|
201
|
+
val logParams = SentryLogParameters.create(
|
|
202
|
+
SentryAttributes.fromMap(sentryAttributes)
|
|
203
|
+
)
|
|
204
|
+
logParams.origin = "cgm-tracky-lib"
|
|
205
|
+
Sentry.logger().log(level, logParams, logMessage)
|
|
206
|
+
// Exceptions logged via logger should also appear under Issues (pre-8.x behaviour).
|
|
207
|
+
if (throwable != null && level >= SentryLogLevel.ERROR) {
|
|
208
|
+
captureModuleException(where, throwable, sentryAttributes)
|
|
184
209
|
}
|
|
210
|
+
} else {
|
|
211
|
+
captureModuleEventFallback(where, logMessage, level, throwable, sentryAttributes)
|
|
212
|
+
}
|
|
213
|
+
} catch (sentryEx: Throwable) {
|
|
214
|
+
try {
|
|
215
|
+
Log.w(
|
|
216
|
+
"logModuleEvent",
|
|
217
|
+
"Sentry logger failed for [$where]: ${sentryEx.message}",
|
|
218
|
+
sentryEx
|
|
219
|
+
)
|
|
220
|
+
Log.e("CgmTrackyLib", "[$where]", throwable ?: sentryEx)
|
|
221
|
+
} catch (_: Throwable) {
|
|
222
|
+
// Last resort: never propagate to callers.
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private fun mapLogLevelToEventLevel(level: SentryLogLevel): SentryLevel = when (level) {
|
|
228
|
+
SentryLogLevel.TRACE, SentryLogLevel.DEBUG -> SentryLevel.DEBUG
|
|
229
|
+
SentryLogLevel.INFO -> SentryLevel.INFO
|
|
230
|
+
SentryLogLevel.WARN -> SentryLevel.WARNING
|
|
231
|
+
SentryLogLevel.ERROR -> SentryLevel.ERROR
|
|
232
|
+
SentryLogLevel.FATAL -> SentryLevel.FATAL
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private fun applyModuleScopeExtras(
|
|
236
|
+
where: String,
|
|
237
|
+
attributes: Map<String, Any>
|
|
238
|
+
): ScopeCallback = ScopeCallback { scope ->
|
|
239
|
+
scope.setTag("cgm_tracky_lib", "true")
|
|
240
|
+
scope.setTag("location", where)
|
|
241
|
+
if (env.isNotEmpty()) {
|
|
242
|
+
scope.setTag("tatva_env", env)
|
|
243
|
+
}
|
|
244
|
+
attributes.forEach { (key, value) ->
|
|
245
|
+
scope.setExtra(key, value.toString())
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** Fallback when native logs are disabled — sends to Issues via captureMessage. */
|
|
250
|
+
private fun captureModuleEventFallback(
|
|
251
|
+
where: String,
|
|
252
|
+
message: String,
|
|
253
|
+
level: SentryLogLevel,
|
|
254
|
+
throwable: Throwable?,
|
|
255
|
+
attributes: Map<String, Any>
|
|
256
|
+
) {
|
|
257
|
+
val scopeCallback = applyModuleScopeExtras(where, attributes)
|
|
258
|
+
if (throwable != null) {
|
|
259
|
+
Sentry.captureException(throwable, scopeCallback)
|
|
260
|
+
} else {
|
|
261
|
+
Sentry.captureMessage(message, mapLogLevelToEventLevel(level), scopeCallback)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private fun captureModuleException(
|
|
266
|
+
where: String,
|
|
267
|
+
throwable: Throwable,
|
|
268
|
+
attributes: Map<String, Any>
|
|
269
|
+
) {
|
|
270
|
+
Sentry.captureException(throwable, applyModuleScopeExtras(where, attributes))
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Wraps log preparation + emission so a bad payload/toString() cannot break CGM flows. */
|
|
274
|
+
private inline fun safeLogModuleEvent(block: () -> Unit) {
|
|
275
|
+
try {
|
|
276
|
+
block()
|
|
277
|
+
} catch (t: Throwable) {
|
|
278
|
+
try {
|
|
279
|
+
Log.w("logModuleEvent", "Failed to prepare Sentry log: ${t.message}", t)
|
|
280
|
+
} catch (_: Throwable) {
|
|
281
|
+
// Never propagate to callers.
|
|
185
282
|
}
|
|
186
|
-
} catch (sentryEx: Exception) {
|
|
187
|
-
// If Sentry itself fails, never crash the CGM processing flow.
|
|
188
|
-
Log.e("captureModuleException", "Sentry capture failed: ${sentryEx.message}", sentryEx)
|
|
189
283
|
}
|
|
190
284
|
}
|
|
191
285
|
|
|
286
|
+
private fun cgmStatusDeviceAttributes(
|
|
287
|
+
status: String,
|
|
288
|
+
device: PocDevice?,
|
|
289
|
+
sensorId: String?,
|
|
290
|
+
bleEnabled: Boolean,
|
|
291
|
+
extra: Map<String, String> = emptyMap(),
|
|
292
|
+
): Map<String, String> {
|
|
293
|
+
val attrs = mutableMapOf(
|
|
294
|
+
"cgm_status" to status,
|
|
295
|
+
"sensor_id" to (sensorId ?: ""),
|
|
296
|
+
"ble_enabled" to bleEnabled.toString(),
|
|
297
|
+
"is_bound_and_connect" to (device?.isBoundAndConnect?.toString() ?: "unknown"),
|
|
298
|
+
"is_unbind" to (device?.isUnBind?.toString() ?: "unknown"),
|
|
299
|
+
"is_bound_but_disconnect" to (device?.isBoundButDisConnect?.toString() ?: "unknown"),
|
|
300
|
+
"transmitter_name" to (device?.name.orEmpty()),
|
|
301
|
+
)
|
|
302
|
+
attrs.putAll(extra)
|
|
303
|
+
return attrs
|
|
304
|
+
}
|
|
305
|
+
|
|
192
306
|
private fun updateUserData(data: ReadableMap?) {
|
|
193
307
|
currentUserData = data
|
|
194
308
|
// Always reset so stale values from a previous user don't persist
|
|
@@ -203,7 +317,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
203
317
|
}
|
|
204
318
|
} catch (e: Exception) {
|
|
205
319
|
Log.e("updateUserData", "Error extracting last_connect_cgm: ${e.message}", e)
|
|
206
|
-
|
|
320
|
+
safeLogModuleEvent {
|
|
321
|
+
logModuleEvent("updateUserData", throwable = e, level = SentryLogLevel.ERROR)
|
|
322
|
+
}
|
|
207
323
|
}
|
|
208
324
|
}
|
|
209
325
|
|
|
@@ -237,7 +353,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
237
353
|
}
|
|
238
354
|
} catch (e: Exception) {
|
|
239
355
|
Log.e("observeDeviceStatus", "observeDeviceStatus: ${e.message}", e)
|
|
240
|
-
|
|
356
|
+
safeLogModuleEvent {
|
|
357
|
+
logModuleEvent("observeDeviceStatus", throwable = e, level = SentryLogLevel.ERROR)
|
|
358
|
+
}
|
|
241
359
|
}
|
|
242
360
|
}
|
|
243
361
|
|
|
@@ -365,7 +483,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
365
483
|
}
|
|
366
484
|
} catch (e: Exception) {
|
|
367
485
|
Log.e("observeTransmitterUnbindStatus", "observeTransmitterUnbindStatus: ${e.message}", e)
|
|
368
|
-
|
|
486
|
+
safeLogModuleEvent {
|
|
487
|
+
logModuleEvent("observeTransmitterUnbindStatus", throwable = e, level = SentryLogLevel.ERROR)
|
|
488
|
+
}
|
|
369
489
|
}
|
|
370
490
|
}
|
|
371
491
|
|
|
@@ -396,11 +516,29 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
396
516
|
|
|
397
517
|
Log.d("Device event Status", "Device event Status: $status")
|
|
398
518
|
|
|
519
|
+
safeLogModuleEvent {
|
|
520
|
+
logModuleEvent(
|
|
521
|
+
where = "postEventDataToAPI.cgmStatusResolved",
|
|
522
|
+
message = "CGM status resolved: $status | bleEnabled=$bleStatus",
|
|
523
|
+
level = SentryLogLevel.INFO,
|
|
524
|
+
attributes = cgmStatusDeviceAttributes(status, device, sensorId, bleStatus),
|
|
525
|
+
)
|
|
526
|
+
}
|
|
527
|
+
|
|
399
528
|
if (status == DeviceStatus.DISCONNECTED.id && !isDebounceTimerActive) {
|
|
400
529
|
// Start debounce timer for 1 minutes
|
|
401
530
|
debounceDeviceTimer = Timer()
|
|
402
531
|
isDebounceTimerActive = true
|
|
403
532
|
|
|
533
|
+
safeLogModuleEvent {
|
|
534
|
+
logModuleEvent(
|
|
535
|
+
where = "postEventDataToAPI.cgmStatusDebounceScheduled",
|
|
536
|
+
message = "CGM DISCONNECTED debounce started (1 min) | status=$status",
|
|
537
|
+
level = SentryLogLevel.INFO,
|
|
538
|
+
attributes = cgmStatusDeviceAttributes(status, device, sensorId, bleStatus),
|
|
539
|
+
)
|
|
540
|
+
}
|
|
541
|
+
|
|
404
542
|
debounceDeviceTimer?.schedule(object : TimerTask() {
|
|
405
543
|
override fun run() {
|
|
406
544
|
isDebounceTimerActive = false
|
|
@@ -422,7 +560,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
422
560
|
|
|
423
561
|
} catch (e: Exception) {
|
|
424
562
|
Log.e("postEventDataToAPI", "postEventDataToAPI: ${e.message}", e)
|
|
425
|
-
|
|
563
|
+
safeLogModuleEvent {
|
|
564
|
+
logModuleEvent("postEventDataToAPI", throwable = e, level = SentryLogLevel.ERROR)
|
|
565
|
+
}
|
|
426
566
|
}
|
|
427
567
|
}
|
|
428
568
|
}
|
|
@@ -438,6 +578,7 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
438
578
|
Log.d("Device event Status", "Last Device event lastDeviceStatus API: $lastDeviceStatus")
|
|
439
579
|
|
|
440
580
|
if (status.isNotEmpty() && status != lastDeviceStatus) {
|
|
581
|
+
val previousStatus = lastDeviceStatus
|
|
441
582
|
lastDeviceStatus = status
|
|
442
583
|
|
|
443
584
|
Log.d("Device event Status", "Device event Status API: $status")
|
|
@@ -455,6 +596,25 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
455
596
|
put("rawData", rawData)
|
|
456
597
|
}
|
|
457
598
|
Log.d("commingg", "Yuppp")
|
|
599
|
+
|
|
600
|
+
safeLogModuleEvent {
|
|
601
|
+
logModuleEvent(
|
|
602
|
+
where = "callEventAPI.cgmStatusChanged",
|
|
603
|
+
message = "CGM status changed | previous=${previousStatus ?: "none"} | new=$status",
|
|
604
|
+
level = SentryLogLevel.INFO,
|
|
605
|
+
jsonPayload = obj.toString(),
|
|
606
|
+
attributes = cgmStatusDeviceAttributes(
|
|
607
|
+
status = status,
|
|
608
|
+
device = device,
|
|
609
|
+
sensorId = sensorId,
|
|
610
|
+
bleEnabled = BluetoothAdapter.getDefaultAdapter()?.isEnabled == true,
|
|
611
|
+
extra = mapOf(
|
|
612
|
+
"previous_cgm_status" to (previousStatus ?: ""),
|
|
613
|
+
),
|
|
614
|
+
),
|
|
615
|
+
)
|
|
616
|
+
}
|
|
617
|
+
|
|
458
618
|
authenticateSDKService.postDeviceData(
|
|
459
619
|
environment = if (envType.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
|
|
460
620
|
data = obj.toString(),
|
|
@@ -489,7 +649,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
489
649
|
currentActivity?.startActivity(intent)
|
|
490
650
|
} catch (e: Exception) {
|
|
491
651
|
Log.e("startCgmTracky", "startCgmTracky: ${e.message}", e)
|
|
492
|
-
|
|
652
|
+
safeLogModuleEvent {
|
|
653
|
+
logModuleEvent("startCgmTracky", throwable = e, level = SentryLogLevel.ERROR)
|
|
654
|
+
}
|
|
493
655
|
}
|
|
494
656
|
}
|
|
495
657
|
|
|
@@ -518,7 +680,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
518
680
|
)
|
|
519
681
|
} catch (e: Exception) {
|
|
520
682
|
Log.e("reconnectCgmTracky", "reconnectCgmTracky: ${e.message}", e)
|
|
521
|
-
|
|
683
|
+
safeLogModuleEvent {
|
|
684
|
+
logModuleEvent("reconnectCgmTracky", throwable = e, level = SentryLogLevel.ERROR)
|
|
685
|
+
}
|
|
522
686
|
}
|
|
523
687
|
}
|
|
524
688
|
|
|
@@ -529,7 +693,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
529
693
|
currentActivity?.startActivity(intent)
|
|
530
694
|
} catch (e: Exception) {
|
|
531
695
|
Log.e("openHelpSupport", "openHelpSupport: ${e.message}", e)
|
|
532
|
-
|
|
696
|
+
safeLogModuleEvent {
|
|
697
|
+
logModuleEvent("openHelpSupport", throwable = e, level = SentryLogLevel.ERROR)
|
|
698
|
+
}
|
|
533
699
|
}
|
|
534
700
|
}
|
|
535
701
|
|
|
@@ -601,7 +767,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
601
767
|
Log.d("observeGlucoseData", "Live glucose observer started successfully")
|
|
602
768
|
} catch (e: Exception) {
|
|
603
769
|
Log.e("observeGlucoseData", "Error adding observer: ${e.message}", e)
|
|
604
|
-
|
|
770
|
+
safeLogModuleEvent {
|
|
771
|
+
logModuleEvent(
|
|
772
|
+
"observeGlucoseData.observeForever",
|
|
773
|
+
throwable = e,
|
|
774
|
+
level = SentryLogLevel.ERROR
|
|
775
|
+
)
|
|
776
|
+
}
|
|
605
777
|
glucoseObserver = null
|
|
606
778
|
isObserving = false
|
|
607
779
|
}
|
|
@@ -610,7 +782,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
610
782
|
|
|
611
783
|
} catch (e: Exception) {
|
|
612
784
|
Log.e("observeGlucoseData", "observeGlucoseData: ${e.message}", e)
|
|
613
|
-
|
|
785
|
+
safeLogModuleEvent {
|
|
786
|
+
logModuleEvent("observeGlucoseData", throwable = e, level = SentryLogLevel.ERROR)
|
|
787
|
+
}
|
|
614
788
|
isObserving = false
|
|
615
789
|
glucoseObserver = null
|
|
616
790
|
}
|
|
@@ -694,8 +868,18 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
694
868
|
val json = singlePayloadJsonObject.toString()
|
|
695
869
|
|
|
696
870
|
Log.d("Glucose data 3 min==> ", "Glucose data 3 min==> final Json: $json")
|
|
697
|
-
|
|
698
|
-
|
|
871
|
+
safeLogModuleEvent {
|
|
872
|
+
logModuleEvent(
|
|
873
|
+
where = "handleGlucoseData.postCGMData",
|
|
874
|
+
message = "Posting single glucose data | glucoseId=${pocGlucose.glucoseId ?: ""}",
|
|
875
|
+
level = SentryLogLevel.INFO,
|
|
876
|
+
jsonPayload = json,
|
|
877
|
+
attributes = mapOf(
|
|
878
|
+
"glucoseId" to (pocGlucose.glucoseId?.toString() ?: "")
|
|
879
|
+
)
|
|
880
|
+
)
|
|
881
|
+
}
|
|
882
|
+
|
|
699
883
|
authenticateSDKService.postCGMData(
|
|
700
884
|
environment = if (envType.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
|
|
701
885
|
data = json,
|
|
@@ -703,31 +887,36 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
703
887
|
responseListener = object : AuthenticateSDKService.ResponseListener {
|
|
704
888
|
override fun onResponseSuccess(response: String) {
|
|
705
889
|
updateSyncMetadata(pocGlucose)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
890
|
+
safeLogModuleEvent {
|
|
891
|
+
logModuleEvent(
|
|
892
|
+
where = "handleGlucoseData.postCGMData.success",
|
|
893
|
+
message = "Single glucose data uploaded successfully | glucoseId=${pocGlucose.glucoseId ?: ""}",
|
|
894
|
+
level = SentryLogLevel.INFO,
|
|
895
|
+
jsonPayload = json,
|
|
896
|
+
attributes = mapOf(
|
|
897
|
+
"glucoseId" to (pocGlucose.glucoseId?.toString() ?: ""),
|
|
898
|
+
"sdk_response" to response
|
|
899
|
+
)
|
|
900
|
+
)
|
|
901
|
+
}
|
|
716
902
|
Log.d("CGM Data", "Single glucose data uploaded successfully")
|
|
717
903
|
}
|
|
718
904
|
|
|
719
905
|
override fun onResponseFail() {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
906
|
+
safeLogModuleEvent {
|
|
907
|
+
val lastSync = prefsHelper?.lastSyncData
|
|
908
|
+
val contextData =
|
|
909
|
+
"failure_reason=Failed to upload single glucose data;" +
|
|
910
|
+
"pocGlucose=${pocGlucose};" +
|
|
911
|
+
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
912
|
+
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
913
|
+
logModuleEvent(
|
|
914
|
+
where = "handleGlucoseData.postCGMData.fail",
|
|
915
|
+
message = contextData,
|
|
916
|
+
level = SentryLogLevel.WARN,
|
|
917
|
+
jsonPayload = json
|
|
918
|
+
)
|
|
919
|
+
}
|
|
731
920
|
Log.e("CGM Data", "Failed to upload single glucose data")
|
|
732
921
|
}
|
|
733
922
|
}
|
|
@@ -741,31 +930,37 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
741
930
|
} */
|
|
742
931
|
} else {
|
|
743
932
|
Log.d("handleGlucoseData", "Glucose data has error: ${pocGlucose.errorCode}")
|
|
933
|
+
safeLogModuleEvent {
|
|
934
|
+
val lastSync = prefsHelper?.lastSyncData
|
|
935
|
+
val contextData =
|
|
936
|
+
"failure_reason=Glucose data has error: ${pocGlucose.errorCode};" +
|
|
937
|
+
"pocGlucose=${pocGlucose};" +
|
|
938
|
+
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
939
|
+
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
940
|
+
logModuleEvent(
|
|
941
|
+
where = "handleGlucoseData==>postCGMData",
|
|
942
|
+
message = "Glucose data has error: ${pocGlucose.errorCode} | $contextData",
|
|
943
|
+
level = SentryLogLevel.INFO
|
|
944
|
+
)
|
|
945
|
+
}
|
|
946
|
+
handleGlucoseError(pocGlucose, envType)
|
|
947
|
+
}
|
|
948
|
+
} catch (e: Exception) {
|
|
949
|
+
Log.e("handleGlucoseData", "Error handling glucose data: ${e.message}", e)
|
|
950
|
+
safeLogModuleEvent {
|
|
744
951
|
val lastSync = prefsHelper?.lastSyncData
|
|
745
952
|
val contextData =
|
|
746
|
-
"failure_reason=
|
|
953
|
+
"failure_reason=Exception in handleGlucoseData;" +
|
|
747
954
|
"pocGlucose=${pocGlucose};" +
|
|
748
955
|
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
749
956
|
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
750
|
-
|
|
751
|
-
"handleGlucoseData
|
|
752
|
-
|
|
753
|
-
|
|
957
|
+
logModuleEvent(
|
|
958
|
+
where = "handleGlucoseData",
|
|
959
|
+
message = "handleGlucoseData failed | $contextData",
|
|
960
|
+
throwable = e,
|
|
961
|
+
level = SentryLogLevel.ERROR
|
|
754
962
|
)
|
|
755
|
-
handleGlucoseError(pocGlucose, envType)
|
|
756
963
|
}
|
|
757
|
-
} catch (e: Exception) {
|
|
758
|
-
Log.e("handleGlucoseData", "Error handling glucose data: ${e.message}", e)
|
|
759
|
-
val lastSync = prefsHelper?.lastSyncData
|
|
760
|
-
val contextData =
|
|
761
|
-
"failure_reason=Exception in handleGlucoseData;" +
|
|
762
|
-
"pocGlucose=${pocGlucose};" +
|
|
763
|
-
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
764
|
-
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
765
|
-
captureModuleException(
|
|
766
|
-
"handleGlucoseData",
|
|
767
|
-
RuntimeException("handleGlucoseData failed | $contextData", e)
|
|
768
|
-
)
|
|
769
964
|
}
|
|
770
965
|
}
|
|
771
966
|
|
|
@@ -811,7 +1006,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
811
1006
|
}
|
|
812
1007
|
} catch (e: Exception) {
|
|
813
1008
|
Log.e("handleGlucoseError", "Error handling glucose error: ${e.message}", e)
|
|
814
|
-
|
|
1009
|
+
safeLogModuleEvent {
|
|
1010
|
+
logModuleEvent("handleGlucoseError", throwable = e, level = SentryLogLevel.ERROR)
|
|
1011
|
+
}
|
|
815
1012
|
}
|
|
816
1013
|
}
|
|
817
1014
|
|
|
@@ -924,7 +1121,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
924
1121
|
}
|
|
925
1122
|
} catch (e: Exception) {
|
|
926
1123
|
Log.e("observeAllGlucoseData", "Error in batch processing: ${e.message}", e)
|
|
927
|
-
|
|
1124
|
+
safeLogModuleEvent {
|
|
1125
|
+
logModuleEvent("observeAllGlucoseData", throwable = e, level = SentryLogLevel.ERROR)
|
|
1126
|
+
}
|
|
928
1127
|
} finally {
|
|
929
1128
|
// Always reset the flag
|
|
930
1129
|
isBatchProcessing.set(false)
|
|
@@ -973,7 +1172,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
973
1172
|
|
|
974
1173
|
} catch (e: Exception) {
|
|
975
1174
|
Log.e("processBatchDataAndStartObserver", "Error in batch processing: ${e.message}", e)
|
|
976
|
-
|
|
1175
|
+
safeLogModuleEvent {
|
|
1176
|
+
logModuleEvent("processBatchDataAndStartObserver", throwable = e, level = SentryLogLevel.ERROR)
|
|
1177
|
+
}
|
|
977
1178
|
// Start live observation even on error
|
|
978
1179
|
withContext(Dispatchers.Main) {
|
|
979
1180
|
if (!isObserving) {
|
|
@@ -993,7 +1194,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
993
1194
|
promise.resolve(dbFile.absolutePath)
|
|
994
1195
|
} catch (e: Exception) {
|
|
995
1196
|
Log.d("dbFileerrrr======", "dbFileerrrr======", e)
|
|
996
|
-
|
|
1197
|
+
safeLogModuleEvent {
|
|
1198
|
+
logModuleEvent("getTrackLibDbPath", throwable = e, level = SentryLogLevel.ERROR)
|
|
1199
|
+
}
|
|
997
1200
|
promise.reject("ERROR_DB_PATH", e)
|
|
998
1201
|
}
|
|
999
1202
|
}
|
|
@@ -1024,7 +1227,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1024
1227
|
|
|
1025
1228
|
} catch (e: Exception) {
|
|
1026
1229
|
Log.e("resetCgmState", "Error resetting CGM state: ${e.message}", e)
|
|
1027
|
-
|
|
1230
|
+
safeLogModuleEvent {
|
|
1231
|
+
logModuleEvent("resetCgmState", throwable = e, level = SentryLogLevel.ERROR)
|
|
1232
|
+
}
|
|
1028
1233
|
}
|
|
1029
1234
|
}
|
|
1030
1235
|
|
|
@@ -1085,11 +1290,54 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1085
1290
|
|
|
1086
1291
|
} catch (e: Exception) {
|
|
1087
1292
|
Log.e("getCgmLogFiles", "Error getting log files: ${e.message}", e)
|
|
1088
|
-
|
|
1293
|
+
safeLogModuleEvent {
|
|
1294
|
+
logModuleEvent("getCgmLogFiles", throwable = e, level = SentryLogLevel.ERROR)
|
|
1295
|
+
}
|
|
1089
1296
|
promise.reject("ERROR_GET_LOG_FILES", e.message, e)
|
|
1090
1297
|
}
|
|
1091
1298
|
}
|
|
1092
1299
|
|
|
1300
|
+
/** POC field: use SDK value when present, otherwise type-appropriate default. */
|
|
1301
|
+
private fun mapPocGlucoseToCgmLog(pocGlucose: PocGlucose): CgmLog {
|
|
1302
|
+
val trend = pocGlucose.trend ?: enumTrend.NONE
|
|
1303
|
+
val glucoseStatus = pocGlucose.glucoseStatus ?: enumGlucoseStatus.NONE
|
|
1304
|
+
val errorCode = pocGlucose.errorCode ?: enumError.NONE
|
|
1305
|
+
|
|
1306
|
+
return CgmLog(
|
|
1307
|
+
timeInMillis = pocGlucose.timeInMillis,
|
|
1308
|
+
countdownMinutes = pocGlucose.countdownMinutes,
|
|
1309
|
+
countdownDays = pocGlucose.countdownDays,
|
|
1310
|
+
hypoglycemiaEarlyWarnMinutes = pocGlucose.hypoglycemiaEarlyWarnMinutes,
|
|
1311
|
+
showGlucoseMG = pocGlucose.showGlucoseMG,
|
|
1312
|
+
glucoseId = pocGlucose.glucoseId ?: 0,
|
|
1313
|
+
name = pocGlucose.name.orEmpty(),
|
|
1314
|
+
bytes = pocGlucose.bytes ?: ByteArray(0),
|
|
1315
|
+
showGlucose = pocGlucose.showGlucose,
|
|
1316
|
+
Ib = pocGlucose.ib,
|
|
1317
|
+
Iw = pocGlucose.iw,
|
|
1318
|
+
countdownHours = pocGlucose.countdownHours,
|
|
1319
|
+
T = pocGlucose.t,
|
|
1320
|
+
year = pocGlucose.year,
|
|
1321
|
+
month = pocGlucose.month,
|
|
1322
|
+
day = pocGlucose.day,
|
|
1323
|
+
hour = pocGlucose.hour,
|
|
1324
|
+
minute = pocGlucose.minute,
|
|
1325
|
+
trendObject = TrendObject(
|
|
1326
|
+
trendId = trend.trendId,
|
|
1327
|
+
drawableId = trend.drawableId,
|
|
1328
|
+
widgetImg = trend.widgetImg,
|
|
1329
|
+
apsChangeRate = trend.apsChangeRate.orEmpty()
|
|
1330
|
+
),
|
|
1331
|
+
glucoseStatusObject = GlucoseStatusObject(
|
|
1332
|
+
statusId = glucoseStatus.statusId
|
|
1333
|
+
),
|
|
1334
|
+
errorObject = ErrorObject(
|
|
1335
|
+
errorId = errorCode.errorId,
|
|
1336
|
+
sound = errorCode.sound ?: enumSound.NONE
|
|
1337
|
+
)
|
|
1338
|
+
)
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1093
1341
|
// Updated batch processing method with better sync control
|
|
1094
1342
|
private suspend fun processBatchDataSynchronously(
|
|
1095
1343
|
dataList: List<PocGlucose>,
|
|
@@ -1141,42 +1389,25 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1141
1389
|
|
|
1142
1390
|
for ((index, batch) in chunks.withIndex()) {
|
|
1143
1391
|
try {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
Ib = pocGlucose.ib,
|
|
1156
|
-
Iw = pocGlucose.iw,
|
|
1157
|
-
countdownHours = pocGlucose.countdownHours,
|
|
1158
|
-
T = pocGlucose.t,
|
|
1159
|
-
year = pocGlucose.year,
|
|
1160
|
-
month = pocGlucose.month,
|
|
1161
|
-
day = pocGlucose.day,
|
|
1162
|
-
hour = pocGlucose.hour,
|
|
1163
|
-
minute = pocGlucose.minute,
|
|
1164
|
-
trendObject = com.mytatvarnsdk.model.TrendObject(
|
|
1165
|
-
trendId = pocGlucose.trend.trendId,
|
|
1166
|
-
drawableId = pocGlucose.trend.drawableId,
|
|
1167
|
-
widgetImg = pocGlucose.trend.widgetImg,
|
|
1168
|
-
apsChangeRate = pocGlucose.trend.apsChangeRate
|
|
1169
|
-
),
|
|
1170
|
-
glucoseStatusObject = com.mytatvarnsdk.model.GlucoseStatusObject(
|
|
1171
|
-
statusId = pocGlucose.glucoseStatus.statusId
|
|
1172
|
-
),
|
|
1173
|
-
errorObject = com.mytatvarnsdk.model.ErrorObject(
|
|
1174
|
-
errorId = pocGlucose.errorCode.errorId,
|
|
1175
|
-
sound = pocGlucose.errorCode.sound
|
|
1392
|
+
safeLogModuleEvent {
|
|
1393
|
+
logModuleEvent(
|
|
1394
|
+
where = "processBatchDataSynchronously.batchStarted",
|
|
1395
|
+
message = "Batch $index started | rawRecords=${batch.size} | totalBatches=${chunks.size}",
|
|
1396
|
+
level = SentryLogLevel.INFO,
|
|
1397
|
+
attributes = mapOf(
|
|
1398
|
+
"batchIndex" to index.toString(),
|
|
1399
|
+
"batch_raw_records" to batch.size.toString(),
|
|
1400
|
+
"total_batches" to chunks.size.toString(),
|
|
1401
|
+
"first_glucoseId" to (batch.firstOrNull()?.glucoseId?.toString() ?: ""),
|
|
1402
|
+
"last_glucoseId" to (batch.lastOrNull()?.glucoseId?.toString() ?: "")
|
|
1176
1403
|
)
|
|
1177
1404
|
)
|
|
1178
1405
|
}
|
|
1179
1406
|
|
|
1407
|
+
val transformedLogs = batch.map { pocGlucose ->
|
|
1408
|
+
mapPocGlucoseToCgmLog(pocGlucose)
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1180
1411
|
if (transformedLogs.isEmpty()) {
|
|
1181
1412
|
Log.d(
|
|
1182
1413
|
"processBatchDataSynchronously",
|
|
@@ -1195,14 +1426,45 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1195
1426
|
|
|
1196
1427
|
val allResult = AllCGMLogRequest(vendor = "GoodFlip", logs = transformedLogs)
|
|
1197
1428
|
|
|
1429
|
+
safeLogModuleEvent {
|
|
1430
|
+
logModuleEvent(
|
|
1431
|
+
where = "processBatchDataSynchronously.batchAssembled",
|
|
1432
|
+
message = "Batch $index assembled | records=${transformedLogs.size}",
|
|
1433
|
+
level = SentryLogLevel.INFO,
|
|
1434
|
+
jsonPayload = Gson().toJson(allResult),
|
|
1435
|
+
attributes = mapOf(
|
|
1436
|
+
"batchIndex" to index.toString(),
|
|
1437
|
+
"batch_records" to transformedLogs.size.toString(),
|
|
1438
|
+
"first_glucoseId" to (batch.firstOrNull()?.glucoseId?.toString() ?: ""),
|
|
1439
|
+
"last_glucoseId" to (batch.lastOrNull()?.glucoseId?.toString() ?: "")
|
|
1440
|
+
)
|
|
1441
|
+
)
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1198
1444
|
// Attach sensorId at the top level of the batch payload sent to /cgm/logs
|
|
1445
|
+
val activeSensorId =
|
|
1446
|
+
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
1199
1447
|
val sensorPayloadJsonObject = JSONObject(Gson().toJson(allResult)).apply {
|
|
1200
|
-
val activeSensorId =
|
|
1201
|
-
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
1202
1448
|
put("sensorId", activeSensorId)
|
|
1203
1449
|
}
|
|
1204
1450
|
val json = sensorPayloadJsonObject.toString()
|
|
1205
1451
|
|
|
1452
|
+
safeLogModuleEvent {
|
|
1453
|
+
logModuleEvent(
|
|
1454
|
+
where = "processBatchDataSynchronously.batchPayloadBuilt",
|
|
1455
|
+
message = "Batch $index payload built | records=${transformedLogs.size} | activeSensorId=$activeSensorId",
|
|
1456
|
+
level = SentryLogLevel.INFO,
|
|
1457
|
+
jsonPayload = json,
|
|
1458
|
+
attributes = mapOf(
|
|
1459
|
+
"batchIndex" to index.toString(),
|
|
1460
|
+
"batch_records" to transformedLogs.size.toString(),
|
|
1461
|
+
"activeSensorId" to activeSensorId,
|
|
1462
|
+
"first_glucoseId" to (batch.firstOrNull()?.glucoseId?.toString() ?: ""),
|
|
1463
|
+
"last_glucoseId" to (batch.lastOrNull()?.glucoseId?.toString() ?: "")
|
|
1464
|
+
)
|
|
1465
|
+
)
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1206
1468
|
// Check if logs array is empty - skip API call if so
|
|
1207
1469
|
if (transformedLogs.isEmpty()) {
|
|
1208
1470
|
Log.d(
|
|
@@ -1222,44 +1484,69 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1222
1484
|
)
|
|
1223
1485
|
logLongJson("Batch $index JSON=>>> ", json)
|
|
1224
1486
|
|
|
1487
|
+
safeLogModuleEvent {
|
|
1488
|
+
logModuleEvent(
|
|
1489
|
+
where = "processBatchDataSynchronously.postCGMData",
|
|
1490
|
+
message = "Posting batch $index | records=${transformedLogs.size}",
|
|
1491
|
+
level = SentryLogLevel.INFO,
|
|
1492
|
+
jsonPayload = json,
|
|
1493
|
+
attributes = mapOf(
|
|
1494
|
+
"batchIndex" to index.toString(),
|
|
1495
|
+
"batch_records" to transformedLogs.size.toString(),
|
|
1496
|
+
"first_glucoseId" to (batch.firstOrNull()?.glucoseId?.toString() ?: ""),
|
|
1497
|
+
"last_glucoseId" to (batch.lastOrNull()?.glucoseId?.toString() ?: "")
|
|
1498
|
+
)
|
|
1499
|
+
)
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1225
1502
|
val uploadSuccessful = uploadBatchSynchronously(json, index, envType)
|
|
1226
1503
|
|
|
1227
1504
|
if (uploadSuccessful) {
|
|
1228
1505
|
lastSyncedRecord = batch.lastOrNull()
|
|
1229
1506
|
// Update sync metadata after each successful batch
|
|
1230
1507
|
updateSyncMetadata(lastSyncedRecord)
|
|
1231
|
-
//
|
|
1508
|
+
// logModuleEvent(
|
|
1232
1509
|
// "processBatchDataSynchronously.batchSuccess",
|
|
1233
|
-
// json,
|
|
1234
|
-
//
|
|
1235
|
-
//
|
|
1236
|
-
// "batchIndex" to index.toString(),
|
|
1237
|
-
// "lastSyncedRecord" to (lastSyncedRecord?.toString() ?: "")
|
|
1238
|
-
// ),
|
|
1239
|
-
// level = SentryLevel.INFO
|
|
1510
|
+
// jsonPayload = json,
|
|
1511
|
+
// level = SentryLogLevel.INFO,
|
|
1512
|
+
// attributes = mapOf("batchIndex" to index.toString())
|
|
1240
1513
|
// )
|
|
1241
1514
|
|
|
1242
1515
|
Log.d("Batch Upload", "✅ Batch $index uploaded and synced successfully")
|
|
1243
1516
|
} else {
|
|
1244
1517
|
allBatchesSuccessful = false
|
|
1245
1518
|
Log.e("Batch Upload", "❌ Batch $index failed")
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1519
|
+
safeLogModuleEvent {
|
|
1520
|
+
val lastSync = prefsHelper?.lastSyncData
|
|
1521
|
+
val contextData =
|
|
1522
|
+
"failure_reason=postCGMData returned failure;" +
|
|
1523
|
+
"batchIndex=$index;" +
|
|
1524
|
+
"batch_records=${batch.size};" +
|
|
1525
|
+
"payload_chars=${json.length};" +
|
|
1526
|
+
"first_glucoseId=${batch.firstOrNull()?.glucoseId ?: ""};" +
|
|
1527
|
+
"last_glucoseId=${batch.lastOrNull()?.glucoseId ?: ""};" +
|
|
1528
|
+
"first_timeInMillis=${batch.firstOrNull()?.timeInMillis ?: ""};" +
|
|
1529
|
+
"last_timeInMillis=${batch.lastOrNull()?.timeInMillis ?: ""};" +
|
|
1530
|
+
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
1531
|
+
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
1532
|
+
logModuleEvent(
|
|
1533
|
+
where = "processBatchDataSynchronously.batchUploadFailed",
|
|
1534
|
+
message = "postCGMData returned failure for batch $index | $contextData",
|
|
1535
|
+
level = SentryLogLevel.WARN,
|
|
1536
|
+
jsonPayload = json,
|
|
1537
|
+
attributes = mapOf(
|
|
1538
|
+
"batchIndex" to index.toString(),
|
|
1539
|
+
"batch_records" to batch.size.toString(),
|
|
1540
|
+
"payload_chars" to json.length.toString(),
|
|
1541
|
+
"first_glucoseId" to (batch.firstOrNull()?.glucoseId?.toString() ?: ""),
|
|
1542
|
+
"last_glucoseId" to (batch.lastOrNull()?.glucoseId?.toString() ?: ""),
|
|
1543
|
+
"first_timeInMillis" to (batch.firstOrNull()?.timeInMillis?.toString() ?: ""),
|
|
1544
|
+
"last_timeInMillis" to (batch.lastOrNull()?.timeInMillis?.toString() ?: ""),
|
|
1545
|
+
"lastSync_glucoseId" to (lastSync?.glucoseId?.toString() ?: ""),
|
|
1546
|
+
"lastSync_timeInMillis" to (lastSync?.timeInMillis?.toString() ?: "")
|
|
1547
|
+
)
|
|
1548
|
+
)
|
|
1549
|
+
}
|
|
1263
1550
|
// Continue with next batch instead of breaking (optional based on your needs)
|
|
1264
1551
|
// break
|
|
1265
1552
|
}
|
|
@@ -1269,13 +1556,15 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1269
1556
|
|
|
1270
1557
|
} catch (e: Exception) {
|
|
1271
1558
|
Log.e("Batch Upload", "❌ Batch $index exception: ${e.message}", e)
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
"processBatchDataSynchronously.batch failed | batchIndex=$index",
|
|
1276
|
-
e
|
|
1559
|
+
safeLogModuleEvent {
|
|
1560
|
+
logModuleEvent(
|
|
1561
|
+
where = "processBatchDataSynchronously.batch",
|
|
1562
|
+
message = "processBatchDataSynchronously.batch failed | batchIndex=$index",
|
|
1563
|
+
throwable = e,
|
|
1564
|
+
level = SentryLogLevel.ERROR,
|
|
1565
|
+
attributes = mapOf("batchIndex" to index.toString())
|
|
1277
1566
|
)
|
|
1278
|
-
|
|
1567
|
+
}
|
|
1279
1568
|
allBatchesSuccessful = false
|
|
1280
1569
|
// Continue processing other batches
|
|
1281
1570
|
}
|
|
@@ -1320,7 +1609,13 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1320
1609
|
Log.d("stopObservingGlucoseData", "Device observer removed successfully")
|
|
1321
1610
|
} catch (e: Exception) {
|
|
1322
1611
|
Log.e("stopObservingGlucoseData", "Error removing observers: ${e.message}", e)
|
|
1323
|
-
|
|
1612
|
+
safeLogModuleEvent {
|
|
1613
|
+
logModuleEvent(
|
|
1614
|
+
"stopObservingGlucoseData.removeObservers",
|
|
1615
|
+
throwable = e,
|
|
1616
|
+
level = SentryLogLevel.ERROR
|
|
1617
|
+
)
|
|
1618
|
+
}
|
|
1324
1619
|
}
|
|
1325
1620
|
}
|
|
1326
1621
|
|
|
@@ -1330,7 +1625,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1330
1625
|
|
|
1331
1626
|
} catch (e: Exception) {
|
|
1332
1627
|
Log.e("stopObservingGlucoseData", "Error stopping observer: ${e.message}", e)
|
|
1333
|
-
|
|
1628
|
+
safeLogModuleEvent {
|
|
1629
|
+
logModuleEvent("stopObservingGlucoseData", throwable = e, level = SentryLogLevel.ERROR)
|
|
1630
|
+
}
|
|
1334
1631
|
}
|
|
1335
1632
|
}
|
|
1336
1633
|
|
|
@@ -1342,29 +1639,89 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1342
1639
|
): Boolean {
|
|
1343
1640
|
return suspendCoroutine { continuation ->
|
|
1344
1641
|
try {
|
|
1642
|
+
safeLogModuleEvent {
|
|
1643
|
+
val activeSensorId =
|
|
1644
|
+
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
1645
|
+
logModuleEvent(
|
|
1646
|
+
where = "uploadBatchSynchronously.postCGMData",
|
|
1647
|
+
message = "Posting batch upload | batchIndex=$batchIndex | activeSensorId=$activeSensorId",
|
|
1648
|
+
level = SentryLogLevel.INFO,
|
|
1649
|
+
jsonPayload = json,
|
|
1650
|
+
attributes = mapOf(
|
|
1651
|
+
"batchIndex" to batchIndex.toString(),
|
|
1652
|
+
"activeSensorId" to activeSensorId,
|
|
1653
|
+
"payload_chars" to json.length.toString()
|
|
1654
|
+
)
|
|
1655
|
+
)
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1345
1658
|
authenticateSDKService.postCGMData(
|
|
1346
1659
|
environment = if (envType.lowercase() == "uat") TATVA_ENVIRONMENT.STAGE else TATVA_ENVIRONMENT.PROD,
|
|
1347
1660
|
data = json,
|
|
1348
1661
|
token = userToken,
|
|
1349
1662
|
responseListener = object : AuthenticateSDKService.ResponseListener {
|
|
1350
1663
|
override fun onResponseSuccess(response: String) {
|
|
1664
|
+
safeLogModuleEvent {
|
|
1665
|
+
val activeSensorId =
|
|
1666
|
+
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
1667
|
+
logModuleEvent(
|
|
1668
|
+
where = "uploadBatchSynchronously.postCGMData.success",
|
|
1669
|
+
message = "Batch upload succeeded | batchIndex=$batchIndex | activeSensorId=$activeSensorId",
|
|
1670
|
+
level = SentryLogLevel.INFO,
|
|
1671
|
+
jsonPayload = json,
|
|
1672
|
+
attributes = mapOf(
|
|
1673
|
+
"batchIndex" to batchIndex.toString(),
|
|
1674
|
+
"activeSensorId" to activeSensorId,
|
|
1675
|
+
"payload_chars" to json.length.toString(),
|
|
1676
|
+
"sdk_response" to response
|
|
1677
|
+
)
|
|
1678
|
+
)
|
|
1679
|
+
}
|
|
1351
1680
|
continuation.resume(true)
|
|
1352
1681
|
}
|
|
1353
1682
|
|
|
1354
1683
|
override fun onResponseFail() {
|
|
1684
|
+
safeLogModuleEvent {
|
|
1685
|
+
val activeSensorId =
|
|
1686
|
+
prefsHelper?.qrInformation?.sensor ?: lastConnectCgm ?: ""
|
|
1687
|
+
val lastSync = prefsHelper?.lastSyncData
|
|
1688
|
+
val contextData =
|
|
1689
|
+
"failure_reason=postCGMData returned failure;" +
|
|
1690
|
+
"batchIndex=$batchIndex;" +
|
|
1691
|
+
"payload_chars=${json.length};" +
|
|
1692
|
+
"activeSensorId=$activeSensorId;" +
|
|
1693
|
+
"lastSync_glucoseId=${lastSync?.glucoseId ?: ""};" +
|
|
1694
|
+
"lastSync_timeInMillis=${lastSync?.timeInMillis ?: ""}"
|
|
1695
|
+
logModuleEvent(
|
|
1696
|
+
where = "uploadBatchSynchronously.postCGMData.fail",
|
|
1697
|
+
message = contextData,
|
|
1698
|
+
level = SentryLogLevel.WARN,
|
|
1699
|
+
jsonPayload = json,
|
|
1700
|
+
attributes = mapOf(
|
|
1701
|
+
"batchIndex" to batchIndex.toString(),
|
|
1702
|
+
"activeSensorId" to activeSensorId,
|
|
1703
|
+
"payload_chars" to json.length.toString(),
|
|
1704
|
+
"lastSync_glucoseId" to (lastSync?.glucoseId?.toString() ?: ""),
|
|
1705
|
+
"lastSync_timeInMillis" to (lastSync?.timeInMillis?.toString() ?: "")
|
|
1706
|
+
)
|
|
1707
|
+
)
|
|
1708
|
+
}
|
|
1355
1709
|
continuation.resume(false)
|
|
1356
1710
|
}
|
|
1357
1711
|
}
|
|
1358
1712
|
)
|
|
1359
1713
|
} catch (e: Exception) {
|
|
1360
1714
|
Log.e("uploadBatchSynchronously", "Exception in batch $batchIndex: ${e.message}", e)
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
"uploadBatchSynchronously failed | batchIndex=$batchIndex",
|
|
1365
|
-
e
|
|
1715
|
+
safeLogModuleEvent {
|
|
1716
|
+
logModuleEvent(
|
|
1717
|
+
where = "uploadBatchSynchronously",
|
|
1718
|
+
message = "uploadBatchSynchronously failed | batchIndex=$batchIndex",
|
|
1719
|
+
throwable = e,
|
|
1720
|
+
level = SentryLogLevel.ERROR,
|
|
1721
|
+
jsonPayload = json,
|
|
1722
|
+
attributes = mapOf("batchIndex" to batchIndex.toString())
|
|
1366
1723
|
)
|
|
1367
|
-
|
|
1724
|
+
}
|
|
1368
1725
|
continuation.resume(false)
|
|
1369
1726
|
}
|
|
1370
1727
|
}
|
|
@@ -1392,7 +1749,9 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1392
1749
|
)
|
|
1393
1750
|
} catch (e: Exception) {
|
|
1394
1751
|
Log.e("updateSyncMetadata", "Error updating sync metadata: ${e.message}", e)
|
|
1395
|
-
|
|
1752
|
+
safeLogModuleEvent {
|
|
1753
|
+
logModuleEvent("updateSyncMetadata", throwable = e, level = SentryLogLevel.ERROR)
|
|
1754
|
+
}
|
|
1396
1755
|
}
|
|
1397
1756
|
}
|
|
1398
1757
|
}
|
|
@@ -1412,48 +1771,46 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1412
1771
|
}
|
|
1413
1772
|
|
|
1414
1773
|
fun mapToDto(glucose: PocGlucose): GlucoseLog {
|
|
1415
|
-
val
|
|
1416
|
-
|
|
1417
|
-
dto
|
|
1418
|
-
dto.
|
|
1419
|
-
dto.
|
|
1420
|
-
dto.
|
|
1421
|
-
dto.
|
|
1422
|
-
dto.
|
|
1423
|
-
dto.
|
|
1424
|
-
dto.
|
|
1425
|
-
dto.
|
|
1426
|
-
dto.
|
|
1427
|
-
dto.
|
|
1428
|
-
dto.
|
|
1429
|
-
dto.
|
|
1430
|
-
dto.
|
|
1431
|
-
dto.
|
|
1432
|
-
dto.
|
|
1433
|
-
|
|
1434
|
-
|
|
1774
|
+
val log = mapPocGlucoseToCgmLog(glucose)
|
|
1775
|
+
|
|
1776
|
+
val dto = GlucoseLog()
|
|
1777
|
+
dto.timeInMillis = log.timeInMillis
|
|
1778
|
+
dto.countdownMinutes = log.countdownMinutes
|
|
1779
|
+
dto.countdownHours = log.countdownHours
|
|
1780
|
+
dto.countdownDays = log.countdownDays
|
|
1781
|
+
dto.hypoglycemiaEarlyWarnMinutes = log.hypoglycemiaEarlyWarnMinutes
|
|
1782
|
+
dto.showGlucoseMG = log.showGlucoseMG
|
|
1783
|
+
dto.glucoseId = log.glucoseId
|
|
1784
|
+
dto.name = log.name
|
|
1785
|
+
dto.showGlucose = log.showGlucose
|
|
1786
|
+
dto.Ib = log.Ib
|
|
1787
|
+
dto.Iw = log.Iw
|
|
1788
|
+
dto.T = log.T
|
|
1789
|
+
dto.year = log.year
|
|
1790
|
+
dto.month = log.month
|
|
1791
|
+
dto.day = log.day
|
|
1792
|
+
dto.hour = log.hour
|
|
1793
|
+
dto.minute = log.minute
|
|
1794
|
+
|
|
1435
1795
|
dto.bytes = ArrayList()
|
|
1436
|
-
|
|
1437
|
-
dto.bytes?.add(b.toInt() and 0xFF)
|
|
1796
|
+
log.bytes?.forEach { b ->
|
|
1797
|
+
dto.bytes?.add(b.toInt() and 0xFF)
|
|
1438
1798
|
}
|
|
1439
1799
|
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
trendObj.
|
|
1443
|
-
trendObj.
|
|
1444
|
-
trendObj.
|
|
1445
|
-
trendObj.apsChangeRate = glucose.getTrend().getApsChangeRate()
|
|
1800
|
+
val trendObj = GlucoseLog.TrendObject()
|
|
1801
|
+
trendObj.trendId = log.trendObject.trendId
|
|
1802
|
+
trendObj.drawableId = log.trendObject.drawableId
|
|
1803
|
+
trendObj.widgetImg = log.trendObject.widgetImg
|
|
1804
|
+
trendObj.apsChangeRate = log.trendObject.apsChangeRate
|
|
1446
1805
|
dto.trendObject = trendObj
|
|
1447
1806
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
statusObj.statusId = glucose.getGlucoseStatus().getStatusId()
|
|
1807
|
+
val statusObj = GlucoseLog.GlucoseStatusObject()
|
|
1808
|
+
statusObj.statusId = log.glucoseStatusObject.statusId
|
|
1451
1809
|
dto.glucoseStatusObject = statusObj
|
|
1452
1810
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
errorObj.
|
|
1456
|
-
errorObj.sound = glucose.getErrorCode().getSound().toString()
|
|
1811
|
+
val errorObj = GlucoseLog.ErrorObject()
|
|
1812
|
+
errorObj.errorId = log.errorObject.errorId
|
|
1813
|
+
errorObj.sound = log.errorObject.sound.toString()
|
|
1457
1814
|
dto.errorObject = errorObj
|
|
1458
1815
|
|
|
1459
1816
|
return dto
|
|
@@ -1476,13 +1833,18 @@ class CgmTrackyLibModule(reactContext: ReactApplicationContext) :
|
|
|
1476
1833
|
?.emit(eventName, map)
|
|
1477
1834
|
} catch (e: Exception) {
|
|
1478
1835
|
Log.e("Error sendDataToReact: ", e.message.toString(), e)
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
"sendDataToReact failed | eventName=$eventName;status=$status",
|
|
1483
|
-
e
|
|
1836
|
+
safeLogModuleEvent {
|
|
1837
|
+
logModuleEvent(
|
|
1838
|
+
where = "sendDataToReact",
|
|
1839
|
+
message = "sendDataToReact failed | eventName=$eventName;status=$status",
|
|
1840
|
+
throwable = e,
|
|
1841
|
+
level = SentryLogLevel.ERROR,
|
|
1842
|
+
attributes = mapOf(
|
|
1843
|
+
"eventName" to eventName,
|
|
1844
|
+
"status" to status
|
|
1845
|
+
)
|
|
1484
1846
|
)
|
|
1485
|
-
|
|
1847
|
+
}
|
|
1486
1848
|
}
|
|
1487
1849
|
}
|
|
1488
1850
|
|