diff --git a/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt b/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt index f45013aa16..4761fb6dc8 100644 --- a/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt +++ b/core/interfaces/src/main/java/info/nightscout/interfaces/sync/NsClient.kt @@ -16,7 +16,31 @@ interface NsClient : Sync { fun textLog(): Spanned fun clearLog() + enum class Collection { ENTRIES, TREATMENTS} + /** + * NSC v3 does first load of all data + * next loads are using srvModified property for sync + * not used for NSCv1 + * + * @return true if inside first load of NSCv3, true for NSCv1 + */ + fun isFirstLoad(collection: Collection): Boolean = true + + /** + * Update newest loaded timestamp for entries collection (first load or NSCv1) + * Update newest srvModified (sync loads) + * + * @param latestReceived timestamp + * + */ fun updateLatestBgReceivedIfNewer(latestReceived: Long) + /** + * Update newest loaded timestamp for treatments collection (first load or NSCv1) + * Update newest srvModified (sync loads) + * + * @param latestReceived timestamp + * + */ fun updateLatestTreatmentReceivedIfNewer(latestReceived: Long) fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt index cb76bf8351..900344bff1 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidClientImpl.kt @@ -4,7 +4,7 @@ import android.content.Context import info.nightscout.sdk.exceptions.DateHeaderOutOfToleranceException import info.nightscout.sdk.exceptions.InvalidAccessTokenException import info.nightscout.sdk.exceptions.InvalidFormatNightscoutException -import info.nightscout.sdk.exceptions.TodoNightscoutException +import info.nightscout.sdk.exceptions.UnsuccessfullNightscoutException import info.nightscout.sdk.exceptions.UnknownResponseNightscoutException import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.localmodel.Status @@ -101,9 +101,9 @@ class NSAndroidClientImpl( val response = api.lastModified() if (response.isSuccessful) { - return@callWrapper response.body()?.result ?: throw TodoNightscoutException() + return@callWrapper response.body()?.result ?: throw UnsuccessfullNightscoutException() } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } @@ -114,17 +114,19 @@ class NSAndroidClientImpl( if (response.isSuccessful) { return@callWrapper response.body()?.result?.map(RemoteEntry::toSgv).toNotNull() } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } - override suspend fun getSgvsModifiedSince(from: Long): List = callWrapper(dispatcher) { + override suspend fun getSgvsModifiedSince(from: Long, limit: Long): NSAndroidClient.ReadResponse> = callWrapper(dispatcher) { - val response = api.getSgvsModifiedSince(from) + val response = api.getSgvsModifiedSince(from, limit) + val eTagString = response.headers()["ETag"] + val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException() if (response.isSuccessful) { - return@callWrapper response.body()?.result?.map(RemoteEntry::toSgv).toNotNull() + return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } @@ -134,7 +136,17 @@ class NSAndroidClientImpl( if (response.isSuccessful) { return@callWrapper response.body()?.result?.map(RemoteEntry::toSgv).toNotNull() } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() + } + } + + override suspend fun getTreatmentsNewerThan(from: Long, limit: Long): List = callWrapper(dispatcher) { + + val response = api.getTreatmentsNewerThan(from, limit) + if (response.isSuccessful) { + return@callWrapper response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull() + } else { + throw UnsuccessfullNightscoutException() } } @@ -142,11 +154,11 @@ class NSAndroidClientImpl( val response = api.getTreatmentsModifiedSince(from, limit) val eTagString = response.headers()["ETag"] - val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw TodoNightscoutException() + val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() ?: throw UnsuccessfullNightscoutException() if (response.isSuccessful) { return@callWrapper NSAndroidClient.ReadResponse(eTag, response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()) } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } @@ -156,7 +168,7 @@ class NSAndroidClientImpl( if (response.isSuccessful) { return@callWrapper response.body()?.result.toNotNull() } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } @@ -174,7 +186,7 @@ class NSAndroidClientImpl( lastModified = response.body()?.result?.lastModified ) } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } @@ -191,7 +203,7 @@ class NSAndroidClientImpl( lastModified = response.body()?.result?.lastModified ) } else { - throw TodoNightscoutException() // TODO: react to response errors (offline, ...) + throw UnsuccessfullNightscoutException() } } diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidRxClientImpl.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidRxClientImpl.kt index 1d4cb3c02c..18c54fea29 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidRxClientImpl.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/NSAndroidRxClientImpl.kt @@ -9,13 +9,14 @@ import info.nightscout.sdk.remotemodel.LastModified import info.nightscout.sdk.remotemodel.RemoteDeviceStatus import io.reactivex.rxjava3.core.Single import kotlinx.coroutines.rx3.rxSingle +import retrofit2.http.Query class NSAndroidRxClientImpl(private val client: NSAndroidClient) : NSAndroidRxClient { override fun getVersion(): Single = rxSingle { client.getVersion() } override fun getStatus(): Single = rxSingle { client.getStatus() } override fun getLastModified(): Single = rxSingle { client.getLastModified() } - override fun getSgvsModifiedSince(from: Long): Single> = rxSingle { client.getSgvsModifiedSince(from) } + override fun getSgvsModifiedSince(from: Long, limit: Long): Single>> = rxSingle { client.getSgvsModifiedSince(from, limit) } override fun getTreatmentsModifiedSince(from: Long, limit: Long): Single>> = rxSingle { client.getTreatmentsModifiedSince(from, limit) } override fun getDeviceStatusModifiedSince(from: Long): Single> = diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/TodoNightscoutException.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/TodoNightscoutException.kt deleted file mode 100644 index e90a172319..0000000000 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/TodoNightscoutException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package info.nightscout.sdk.exceptions - -class TodoNightscoutException : NightscoutException() diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/UnsuccessfullNightscoutException.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/UnsuccessfullNightscoutException.kt new file mode 100644 index 0000000000..7cea408407 --- /dev/null +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/exceptions/UnsuccessfullNightscoutException.kt @@ -0,0 +1,3 @@ +package info.nightscout.sdk.exceptions + +class UnsuccessfullNightscoutException : NightscoutException() diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidClient.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidClient.kt index d29b959080..86dd1fc23d 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidClient.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidClient.kt @@ -21,8 +21,9 @@ interface NSAndroidClient { suspend fun getLastModified(): LastModified suspend fun getSgvs(): List - suspend fun getSgvsModifiedSince(from: Long): List + suspend fun getSgvsModifiedSince(from: Long, limit: Long): ReadResponse> suspend fun getSgvsNewerThan(from: Long, limit: Long): List + suspend fun getTreatmentsNewerThan(from: Long, limit: Long): List suspend fun getTreatmentsModifiedSince(from: Long, limit: Long): ReadResponse> suspend fun getDeviceStatusModifiedSince(from: Long): List suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidRxClient.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidRxClient.kt index 01b365b6f5..f1e6c2df1e 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidRxClient.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/interfaces/NSAndroidRxClient.kt @@ -12,7 +12,7 @@ interface NSAndroidRxClient { fun getVersion(): Single fun getStatus(): Single fun getLastModified(): Single - fun getSgvsModifiedSince(from: Long): Single> + fun getSgvsModifiedSince(from: Long, limit: Long): Single>> fun getTreatmentsModifiedSince(from: Long, limit: Long): Single>> fun getDeviceStatusModifiedSince(from: Long): Single> } diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/networking/NightscoutRemoteService.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/networking/NightscoutRemoteService.kt index fc52b14891..e1b93860a2 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/networking/NightscoutRemoteService.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/networking/NightscoutRemoteService.kt @@ -45,7 +45,10 @@ internal interface NightscoutRemoteService { suspend fun getSgvsNewerThan(@Query(value = "date\$gt", encoded = true) date: Long, @Query("limit") limit: Long): Response>> @GET("v3/entries/history/{from}") - suspend fun getSgvsModifiedSince(@Path("from") from: Long): Response>> + suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response>> + + @GET("v3/treatments") + suspend fun getTreatmentsNewerThan(@Query(value = "date\$gt", encoded = true) date: Long, @Query("limit") limit: Long): Response>> @GET("v3/treatments/history/{from}") suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long): Response>> diff --git a/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt b/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt index 1f7b3344f4..0256499f2f 100644 --- a/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt +++ b/core/ns-sdk/src/main/java/info/nightscout/sdk/remotemodel/LastModified.kt @@ -15,9 +15,9 @@ data class LastModified( @Serializable data class Collections( - @SerializedName("devicestatus") var devicestatus: Long, // devicestatus collection - @SerializedName("entries") var entries: Long, // entries collection - @SerializedName("profile") var profile: Long, // profile collection - @SerializedName("treatments") var treatments: Long // treatments collection + @SerializedName("devicestatus") var devicestatus: Long = 0, // devicestatus collection + @SerializedName("entries") var entries: Long = 0, // entries collection + @SerializedName("profile") var profile: Long = 0, // profile collection + @SerializedName("treatments") var treatments: Long = 0 // treatments collection ) } diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt index dd1241c8d7..439875dfab 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsShared/StoreDataForDbImpl.kt @@ -54,6 +54,7 @@ import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.pump.VirtualPump import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.ui.UiInteraction +import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.logging.AAPSLogger diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt index 7c98627f2e..df68228f2e 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/NSClientV3Plugin.kt @@ -39,6 +39,7 @@ import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorke import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.bus.RxBus +import info.nightscout.rx.events.EventAppExit import info.nightscout.rx.events.EventChargingState import info.nightscout.rx.events.EventNSClientNewLog import info.nightscout.rx.events.EventNetworkChange @@ -60,7 +61,6 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import javax.inject.Inject import javax.inject.Singleton -import kotlin.math.max @Singleton class NSClientV3Plugin @Inject constructor( @@ -113,22 +113,14 @@ class NSClientV3Plugin @Inject constructor( } internal lateinit var nsAndroidClient: NSAndroidClient -// private lateinit var nsAndroidRxClient: NSAndroidRxClient - val isAllowed get() = nsClientReceiverDelegate.allowed - val blockingReason get() = nsClientReceiverDelegate.blockingReason + private val isAllowed get() = nsClientReceiverDelegate.allowed + private val blockingReason get() = nsClientReceiverDelegate.blockingReason - private val maxAge = T.days(77).msecs() - internal var newestDataOnServer: LastModified? = null // timestamp of last modification for every collection - internal var lastLoadedSrvModified = - LastModified( - LastModified.Collections( - dateUtil.now() - maxAge, - dateUtil.now() - maxAge, - dateUtil.now() - maxAge, - dateUtil.now() - maxAge - ) - ) // timestamp of last fetched data for every collection + val maxAge = T.days(77).msecs() + internal var newestDataOnServer: LastModified? = null // timestamp of last modification for every collection provided by server + internal var lastLoadedSrvModified = LastModified(LastModified.Collections()) // max srvLastModified timestamp of last fetched data for every collection + internal var firstLoadContinueTimestamp = LastModified(LastModified.Collections()) // timestamp of last fetched data for every collection during initial load override fun onStart() { // context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE) @@ -137,16 +129,9 @@ class NSClientV3Plugin @Inject constructor( lastLoadedSrvModified = Json.decodeFromString( sp.getString( R.string.key_ns_client_v3_last_modified, - Json.encodeToString( - LastModified.serializer(), - LastModified(LastModified.Collections(dateUtil.now() - maxAge, dateUtil.now() - maxAge, dateUtil.now() - maxAge, dateUtil.now() - maxAge)) - ) + Json.encodeToString(LastModified.serializer(), LastModified(LastModified.Collections())) ) ) - lastLoadedSrvModified.collections.entries = max(dateUtil.now() - maxAge, lastLoadedSrvModified.collections.entries) - lastLoadedSrvModified.collections.treatments = max(dateUtil.now() - maxAge, lastLoadedSrvModified.collections.treatments) - lastLoadedSrvModified.collections.profile = max(dateUtil.now() - maxAge, lastLoadedSrvModified.collections.profile) - lastLoadedSrvModified.collections.devicestatus = max(dateUtil.now() - maxAge, lastLoadedSrvModified.collections.devicestatus) setClient() @@ -166,10 +151,10 @@ class NSClientV3Plugin @Inject constructor( if (ev.isChanged(rh.gs(R.string.key_ns_client_token)) || ev.isChanged(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_url))) setClient() }, fabricPrivacy::logException) - // disposable += rxBus - // .toObservable(EventAppExit::class.java) - // .observeOn(aapsSchedulers.io) - // .subscribe({ if (nsClientService != null) context.unbindService(mConnection) }, fabricPrivacy::logException) + disposable += rxBus + .toObservable(EventAppExit::class.java) + .observeOn(aapsSchedulers.io) + .subscribe({ WorkManager.getInstance(context).cancelUniqueWork(JOB_NAME) }, fabricPrivacy::logException) disposable += rxBus .toObservable(EventNSClientNewLog::class.java) .observeOn(aapsSchedulers.io) @@ -187,8 +172,8 @@ class NSClientV3Plugin @Inject constructor( .subscribe({ event -> resend(event.reason) }, fabricPrivacy::logException) runLoop = Runnable { - executeLoop() handler.postDelayed(runLoop, REFRESH_INTERVAL) + executeLoop() } handler.postDelayed(runLoop, REFRESH_INTERVAL) executeLoop() @@ -214,7 +199,6 @@ class NSClientV3Plugin @Inject constructor( override val hasWritePermission: Boolean get() = nsAndroidClient.lastStatus?.apiPermissions?.isFull() ?: false override val connected: Boolean get() = nsAndroidClient.lastStatus != null - override fun clearLog() { handler.post { synchronized(listLog) { listLog.clear() } @@ -283,27 +267,23 @@ class NSClientV3Plugin @Inject constructor( // }) } - override fun updateLatestBgReceivedIfNewer(latestReceived: Long) { - if (latestReceived > lastLoadedSrvModified.collections.entries) { - lastLoadedSrvModified.collections.entries = latestReceived - storeLastFetched() + override fun isFirstLoad(collection: NsClient.Collection) = + when (collection) { + NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L + NsClient.Collection.TREATMENTS -> lastLoadedSrvModified.collections.treatments == 0L } + + override fun updateLatestBgReceivedIfNewer(latestReceived: Long) { + if (isFirstLoad(NsClient.Collection.ENTRIES)) firstLoadContinueTimestamp.collections.entries = latestReceived } override fun updateLatestTreatmentReceivedIfNewer(latestReceived: Long) { - lastLoadedSrvModified.collections.treatments = latestReceived - storeLastFetched() + if (isFirstLoad(NsClient.Collection.TREATMENTS)) firstLoadContinueTimestamp.collections.treatments = latestReceived } override fun resetToFullSync() { - lastLoadedSrvModified = LastModified( - LastModified.Collections( - dateUtil.now() - maxAge, - dateUtil.now() - maxAge, - dateUtil.now() - maxAge, - dateUtil.now() - maxAge - ) - ) + firstLoadContinueTimestamp = LastModified(LastModified.Collections()) + lastLoadedSrvModified = LastModified(LastModified.Collections()) storeLastFetched() } @@ -316,9 +296,10 @@ class NSClientV3Plugin @Inject constructor( } enum class Operation { CREATE, UPDATE } + private val gson: Gson = GsonBuilder().create() private fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) { - val call = when(operation) { + val call = when (operation) { Operation.CREATE -> nsAndroidClient::createTreatment Operation.UPDATE -> nsAndroidClient::updateTreatment } @@ -343,11 +324,11 @@ class NSClientV3Plugin @Inject constructor( val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else "" rxBus.send( EventNSClientNewLog( - when(operation) { + when (operation) { Operation.CREATE -> "ADD $collection" Operation.UPDATE -> "UPDATE $collection" }, - when(operation) { + when (operation) { Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} ${gson.toJson(data)} $progress" Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id ${gson.toJson(data)} $progress" } @@ -382,7 +363,8 @@ class NSClientV3Plugin @Inject constructor( } } } - private fun storeLastFetched() { + + fun storeLastFetched() { sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified)) } @@ -391,20 +373,19 @@ class NSClientV3Plugin @Inject constructor( } fun scheduleNewExecution() { - val toTime = lastLoadedSrvModified.collections.entries + T.mins(6).plus(T.secs(0)).msecs() - if (toTime > dateUtil.now()) { - handler.postDelayed({ executeLoop() }, toTime - dateUtil.now()) - rxBus.send(EventNSClientNewLog("NEXT", dateUtil.dateAndTimeAndSecondsString(toTime))) - } + var toTime = lastLoadedSrvModified.collections.entries + T.mins(6).plus(T.secs(0)).msecs() + if (toTime < dateUtil.now()) toTime = dateUtil.now() + T.mins(1).plus(T.secs(0)).msecs() + handler.postDelayed({ executeLoop() }, toTime - dateUtil.now()) + rxBus.send(EventNSClientNewLog("NEXT", dateUtil.dateAndTimeAndSecondsString(toTime))) } private fun executeLoop() { if (sp.getBoolean(R.string.key_ns_client_paused, false)) { - rxBus.send(EventNSClientNewLog("NSCLIENT", "paused")) + rxBus.send(EventNSClientNewLog("RUN", "paused")) return } if (!isAllowed) { - rxBus.send(EventNSClientNewLog("NSCLIENT", blockingReason)) + rxBus.send(EventNSClientNewLog("RUN", blockingReason)) return } if (workIsRunning(arrayOf(JOB_NAME))) diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt index f381913e58..47dacb6e81 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadBgWorker.kt @@ -8,15 +8,19 @@ import androidx.work.WorkerParameters import androidx.work.workDataOf import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.worker.LoggingWorker +import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog +import info.nightscout.sdk.interfaces.NSAndroidClient +import info.nightscout.sdk.localmodel.entry.NSSgvV3 import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.utils.DateUtil import kotlinx.coroutines.runBlocking import javax.inject.Inject +import kotlin.math.max class LoadBgWorker( context: Context, params: WorkerParameters @@ -37,20 +41,26 @@ class LoadBgWorker( override fun doWorkAndLog(): Result { var ret = Result.success() - + val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.ENTRIES) + val lastLoaded = + if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) + else max(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) runBlocking { - if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > nsClientV3Plugin.lastLoadedSrvModified.collections.entries) + if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) try { - //val sgvs = nsClientV3Plugin.nsAndroidClient.getSgvsModifiedSince(nsClientV3Plugin.lastFetched.collections.entries) - val sgvs = nsClientV3Plugin.nsAndroidClient.getSgvsNewerThan(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, 500) + val sgvs: List + val response: NSAndroidClient.ReadResponse>? + if (isFirstLoad) sgvs = nsClientV3Plugin.nsAndroidClient.getSgvsNewerThan(lastLoaded, 500) + else { + response = nsClientV3Plugin.nsAndroidClient.getSgvsModifiedSince(lastLoaded, 500) + sgvs = response.values + nsClientV3Plugin.lastLoadedSrvModified.collections.entries = response.lastServerModified + nsClientV3Plugin.storeLastFetched() + } aapsLogger.debug("SGVS: $sgvs") if (sgvs.isNotEmpty()) { - rxBus.send( - EventNSClientNewLog( - "RCV", - "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.entries)}" - ) - ) + val action = if (isFirstLoad) "RCV-FIRST" else "RCV" + rxBus.send(EventNSClientNewLog(action, "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) // Objective0 sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true) // Schedule processing of fetched data and continue of loading @@ -60,7 +70,13 @@ class LoadBgWorker( OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(sgvs)).build() ).then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build()).enqueue() } else { - rxBus.send(EventNSClientNewLog("END", "No SGVs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.entries)}")) + // End first load + if (isFirstLoad) { + nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded + nsClientV3Plugin.storeLastFetched() + } + rxBus.send(EventNSClientNewLog("RCV END", "No SGVs from ${dateUtil + .dateAndTimeAndSecondsString(lastLoaded)}")) WorkManager.getInstance(context) .beginUniqueWork( NSClientV3Plugin.JOB_NAME, @@ -75,7 +91,13 @@ class LoadBgWorker( ret = Result.failure(workDataOf("Error" to error.toString())) } else { - rxBus.send(EventNSClientNewLog("END", "No new SGVs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.entries)}")) + // End first load + if (isFirstLoad) { + nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded + nsClientV3Plugin.storeLastFetched() + } + rxBus.send(EventNSClientNewLog("RCV END", "No new SGVs from ${dateUtil + .dateAndTimeAndSecondsString(lastLoaded)}")) nsClientV3Plugin.scheduleNewExecution() // Idea is to run after 5 min after last BG WorkManager.getInstance(context) .beginUniqueWork( diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt index 80d2cc4661..ca910880b1 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadDeviceStatusWorker.kt @@ -40,8 +40,9 @@ class LoadDeviceStatusWorker( if (deviceStatuses.isNotEmpty()) { rxBus.send(EventNSClientNewLog("RCV", "${deviceStatuses.size} DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) nsDeviceStatusHandler.handleNewData(deviceStatuses.toTypedArray()) + rxBus.send(EventNSClientNewLog("DONE DS", "")) } else { - rxBus.send(EventNSClientNewLog("END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) + rxBus.send(EventNSClientNewLog("RCV END", "No DSs from ${dateUtil.dateAndTimeAndSecondsString(from)}")) } WorkManager.getInstance(context) .enqueueUniqueWork( diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt index 39dd4663de..c1d7e557c4 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/LoadTreatmentsWorker.kt @@ -9,12 +9,16 @@ import androidx.work.workDataOf import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.interfaces.nsclient.StoreDataForDb +import info.nightscout.interfaces.sync.NsClient import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.rx.bus.RxBus import info.nightscout.rx.events.EventNSClientNewLog +import info.nightscout.sdk.interfaces.NSAndroidClient +import info.nightscout.sdk.localmodel.treatment.NSTreatment import info.nightscout.shared.utils.DateUtil import kotlinx.coroutines.runBlocking import javax.inject.Inject +import kotlin.math.max class LoadTreatmentsWorker( context: Context, @@ -31,34 +35,47 @@ class LoadTreatmentsWorker( override fun doWorkAndLog(): Result { var ret = Result.success() + val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.TREATMENTS) + val lastLoaded = + if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge) + else max(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge) runBlocking { - if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > nsClientV3Plugin.lastLoadedSrvModified.collections.treatments) + if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > lastLoaded) try { - val treatments = nsClientV3Plugin.nsAndroidClient.getTreatmentsModifiedSince(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments, 500) + val treatments: List + val response: NSAndroidClient.ReadResponse>? + if (isFirstLoad) { + treatments = nsClientV3Plugin.nsAndroidClient.getTreatmentsNewerThan(lastLoaded, 500) + response = NSAndroidClient.ReadResponse(0, treatments) + } + else { + response = nsClientV3Plugin.nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, 500) + treatments = response.values + nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = response.lastServerModified + nsClientV3Plugin.storeLastFetched() + } aapsLogger.debug("TREATMENTS: $treatments") - if (treatments.values.isNotEmpty()) { - rxBus.send( - EventNSClientNewLog( - "RCV", - "${treatments.values.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.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(treatments)) + .setInputData(dataWorkerStorage.storeInputData(response)) .build() ).then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()) .enqueue() } else { - rxBus.send( - EventNSClientNewLog( - "END", "No TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments)}" - ) - ) + // End first load + if (isFirstLoad) { + nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded + nsClientV3Plugin.storeLastFetched() + } + rxBus.send(EventNSClientNewLog("RCV END", "No TRs from ${dateUtil + .dateAndTimeAndSecondsString(lastLoaded)}")) storeDataForDb.storeTreatmentsToDb() WorkManager.getInstance(context) .enqueueUniqueWork( @@ -72,7 +89,13 @@ class LoadTreatmentsWorker( ret = Result.failure(workDataOf("Error" to error.toString())) } else { - rxBus.send(EventNSClientNewLog("END", "No new TRs from ${dateUtil.dateAndTimeAndSecondsString(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments)}")) + // End first load + if (isFirstLoad) { + nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded + nsClientV3Plugin.storeLastFetched() + } + rxBus.send(EventNSClientNewLog("RCV END", "No new TRs from ${dateUtil + .dateAndTimeAndSecondsString(lastLoaded)}")) storeDataForDb.storeTreatmentsToDb() WorkManager.getInstance(context) .enqueueUniqueWork( diff --git a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt index 6859805e5d..150b0cf1bf 100644 --- a/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt +++ b/plugins/sync/src/main/java/info/nightscout/plugins/sync/nsclientV3/workers/ProcessTreatmentsWorker.kt @@ -62,12 +62,12 @@ class ProcessTreatmentsWorker( val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as NSAndroidClient.ReadResponse>? ?: return Result.failure(workDataOf("Error" to "missing input data")) + var latestDateInReceivedData: Long = 0 val ret = Result.success() for (treatment in treatments.values) { aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment") + if (treatment.date > latestDateInReceivedData) latestDateInReceivedData = treatment.date - //Find latest date in treatment - val mills = treatment.date when (treatment) { is NSBolus -> if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT) @@ -136,7 +136,7 @@ class ProcessTreatmentsWorker( } } } - activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(treatments.lastServerModified) + activePlugin.activeNsClient?.updateLatestTreatmentReceivedIfNewer(latestDateInReceivedData) // xDripBroadcast.sendTreatments(treatments) return ret } diff --git a/plugins/sync/src/main/res/xml/pref_ns_client.xml b/plugins/sync/src/main/res/xml/pref_ns_client.xml index 5eca05b5ec..9f2739ee68 100644 --- a/plugins/sync/src/main/res/xml/pref_ns_client.xml +++ b/plugins/sync/src/main/res/xml/pref_ns_client.xml @@ -151,7 +151,7 @@ android:title="@string/connection_settings_title">