NSCv3: improve error handling

This commit is contained in:
Milos Kozak 2023-01-15 20:08:00 +01:00
parent 4b0c86546c
commit a3711f0c0c
10 changed files with 298 additions and 278 deletions

View file

@ -3,7 +3,7 @@ package info.nightscout.rx.events
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
class EventNSClientNewLog(val action: String, val logText: String) : Event() { class EventNSClientNewLog(val action: String, val logText: String?) : Event() {
var date = System.currentTimeMillis() var date = System.currentTimeMillis()
private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) private var timeFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())

View file

@ -16,6 +16,7 @@ import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.localmodel.entry.NSSgvV3 import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
@ -49,46 +50,63 @@ class LoadBgWorker(
return Result.success(workDataOf("Result" to "Load not enabled")) return Result.success(workDataOf("Result" to "Load not enabled"))
} }
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) try {
val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.ENTRIES) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
val lastLoaded = val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.ENTRIES)
if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) val lastLoaded =
else max(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) { else max(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge)
val sgvs: List<NSSgvV3> if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) {
val response: NSAndroidClient.ReadResponse<List<NSSgvV3>>? val sgvs: List<NSSgvV3>
if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, 500) val response: NSAndroidClient.ReadResponse<List<NSSgvV3>>?
else { if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, 500)
response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, 500) else {
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.entries = it } response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, 500)
nsClientV3Plugin.storeLastLoadedSrvModified() response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.entries = it }
nsClientV3Plugin.scheduleIrregularExecution() // Idea is to run after 5 min after last BG nsClientV3Plugin.storeLastLoadedSrvModified()
} nsClientV3Plugin.scheduleIrregularExecution() // Idea is to run after 5 min after last BG
sgvs = response.values }
aapsLogger.debug("SGVS: $sgvs") sgvs = response.values
if (sgvs.isNotEmpty()) { aapsLogger.debug(LTag.NSCLIENT, "SGVS: $sgvs")
val action = if (isFirstLoad) "RCV-FIRST" else "RCV" if (sgvs.isNotEmpty()) {
rxBus.send(EventNSClientNewLog(action, "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) val action = if (isFirstLoad) "RCV-FIRST" else "RCV"
// Objective0 rxBus.send(EventNSClientNewLog(action, "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true) // Objective0
// Schedule processing of fetched data and continue of loading sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true)
workManager // Schedule processing of fetched data and continue of loading
.beginUniqueWork( workManager
NSClientV3Plugin.JOB_NAME, .beginUniqueWork(
ExistingWorkPolicy.APPEND_OR_REPLACE, NSClientV3Plugin.JOB_NAME,
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(sgvs)).build() ExistingWorkPolicy.APPEND_OR_REPLACE,
) OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(sgvs)).build()
// response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload )
.then(response.code != 304, OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build()) // response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload
.then(response.code == 304, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()) .then(response.code != 304, OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build())
.enqueue() .then(response.code == 304, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
} else {
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
workManager
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
}
} else { } else {
// End first load // End first load
if (isFirstLoad) { if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
} }
rxBus.send(EventNSClientNewLog("RCV END", "No SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("RCV END", "No new SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
workManager workManager
.beginUniqueWork( .beginUniqueWork(
NSClientV3Plugin.JOB_NAME, NSClientV3Plugin.JOB_NAME,
@ -98,22 +116,12 @@ class LoadBgWorker(
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()) .then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue() .enqueue()
} }
} else { } catch (error: Exception) {
// End first load aapsLogger.error("Error: ", error)
if (isFirstLoad) { rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded return Result.failure(workDataOf("Error" to error.localizedMessage))
nsClientV3Plugin.storeLastLoadedSrvModified() }
}
rxBus.send(EventNSClientNewLog("RCV END", "No new SGVs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
workManager
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
}
return Result.success() return Result.success()
} }
} }

View file

@ -15,7 +15,6 @@ import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.inject.Inject import javax.inject.Inject
class LoadDeviceStatusWorker( class LoadDeviceStatusWorker(
@ -32,31 +31,30 @@ class LoadDeviceStatusWorker(
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
var ret = Result.success()
runBlocking { try {
try { val from = dateUtil.now() - T.mins(7).msecs()
val from = dateUtil.now() - T.mins(7).msecs() val deviceStatuses = nsAndroidClient.getDeviceStatusModifiedSince(from)
val deviceStatuses = nsAndroidClient.getDeviceStatusModifiedSince(from) aapsLogger.debug("DEVICESTATUSES: $deviceStatuses")
aapsLogger.debug("DEVICESTATUSES: $deviceStatuses") if (deviceStatuses.isNotEmpty()) {
if (deviceStatuses.isNotEmpty()) { rxBus.send(EventNSClientNewLog("RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}"))
rxBus.send(EventNSClientNewLog("RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) nsDeviceStatusHandler.handleNewData(deviceStatuses.toTypedArray())
nsDeviceStatusHandler.handleNewData(deviceStatuses.toTypedArray()) rxBus.send(EventNSClientNewLog("DONE DS", ""))
rxBus.send(EventNSClientNewLog("DONE DS", "")) } else {
} else { rxBus.send(EventNSClientNewLog("RCV END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}"))
rxBus.send(EventNSClientNewLog("RCV END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}"))
}
WorkManager.getInstance(context)
.enqueueUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(DataSyncWorker::class.java).build()
)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
} }
WorkManager.getInstance(context)
.enqueueUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(DataSyncWorker::class.java).build()
)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
return ret
return Result.success()
} }
} }

View file

@ -13,10 +13,10 @@ import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.food.NSFood import info.nightscout.sdk.localmodel.food.NSFood
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.inject.Inject import javax.inject.Inject
class LoadFoodsWorker( class LoadFoodsWorker(
@ -36,10 +36,10 @@ class LoadFoodsWorker(
// Food database doesn't provide last record modification // Food database doesn't provide last record modification
// Read full collection every 5th attempt // Read full collection every 5th attempt
runBlocking { try {
if (nsClientV3Plugin.lastLoadedSrvModified.collections.foods++ % 5 == 0L) { if (nsClientV3Plugin.lastLoadedSrvModified.collections.foods++ % 5 == 0L) {
val foods: List<NSFood> = nsAndroidClient.getFoods(1000).values val foods: List<NSFood> = nsAndroidClient.getFoods(1000).values
aapsLogger.debug("FOODS: $foods") aapsLogger.debug(LTag.NSCLIENT, "FOODS: $foods")
rxBus.send(EventNSClientNewLog("RCV", "${foods.size} FOODs")) rxBus.send(EventNSClientNewLog("RCV", "${foods.size} FOODs"))
// Schedule processing of fetched data // Schedule processing of fetched data
WorkManager.getInstance(context) WorkManager.getInstance(context)
@ -61,7 +61,12 @@ class LoadFoodsWorker(
OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build() OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build()
) )
} }
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
return Result.success() return Result.success()
} }
} }

View file

@ -5,8 +5,10 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.inject.Inject import javax.inject.Inject
class LoadLastModificationWorker( class LoadLastModificationWorker(
@ -14,21 +16,20 @@ class LoadLastModificationWorker(
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var rxBus: RxBus
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
var ret = Result.success()
runBlocking { try {
try { val lm = nsAndroidClient.getLastModified()
val lm = nsAndroidClient.getLastModified() nsClientV3Plugin.newestDataOnServer = lm
nsClientV3Plugin.newestDataOnServer = lm aapsLogger.debug(LTag.NSCLIENT, "LAST MODIFIED: ${nsClientV3Plugin.newestDataOnServer}")
aapsLogger.debug("LAST MODIFIED: ${nsClientV3Plugin.newestDataOnServer}") } catch (error: Exception) {
} catch (error: Exception) { aapsLogger.error(LTag.NSCLIENT, "Error: ", error)
aapsLogger.error("Error: ", error) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
ret = Result.failure(workDataOf("Error" to error.toString())) return Result.failure(workDataOf("Error" to error.localizedMessage))
}
} }
return ret return Result.success()
} }
} }

View file

@ -13,10 +13,10 @@ import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.json.JSONObject import org.json.JSONObject
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
@ -35,43 +35,37 @@ class LoadProfileStoreWorker(
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
var ret = Result.success()
val lastLoaded = max(nsClientV3Plugin.lastLoadedSrvModified.collections.profile, 0) try {
runBlocking { val lastLoaded = max(nsClientV3Plugin.lastLoadedSrvModified.collections.profile, 0)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.profile ?: Long.MAX_VALUE) > lastLoaded) if ((nsClientV3Plugin.newestDataOnServer?.collections?.profile ?: Long.MAX_VALUE) > lastLoaded) {
try { val response: NSAndroidClient.ReadResponse<List<JSONObject>> = nsAndroidClient.getLastProfileStore()
val response: NSAndroidClient.ReadResponse<List<JSONObject>> = nsAndroidClient.getLastProfileStore() val profiles = response.values
val profiles = response.values if (profiles.size == 1) {
if (profiles.size == 1) { val profile = profiles[0]
val profile = profiles[0] JsonHelper.safeGetLongAllowNull(profile, "srvModified")?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = it }
JsonHelper.safeGetLongAllowNull(profile, "srvModified")?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = it } nsClientV3Plugin.storeLastLoadedSrvModified()
nsClientV3Plugin.storeLastLoadedSrvModified() aapsLogger.debug(LTag.NSCLIENT, "PROFILE: $profile")
aapsLogger.debug("PROFILE: $profile") rxBus.send(EventNSClientNewLog("RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
rxBus.send(EventNSClientNewLog("RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context)
WorkManager.getInstance(context) .beginUniqueWork(
.beginUniqueWork( NSClientV3Plugin.JOB_NAME,
NSClientV3Plugin.JOB_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE,
ExistingWorkPolicy.APPEND_OR_REPLACE, OneTimeWorkRequest.Builder((workerClasses.nsProfileWorker))
OneTimeWorkRequest.Builder((workerClasses.nsProfileWorker)) .setInputData(dataWorkerStorage.storeInputData(profile))
.setInputData(dataWorkerStorage.storeInputData(profile)) .build()
.build() ).then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build())
).then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()) .enqueue()
.enqueue() } else {
} else { rxBus.send(EventNSClientNewLog("RCV END", "No new PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
rxBus.send(EventNSClientNewLog("RCV END", "No new PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context)
WorkManager.getInstance(context) .enqueueUniqueWork(
.enqueueUniqueWork( NSClientV3Plugin.JOB_NAME,
NSClientV3Plugin.JOB_NAME, ExistingWorkPolicy.APPEND_OR_REPLACE,
ExistingWorkPolicy.APPEND_OR_REPLACE, OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build() )
)
}
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
} }
else { } else {
rxBus.send(EventNSClientNewLog("RCV END", "No PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("RCV END", "No PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
WorkManager.getInstance(context) WorkManager.getInstance(context)
.enqueueUniqueWork( .enqueueUniqueWork(
@ -80,7 +74,12 @@ class LoadProfileStoreWorker(
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build() OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
) )
} }
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
return ret
return Result.success()
} }
} }

View file

@ -5,8 +5,10 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.inject.Inject import javax.inject.Inject
class LoadStatusWorker( class LoadStatusWorker(
@ -14,20 +16,19 @@ class LoadStatusWorker(
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var rxBus: RxBus
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
var ret = Result.success()
runBlocking { try {
try { val status = nsAndroidClient.getStatus()
val status = nsAndroidClient.getStatus() aapsLogger.debug(LTag.NSCLIENT, "STATUS: $status")
aapsLogger.debug("STATUS: $status") } catch (error: Exception) {
} catch (error: Exception) { aapsLogger.error("Error: ", error)
aapsLogger.error("Error: ", error) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
ret = Result.failure(workDataOf("Error" to error.toString())) return Result.failure(workDataOf("Error" to error.localizedMessage))
}
} }
return ret return Result.success()
} }
} }

View file

@ -14,11 +14,11 @@ import info.nightscout.interfaces.sync.NsClient
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.localmodel.treatment.NSTreatment import info.nightscout.sdk.localmodel.treatment.NSTreatment
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.max import kotlin.math.max
@ -36,64 +36,57 @@ class LoadTreatmentsWorker(
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
var ret = Result.success()
val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.TREATMENTS) try {
val lastLoaded = val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.TREATMENTS)
if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge) val lastLoaded =
else max(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge) if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge)
runBlocking { else max(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > lastLoaded) if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > lastLoaded) {
try { val treatments: List<NSTreatment>
val treatments: List<NSTreatment> val response: NSAndroidClient.ReadResponse<List<NSTreatment>>?
val response: NSAndroidClient.ReadResponse<List<NSTreatment>>? if (isFirstLoad) {
val lastLoadedIso = dateUtil.toISOString(lastLoaded)
response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, 500)
} else {
response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, 500)
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = it }
nsClientV3Plugin.storeLastLoadedSrvModified()
}
treatments = response.values
aapsLogger.debug(LTag.NSCLIENT, "TREATMENTS: $treatments")
if (treatments.isNotEmpty()) {
val action = if (isFirstLoad) "RCV-FIRST" else "RCV"
rxBus.send(EventNSClientNewLog(action, "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
// Schedule processing of fetched data and continue of loading
WorkManager.getInstance(context)
.beginUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(response))
.build()
)
// response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload
.then(response.code != 304, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.then(response.code == 304, OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build())
.enqueue()
} else {
// End first load
if (isFirstLoad) { if (isFirstLoad) {
val lastLoadedIso = dateUtil.toISOString(lastLoaded) nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, 500)
}
else {
response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, 500)
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = it }
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
} }
treatments = response.values rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
aapsLogger.debug("TREATMENTS: $treatments") storeDataForDb.storeTreatmentsToDb()
if (treatments.isNotEmpty()) { WorkManager.getInstance(context)
val action = if (isFirstLoad) "RCV-FIRST" else "RCV" .enqueueUniqueWork(
rxBus.send(EventNSClientNewLog(action, "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) NSClientV3Plugin.JOB_NAME,
// Schedule processing of fetched data and continue of loading ExistingWorkPolicy.APPEND_OR_REPLACE,
WorkManager.getInstance(context) OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()
.beginUniqueWork( )
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(response))
.build()
)
// response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload
.then(response.code != 304, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.then(response.code == 304, OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build())
.enqueue()
} else {
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
storeDataForDb.storeTreatmentsToDb()
WorkManager.getInstance(context)
.enqueueUniqueWork(
NSClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()
)
}
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
ret = Result.failure(workDataOf("Error" to error.toString()))
} }
else { } else {
// End first load // End first load
if (isFirstLoad) { if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
@ -108,7 +101,12 @@ class LoadTreatmentsWorker(
OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build() OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()
) )
} }
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
return ret
return Result.success()
} }
} }

View file

@ -12,6 +12,8 @@ import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.nsclientV3.extensions.toFood import info.nightscout.plugins.sync.nsclientV3.extensions.toFood
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.food.NSFood import info.nightscout.sdk.localmodel.food.NSFood
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
@ -30,24 +32,24 @@ class ProcessFoodWorker(
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var storeDataForDb: StoreDataForDb @Inject lateinit var storeDataForDb: StoreDataForDb
@Inject lateinit var rxBus: RxBus
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
val data = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) val data = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data") aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data")
val ret = Result.success() try {
val foods = mutableListOf<Food>() val foods = mutableListOf<Food>()
if (data is JSONArray) {
for (index in 0 until data.length()) {
val jsonFood: JSONObject = data.getJSONObject(index)
if (data is JSONArray) { if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue
for (index in 0 until data.length()) {
val jsonFood: JSONObject = data.getJSONObject(index)
if (JsonHelper.safeGetString(jsonFood, "type") != "food") continue when (JsonHelper.safeGetString(jsonFood, "action")) {
"remove" -> {
when (JsonHelper.safeGetString(jsonFood, "action")) { val delFood = Food(
"remove" -> {
val delFood = Food(
name = "", name = "",
portion = 0.0, portion = 0.0,
carbs = 0, carbs = 0,
@ -61,13 +63,19 @@ class ProcessFoodWorker(
if (food != null) foods += food if (food != null) foods += food
else aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString()) else aapsLogger.error(LTag.DATABASE, "Error parsing food", jsonFood.toString())
} }
}
} }
} else if (data is List<*>) {
for (i in 0 until data.size)
foods += (data[i] as NSFood).toFood()
} }
} else if (data is List<*>) { storeDataForDb.foods.addAll(foods)
for (i in 0 until data.size) } catch (error: Exception) {
foods += (data[i] as NSFood).toFood() aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
storeDataForDb.foods.addAll(foods)
return ret return Result.success()
} }
} }

View file

@ -8,8 +8,6 @@ import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
@ -24,6 +22,7 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toTemporaryBasal
import info.nightscout.plugins.sync.nsclientV3.extensions.toTemporaryTarget import info.nightscout.plugins.sync.nsclientV3.extensions.toTemporaryTarget
import info.nightscout.plugins.sync.nsclientV3.extensions.toTherapyEvent import info.nightscout.plugins.sync.nsclientV3.extensions.toTherapyEvent
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.localmodel.treatment.NSBolus import info.nightscout.sdk.localmodel.treatment.NSBolus
@ -54,8 +53,6 @@ class ProcessTreatmentsWorker(
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var uel: UserEntryLogger
@Inject lateinit var xDripBroadcast: XDripBroadcast
@Inject lateinit var storeDataForDb: StoreDataForDb @Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
@ -63,83 +60,88 @@ class ProcessTreatmentsWorker(
val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as NSAndroidClient.ReadResponse<List<NSTreatment>>? val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as NSAndroidClient.ReadResponse<List<NSTreatment>>?
?: return Result.failure(workDataOf("Error" to "missing input data")) ?: return Result.failure(workDataOf("Error" to "missing input data"))
var latestDateInReceivedData: Long = 0 try {
val ret = Result.success() var latestDateInReceivedData: Long = 0
for (treatment in treatments.values) { for (treatment in treatments.values) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment") aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
val date = treatment.date ?: continue val date = treatment.date ?: continue
if (date > latestDateInReceivedData) latestDateInReceivedData = date if (date > latestDateInReceivedData) latestDateInReceivedData = date
when (treatment) { when (treatment) {
is NSBolus -> is NSBolus ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT) if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT)
storeDataForDb.boluses.add(treatment.toBolus()) storeDataForDb.boluses.add(treatment.toBolus())
is NSCarbs -> is NSCarbs ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_carbs, false) || config.NSCLIENT) if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_carbs, false) || config.NSCLIENT)
storeDataForDb.carbs.add(treatment.toCarbs()) storeDataForDb.carbs.add(treatment.toCarbs())
is NSTemporaryTarget -> is NSTemporaryTarget ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) { if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
if (treatment.duration > 0L) { if (treatment.duration > 0L) {
// not ending event // not ending event
if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL || treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL || treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL || treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl() || treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl()
) { ) {
aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment") aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment")
continue continue
}
}
storeDataForDb.temporaryTargets.add(treatment.toTemporaryTarget())
}
is NSTemporaryBasal ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
storeDataForDb.temporaryBasals.add(treatment.toTemporaryBasal())
is NSEffectiveProfileSwitch ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toEffectiveProfileSwitch(dateUtil)?.let { effectiveProfileSwitch ->
storeDataForDb.effectiveProfileSwitches.add(effectiveProfileSwitch)
} }
} }
storeDataForDb.temporaryTargets.add(treatment.toTemporaryTarget())
}
is NSTemporaryBasal -> is NSProfileSwitch ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
storeDataForDb.temporaryBasals.add(treatment.toTemporaryBasal()) treatment.toProfileSwitch(activePlugin, dateUtil)?.let { profileSwitch ->
storeDataForDb.profileSwitches.add(profileSwitch)
is NSEffectiveProfileSwitch -> }
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toEffectiveProfileSwitch(dateUtil)?.let { effectiveProfileSwitch ->
storeDataForDb.effectiveProfileSwitches.add(effectiveProfileSwitch)
}
}
is NSProfileSwitch ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_switch, false) || config.NSCLIENT) {
treatment.toProfileSwitch(activePlugin, dateUtil)?.let { profileSwitch ->
storeDataForDb.profileSwitches.add(profileSwitch)
}
}
is NSBolusWizard ->
treatment.toBolusCalculatorResult()?.let { bolusCalculatorResult ->
storeDataForDb.bolusCalculatorResults.add(bolusCalculatorResult)
}
is NSTherapyEvent ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
treatment.toTherapyEvent().let { therapyEvent ->
storeDataForDb.therapyEvents.add(therapyEvent)
} }
is NSOfflineEvent -> is NSBolusWizard ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_offline_event, false) && config.isEngineeringMode() || config.NSCLIENT) treatment.toBolusCalculatorResult()?.let { bolusCalculatorResult ->
treatment.toOfflineEvent().let { offlineEvent -> storeDataForDb.bolusCalculatorResults.add(bolusCalculatorResult)
storeDataForDb.offlineEvents.add(offlineEvent)
} }
is NSExtendedBolus -> is NSTherapyEvent ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT) if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_therapy_events, false) || config.NSCLIENT)
treatment.toExtendedBolus().let { extendedBolus -> treatment.toTherapyEvent().let { therapyEvent ->
storeDataForDb.extendedBoluses.add(extendedBolus) storeDataForDb.therapyEvents.add(therapyEvent)
} }
is NSOfflineEvent ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_offline_event, false) && config.isEngineeringMode() || config.NSCLIENT)
treatment.toOfflineEvent().let { offlineEvent ->
storeDataForDb.offlineEvents.add(offlineEvent)
}
is NSExtendedBolus ->
if (config.isEngineeringMode() && sp.getBoolean(R.string.key_ns_receive_tbr_eb, false) || config.NSCLIENT)
treatment.toExtendedBolus().let { extendedBolus ->
storeDataForDb.extendedBoluses.add(extendedBolus)
}
}
} }
} activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData)
// xDripBroadcast.sendTreatments(treatments) // xDripBroadcast.sendTreatments(treatments)
return ret } catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
}
return Result.success()
} }
} }