NSCv3: optimize, use coroutines istead of recursion

This commit is contained in:
Milos Kozak 2023-02-10 22:00:26 +01:00
parent 40e14ba0e3
commit af4b7829f9
72 changed files with 2094 additions and 1848 deletions

View file

@ -4,6 +4,8 @@
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" /> <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" /> <option name="BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES" value="1" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>

View file

@ -15,7 +15,6 @@ class EventNSClientNewLog(val action: String, val logText: String?) : Event() {
stringBuilder.append(action) stringBuilder.append(action)
stringBuilder.append("</b> ") stringBuilder.append("</b> ")
stringBuilder.append(logText) stringBuilder.append(logText)
stringBuilder.append("<br>")
return stringBuilder return stringBuilder
} }
} }

View file

@ -1,12 +1,9 @@
package info.nightscout.androidaps.workflow package info.nightscout.androidaps.workflow
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.profile.ProfilePlugin
import info.nightscout.source.NSClientSourcePlugin
import javax.inject.Inject import javax.inject.Inject
class WorkerClassesImpl @Inject constructor(): WorkerClasses{ class WorkerClassesImpl @Inject constructor() : WorkerClasses {
override val nsClientSourceWorker = NSClientSourcePlugin.NSClientSourceWorker::class.java //override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
override val nsProfileWorker = ProfilePlugin.NSProfileWorker::class.java
} }

View file

@ -47,4 +47,5 @@ interface StoreDataForDb {
fun storeGlucoseValuesToDb() fun storeGlucoseValuesToDb()
fun storeFoodsToDb() fun storeFoodsToDb()
fun scheduleNsIdUpdate() fun scheduleNsIdUpdate()
fun updateNsIds()
} }

View file

@ -36,5 +36,6 @@ interface ProfileSource {
var currentProfileIndex: Int var currentProfileIndex: Int
fun currentProfile(): SingleProfile? fun currentProfile(): SingleProfile?
fun storeSettings(activity: FragmentActivity? = null, emptyCreated: Boolean = false) fun storeSettings(activity: FragmentActivity? = null, emptyCreated: Boolean = false)
fun loadFromStore(store: ProfileStore)
} }

View file

@ -17,70 +17,30 @@ import org.json.JSONObject
interface DataSyncSelector { interface DataSyncSelector {
interface DataPair { interface DataPair {
val value: Any val value: Any
val id: Long val id: Long
} }
data class PairTemporaryTarget(override val value: TemporaryTarget, override val id: Long): DataPair
data class PairGlucoseValue(override val value: GlucoseValue, override val id: Long): DataPair data class PairTemporaryTarget(override val value: TemporaryTarget, override val id: Long) : DataPair
data class PairTherapyEvent(override val value: TherapyEvent, override val id: Long): DataPair data class PairGlucoseValue(override val value: GlucoseValue, override val id: Long) : DataPair
data class PairFood(override val value: Food, override val id: Long): DataPair data class PairTherapyEvent(override val value: TherapyEvent, override val id: Long) : DataPair
data class PairBolus(override val value: Bolus, override val id: Long): DataPair data class PairFood(override val value: Food, override val id: Long) : DataPair
data class PairCarbs(override val value: Carbs, override val id: Long): DataPair data class PairBolus(override val value: Bolus, override val id: Long) : DataPair
data class PairBolusCalculatorResult(override val value: BolusCalculatorResult, override val id: Long): DataPair data class PairCarbs(override val value: Carbs, override val id: Long) : DataPair
data class PairTemporaryBasal(override val value: TemporaryBasal, override val id: Long): DataPair data class PairBolusCalculatorResult(override val value: BolusCalculatorResult, override val id: Long) : DataPair
data class PairExtendedBolus(override val value: ExtendedBolus, override val id: Long): DataPair data class PairTemporaryBasal(override val value: TemporaryBasal, override val id: Long) : DataPair
data class PairProfileSwitch(override val value: ProfileSwitch, override val id: Long): DataPair data class PairExtendedBolus(override val value: ExtendedBolus, override val id: Long) : DataPair
data class PairEffectiveProfileSwitch(override val value: EffectiveProfileSwitch, override val id: Long): DataPair data class PairProfileSwitch(override val value: ProfileSwitch, override val id: Long) : DataPair
data class PairOfflineEvent(override val value: OfflineEvent, override val id: Long): DataPair data class PairEffectiveProfileSwitch(override val value: EffectiveProfileSwitch, override val id: Long) : DataPair
data class PairProfileStore(override val value: JSONObject, override val id: Long): DataPair data class PairOfflineEvent(override val value: OfflineEvent, override val id: Long) : DataPair
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long): DataPair data class PairProfileStore(override val value: JSONObject, override val id: Long) : DataPair
data class PairDeviceStatus(override val value: DeviceStatus, override val id: Long) : DataPair
fun queueSize(): Long fun queueSize(): Long
fun doUpload()
fun resetToNextFullSync() fun resetToNextFullSync()
fun confirmLastBolusIdIfGreater(lastSynced: Long) suspend fun doUpload()
fun processChangedBoluses()
fun confirmLastCarbsIdIfGreater(lastSynced: Long)
fun processChangedCarbs()
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long)
fun processChangedBolusCalculatorResults()
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long)
fun processChangedTempTargets()
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long)
fun processChangedGlucoseValues()
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long)
fun processChangedTherapyEvents()
fun confirmLastFoodIdIfGreater(lastSynced: Long)
fun processChangedFoods()
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long)
fun processChangedDeviceStatuses()
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long)
fun processChangedTemporaryBasals()
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long)
fun processChangedExtendedBoluses()
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long)
fun processChangedProfileSwitches()
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long)
fun processChangedEffectiveProfileSwitches()
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long)
fun processChangedOfflineEvents()
fun confirmLastProfileStore(lastSynced: Long)
fun processChangedProfileStore()
} }

View file

@ -0,0 +1,46 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorV1 : DataSyncSelector {
fun confirmLastBolusIdIfGreater(lastSynced: Long)
suspend fun processChangedBoluses()
fun confirmLastCarbsIdIfGreater(lastSynced: Long)
suspend fun processChangedCarbs()
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long)
suspend fun processChangedBolusCalculatorResults()
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long)
suspend fun processChangedTempTargets()
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long)
suspend fun processChangedGlucoseValues()
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long)
suspend fun processChangedTherapyEvents()
fun confirmLastFoodIdIfGreater(lastSynced: Long)
suspend fun processChangedFoods()
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long)
suspend fun processChangedDeviceStatuses()
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long)
suspend fun processChangedTemporaryBasals()
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long)
suspend fun processChangedExtendedBoluses()
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long)
suspend fun processChangedProfileSwitches()
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long)
suspend fun processChangedEffectiveProfileSwitches()
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long)
suspend fun processChangedOfflineEvents()
fun confirmLastProfileStore(lastSynced: Long)
suspend fun processChangedProfileStore()
}

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorV3 : DataSyncSelector

View file

@ -0,0 +1,3 @@
package info.nightscout.interfaces.sync
interface DataSyncSelectorXdrip : DataSyncSelector

View file

@ -1,7 +1,7 @@
package info.nightscout.interfaces.sync package info.nightscout.interfaces.sync
import android.text.Spanned
import info.nightscout.interfaces.nsclient.NSAlarm import info.nightscout.interfaces.nsclient.NSAlarm
import info.nightscout.rx.events.EventNSClientNewLog
/** /**
* Plugin providing communication with Nightscout server * Plugin providing communication with Nightscout server
@ -24,14 +24,14 @@ interface NsClient : Sync {
fun resend(reason: String) fun resend(reason: String)
/** /**
* @return List last of messages for fragment in HTML format * List of log messages for fragment
*/ */
fun textLog(): Spanned val listLog: MutableList<EventNSClientNewLog>
/** /**
* Clear list of stored messages displayed in fragment * Used data sync selector
*/ */
fun clearLog() val dataSyncSelector: DataSyncSelector
/** /**
* Version of NS server * Version of NS server
@ -89,8 +89,9 @@ interface NsClient : Sync {
* @param collection target ns collection * @param collection target ns collection
* @param dataPair data to upload (data.first) and id of changed record (data.second) * @param dataPair data to upload (data.first) and id of changed record (data.second)
* @param progress progress of sync in format "number/number". Only for display in fragment * @param progress progress of sync in format "number/number". Only for display in fragment
* @return true for successful upload
*/ */
fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean
/** /**
* Upload updated record to NS * Upload updated record to NS
@ -98,6 +99,7 @@ interface NsClient : Sync {
* @param collection target ns collection * @param collection target ns collection
* @param dataPair data to upload (data.first) and id of changed record (data.second) * @param dataPair data to upload (data.first) and id of changed record (data.second)
* @param progress progress of sync in format "number/number". Only for display in fragment * @param progress progress of sync in format "number/number". Only for display in fragment
* @return true for successful upload
*/ */
fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) suspend fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean
} }

View file

@ -1,8 +1,5 @@
package info.nightscout.interfaces.workflow package info.nightscout.interfaces.workflow
import androidx.work.ListenableWorker
interface WorkerClasses { interface WorkerClasses {
val nsClientSourceWorker: Class<out ListenableWorker> // val nsProfileWorker: Class<out ListenableWorker>
val nsProfileWorker: Class<out ListenableWorker>
} }

View file

@ -119,7 +119,11 @@ class NSAndroidClientImpl(
val response = api.getSgvs() val response = api.getSgvs()
if (response.isSuccessful) { if (response.isSuccessful) {
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} else if (response.code() in 400..499) } else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else else
@ -132,7 +136,11 @@ class NSAndroidClientImpl(
if (response.isSuccessful) { if (response.isSuccessful) {
val eTagString = response.headers()["ETag"] val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong() val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong()
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = eTag,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} else if (response.code() in 400..499) } else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else else
@ -143,39 +151,37 @@ class NSAndroidClientImpl(
val response = api.getSgvsNewerThan(from, limit) val response = api.getSgvsNewerThan(from, limit)
if (response.isSuccessful) { if (response.isSuccessful) {
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()) return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteEntry::toSgv).toNotNull()
)
} else if (response.code() in 400..499) } else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else else
throw UnsuccessfullNightscoutException() throw UnsuccessfullNightscoutException()
} }
override suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) { override suspend fun createSgv(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) {
val remoteEntry = nsSgvV3.toRemoteEntry() val remoteEntry = nsSgvV3.toRemoteEntry()
remoteEntry.app = "AAPS" remoteEntry.app = "AAPS"
val response = api.createEntry(remoteEntry) val response = api.createEntry(remoteEntry)
val responseBody = response.body() val responseBody = response.body()
val errorResponse = response.errorBody()?.string() val errorResponse = response.errorBody()?.string()
if (response.code() == 200) { if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = responseBody?.identifier,
isDeduplication = true isDeduplication = responseBody?.isDeduplication ?: false,
) deduplicatedIdentifier = responseBody?.deduplicatedIdentifier,
} else if (response.code() == 201) { lastModified = responseBody?.lastModified
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = responseBody?.result?.identifier,
isDeduplication = responseBody?.result?.isDeduplication ?: false,
deduplicatedIdentifier = responseBody?.result?.deduplicatedIdentifier,
lastModified = responseBody?.result?.lastModified
) )
} else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsSgvV3.utcOffset != 0L) { } else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsSgvV3.utcOffset != 0L) {
// Record can be originally uploaded without utcOffset // Record can be originally uploaded without utcOffset
// because utcOffset is mandatory and cannot be change, try 0 // because utcOffset is mandatory and cannot be change, try 0
nsSgvV3.utcOffset = 0 nsSgvV3.utcOffset = 0
return@callWrapper createSvg(nsSgvV3) return@callWrapper createSgv(nsSgvV3)
} else if (response.code() == 400 && errorResponse?.contains("cannot be modified by the client") == true) { } else if (response.code() == 400 && errorResponse?.contains("cannot be modified by the client") == true) {
// there is different field to field in AAPS // there is different field to field in AAPS
// not possible to upload // not possible to upload
@ -234,7 +240,11 @@ class NSAndroidClientImpl(
val response = api.getTreatmentsNewerThan(createdAt, limit) val response = api.getTreatmentsNewerThan(createdAt, limit)
if (response.isSuccessful) { if (response.isSuccessful) {
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()) return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteTreatment::toTreatment).toNotNull()
)
} else if (response.code() in 400..499) } else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else else
@ -273,22 +283,13 @@ class NSAndroidClientImpl(
nsDeviceStatus.app = "AAPS" nsDeviceStatus.app = "AAPS"
val response = api.createDeviceStatus(nsDeviceStatus.toRemoteDeviceStatus()) val response = api.createDeviceStatus(nsDeviceStatus.toRemoteDeviceStatus())
if (response.isSuccessful) { if (response.isSuccessful) {
if (response.code() == 200) { if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = response.body()?.identifier,
isDeduplication = true, isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = null, deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = null lastModified = response.body()?.lastModified
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier
?: throw UnknownResponseNightscoutException(),
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
) )
} else throw UnknownResponseNightscoutException() } else throw UnknownResponseNightscoutException()
} else if (response.code() in 400..499) { } else if (response.code() in 400..499) {
@ -307,19 +308,13 @@ class NSAndroidClientImpl(
remoteTreatment.app = "AAPS" remoteTreatment.app = "AAPS"
val response = api.createTreatment(remoteTreatment) val response = api.createTreatment(remoteTreatment)
val errorResponse = response.errorBody()?.string() val errorResponse = response.errorBody()?.string()
if (response.code() == 200) { if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = response.body()?.identifier,
isDeduplication = true isDeduplication = response.body()?.isDeduplication ?: false,
) deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
} else if (response.code() == 201) { lastModified = response.body()?.lastModified
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
) )
} else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsTreatment.utcOffset != 0L) { } else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsTreatment.utcOffset != 0L) {
// Record can be originally uploaded without utcOffset // Record can be originally uploaded without utcOffset
@ -384,7 +379,11 @@ class NSAndroidClientImpl(
val response = api.getFoods(limit) val response = api.getFoods(limit)
if (response.isSuccessful) { if (response.isSuccessful) {
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = 0, values = response.body()?.result?.map(RemoteFood::toNSFood).toNotNull()) return@callWrapper NSAndroidClient.ReadResponse(
code = response.raw().networkResponse?.code ?: response.code(),
lastServerModified = 0,
values = response.body()?.result?.map(RemoteFood::toNSFood).toNotNull()
)
} else if (response.code() in 400..499) } else if (response.code() in 400..499)
throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message()) throw InvalidParameterNightscoutException(response.errorBody()?.string() ?: response.message())
else else
@ -410,21 +409,13 @@ class NSAndroidClientImpl(
remoteFood.app = "AAPS" remoteFood.app = "AAPS"
val response = api.createFood(remoteFood) val response = api.createFood(remoteFood)
if (response.isSuccessful) { if (response.isSuccessful) {
if (response.code() == 200) { if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = response.body()?.identifier,
isDeduplication = true, isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = null, deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = null lastModified = response.body()?.lastModified
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
) )
} else throw UnsuccessfullNightscoutException() } else throw UnsuccessfullNightscoutException()
} else if (response.code() in 400..499) { } else if (response.code() in 400..499) {
@ -474,21 +465,13 @@ class NSAndroidClientImpl(
remoteProfileStore.put("app", "AAPS") remoteProfileStore.put("app", "AAPS")
val response = api.createProfile(JsonParser.parseString(remoteProfileStore.toString()).asJsonObject) val response = api.createProfile(JsonParser.parseString(remoteProfileStore.toString()).asJsonObject)
if (response.isSuccessful) { if (response.isSuccessful) {
if (response.code() == 200) { if (response.code() == 200 || response.code() == 201) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = response.body()?.identifier,
isDeduplication = true, isDeduplication = response.body()?.isDeduplication,
deduplicatedIdentifier = null, deduplicatedIdentifier = response.body()?.deduplicatedIdentifier,
lastModified = null lastModified = response.body()?.lastModified
)
} else if (response.code() == 201) {
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = response.body()?.result?.identifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
lastModified = response.body()?.result?.lastModified
) )
} else throw UnsuccessfullNightscoutException() } else throw UnsuccessfullNightscoutException()
} else if (response.code() in 400..499) { } else if (response.code() in 400..499) {
@ -514,7 +497,6 @@ class NSAndroidClientImpl(
throw UnsuccessfullNightscoutException() throw UnsuccessfullNightscoutException()
} }
override suspend fun getProfileModifiedSince(from: Long): NSAndroidClient.ReadResponse<List<JSONObject>> = callWrapper(dispatcher) { override suspend fun getProfileModifiedSince(from: Long): NSAndroidClient.ReadResponse<List<JSONObject>> = callWrapper(dispatcher) {
val response = api.getProfileModifiedSince(from) val response = api.getProfileModifiedSince(from)
@ -528,7 +510,6 @@ class NSAndroidClientImpl(
throw UnsuccessfullNightscoutException() throw UnsuccessfullNightscoutException()
} }
private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T = private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T =
withContext(dispatcher) { withContext(dispatcher) {
retry( retry(

View file

@ -25,7 +25,7 @@ interface NSAndroidClient {
suspend fun getSgvs(): ReadResponse<List<NSSgvV3>> suspend fun getSgvs(): ReadResponse<List<NSSgvV3>>
suspend fun getSgvsModifiedSince(from: Long, limit: Int): ReadResponse<List<NSSgvV3>> suspend fun getSgvsModifiedSince(from: Long, limit: Int): ReadResponse<List<NSSgvV3>>
suspend fun getSgvsNewerThan(from: Long, limit: Int): ReadResponse<List<NSSgvV3>> suspend fun getSgvsNewerThan(from: Long, limit: Int): ReadResponse<List<NSSgvV3>>
suspend fun createSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse suspend fun createSgv(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse
suspend fun getTreatmentsNewerThan(createdAt: String, limit: Int): ReadResponse<List<NSTreatment>> suspend fun getTreatmentsNewerThan(createdAt: String, limit: Int): ReadResponse<List<NSTreatment>>

View file

@ -48,7 +48,7 @@ internal interface NightscoutRemoteService {
suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteEntry>>> suspend fun getSgvsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteEntry>>>
@POST("v3/entries") @POST("v3/entries")
suspend fun createEntry(@Body remoteEntry: RemoteEntry): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createEntry(@Body remoteEntry: RemoteEntry): Response<RemoteCreateUpdateResponse>
@PATCH("v3/entries/{identifier}") @PATCH("v3/entries/{identifier}")
suspend fun updateEntry(@Body remoteEntry: RemoteEntry, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun updateEntry(@Body remoteEntry: RemoteEntry, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
@ -63,16 +63,16 @@ internal interface NightscoutRemoteService {
suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteTreatment>>> suspend fun getTreatmentsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteTreatment>>>
@POST("v3/treatments") @POST("v3/treatments")
suspend fun createTreatment(@Body remoteTreatment: RemoteTreatment): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createTreatment(@Body remoteTreatment: RemoteTreatment): Response<RemoteCreateUpdateResponse>
@PATCH("v3/treatments/{identifier}") @PATCH("v3/treatments/{identifier}")
suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun updateTreatment(@Body remoteTreatment: RemoteTreatment, @Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@DELETE("v3/treatments/{identifier}") @DELETE("v3/treatments/{identifier}")
suspend fun deleteTreatment(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun deleteTreatment(@Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@POST("v3/devicestatus") @POST("v3/devicestatus")
suspend fun createDeviceStatus(@Body remoteDeviceStatus: RemoteDeviceStatus): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createDeviceStatus(@Body remoteDeviceStatus: RemoteDeviceStatus): Response<RemoteCreateUpdateResponse>
@GET("v3/devicestatus/history/{from}") @GET("v3/devicestatus/history/{from}")
suspend fun getDeviceStatusModifiedSince(@Path("from") from: Long): Response<NSResponse<List<RemoteDeviceStatus>>> suspend fun getDeviceStatusModifiedSince(@Path("from") from: Long): Response<NSResponse<List<RemoteDeviceStatus>>>
@ -85,13 +85,13 @@ internal interface NightscoutRemoteService {
suspend fun getFoodsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteFood>>> suspend fun getFoodsModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int): Response<NSResponse<List<RemoteFood>>>
*/ */
@POST("v3/food") @POST("v3/food")
suspend fun createFood(@Body remoteFood: RemoteFood): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createFood(@Body remoteFood: RemoteFood): Response<RemoteCreateUpdateResponse>
@PATCH("v3/food") @PATCH("v3/food")
suspend fun updateFood(@Body remoteFood: RemoteFood, @Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun updateFood(@Body remoteFood: RemoteFood, @Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@DELETE("v3/food") @DELETE("v3/food")
suspend fun deleteFood(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun deleteFood(@Path("identifier") identifier: String): Response<RemoteCreateUpdateResponse>
@GET("v3/profile/history/{from}") @GET("v3/profile/history/{from}")
suspend fun getProfileModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int = 10): Response<NSResponse<List<JSONObject>>> suspend fun getProfileModifiedSince(@Path("from") from: Long, @Query("limit") limit: Int = 10): Response<NSResponse<List<JSONObject>>>
@ -100,8 +100,7 @@ internal interface NightscoutRemoteService {
@GET("v3/profile?sort\$desc=date&limit=1") @GET("v3/profile?sort\$desc=date&limit=1")
suspend fun getLastProfile(): Response<NSResponse<List<JSONObject>>> suspend fun getLastProfile(): Response<NSResponse<List<JSONObject>>>
@POST("v3/profile") @POST("v3/profile")
suspend fun createProfile(@Body profile: JsonObject): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createProfile(@Body profile: JsonObject): Response<RemoteCreateUpdateResponse>
} }

View file

@ -39,6 +39,28 @@ object OKDialog {
.setCanceledOnTouchOutside(false) .setCanceledOnTouchOutside(false)
} }
@SuppressLint("InflateParams")
fun show(context: Context, title: String, message: Spanned, runnable: Runnable? = null) {
var okClicked = false
var notEmptyTitle = title
if (notEmptyTitle.isEmpty()) notEmptyTitle = context.getString(R.string.message)
MaterialAlertDialogBuilder(context, R.style.DialogTheme)
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, notEmptyTitle))
.setMessage(message)
.setPositiveButton(context.getString(R.string.ok)) { dialog: DialogInterface, _: Int ->
if (okClicked) return@setPositiveButton
else {
okClicked = true
dialog.dismiss()
SystemClock.sleep(100)
runOnUiThread(runnable)
}
}
.show()
.setCanceledOnTouchOutside(false)
}
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
fun show(activity: FragmentActivity, title: String, message: Spanned, runnable: Runnable? = null) { fun show(activity: FragmentActivity, title: String, message: Spanned, runnable: Runnable? = null) {
var okClicked = false var okClicked = false

View file

@ -620,4 +620,9 @@
<item quantity="other">%1$d minutes</item> <item quantity="other">%1$d minutes</item>
</plurals> </plurals>
<!-- Maintenance-->
<string name="cleanup_db_confirm">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.</string>
<string name="cleanup_db_confirm_sync">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.\nDoing it will speedup full synchronization dramatically.</string>
<string name="cleared_entries">Cleared entries</string>
</resources> </resources>

View file

@ -150,10 +150,8 @@ import kotlin.math.roundToInt
database.glucoseValueDao.getModifiedFrom(lastId) database.glucoseValueDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getLastGlucoseValueIdWrapped(): Single<ValueWrapper<Long>> = fun getLastGlucoseValueId(): Long? =
database.glucoseValueDao.getLastId() database.glucoseValueDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
fun getLastGlucoseValueWrapped(): Single<ValueWrapper<GlucoseValue>> = fun getLastGlucoseValueWrapped(): Single<ValueWrapper<GlucoseValue>> =
database.glucoseValueDao.getLast() database.glucoseValueDao.getLast()
@ -233,10 +231,8 @@ import kotlin.math.roundToInt
fun deleteAllTempTargetEntries() = fun deleteAllTempTargetEntries() =
database.temporaryTargetDao.deleteAllEntries() database.temporaryTargetDao.deleteAllEntries()
fun getLastTempTargetIdWrapped(): Single<ValueWrapper<Long>> = fun getLastTempTargetId(): Long? =
database.temporaryTargetDao.getLastId() database.temporaryTargetDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// USER ENTRY // USER ENTRY
fun getAllUserEntries(): Single<List<UserEntry>> = fun getAllUserEntries(): Single<List<UserEntry>> =
@ -309,10 +305,8 @@ import kotlin.math.roundToInt
.map { if (!ascending) it.reversed() else it } .map { if (!ascending) it.reversed() else it }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getLastProfileSwitchIdWrapped(): Single<ValueWrapper<Long>> = fun getLastProfileSwitchId(): Long? =
database.profileSwitchDao.getLastId() database.profileSwitchDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// EFFECTIVE PROFILE SWITCH // EFFECTIVE PROFILE SWITCH
/* /*
@ -368,10 +362,8 @@ import kotlin.math.roundToInt
fun deleteAllEffectiveProfileSwitches() = fun deleteAllEffectiveProfileSwitches() =
database.effectiveProfileSwitchDao.deleteAllEntries() database.effectiveProfileSwitchDao.deleteAllEntries()
fun getLastEffectiveProfileSwitchIdWrapped(): Single<ValueWrapper<Long>> = fun getLastEffectiveProfileSwitchId(): Long? =
database.effectiveProfileSwitchDao.getLastId() database.effectiveProfileSwitchDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// THERAPY EVENT // THERAPY EVENT
/* /*
@ -435,10 +427,8 @@ import kotlin.math.roundToInt
database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to) database.therapyEventDao.compatGetTherapyEventDataFromToTime(from, to)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getLastTherapyEventIdWrapped(): Single<ValueWrapper<Long>> = fun getLastTherapyEventId(): Long? =
database.therapyEventDao.getLastId() database.therapyEventDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// FOOD // FOOD
/* /*
@ -471,10 +461,8 @@ import kotlin.math.roundToInt
fun deleteAllFoods() = fun deleteAllFoods() =
database.foodDao.deleteAllEntries() database.foodDao.deleteAllEntries()
fun getLastFoodIdWrapped(): Single<ValueWrapper<Long>> = fun getLastFoodId(): Long? =
database.foodDao.getLastId() database.foodDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// BOLUS // BOLUS
/* /*
@ -539,10 +527,8 @@ import kotlin.math.roundToInt
fun deleteAllBoluses() = fun deleteAllBoluses() =
database.bolusDao.deleteAllEntries() database.bolusDao.deleteAllEntries()
fun getLastBolusIdWrapped(): Single<ValueWrapper<Long>> = fun getLastBolusId(): Long? =
database.bolusDao.getLastId() database.bolusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// CARBS // CARBS
private fun expandCarbs(carbs: Carbs): List<Carbs> = private fun expandCarbs(carbs: Carbs): List<Carbs> =
@ -656,10 +642,8 @@ import kotlin.math.roundToInt
fun deleteAllCarbs() = fun deleteAllCarbs() =
database.carbsDao.deleteAllEntries() database.carbsDao.deleteAllEntries()
fun getLastCarbsIdWrapped(): Single<ValueWrapper<Long>> = fun getLastCarbsId(): Long? =
database.carbsDao.getLastId() database.carbsDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// BOLUS CALCULATOR RESULT // BOLUS CALCULATOR RESULT
/* /*
@ -698,10 +682,8 @@ import kotlin.math.roundToInt
fun deleteAllBolusCalculatorResults() = fun deleteAllBolusCalculatorResults() =
database.bolusCalculatorResultDao.deleteAllEntries() database.bolusCalculatorResultDao.deleteAllEntries()
fun getLastBolusCalculatorResultIdWrapped(): Single<ValueWrapper<Long>> = fun getLastBolusCalculatorResultId(): Long? =
database.bolusCalculatorResultDao.getLastId() database.bolusCalculatorResultDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// DEVICE STATUS // DEVICE STATUS
fun insert(deviceStatus: DeviceStatus): Long = fun insert(deviceStatus: DeviceStatus): Long =
@ -723,10 +705,8 @@ import kotlin.math.roundToInt
database.deviceStatusDao.getModifiedFrom(lastId) database.deviceStatusDao.getModifiedFrom(lastId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
fun getLastDeviceStatusIdWrapped(): Single<ValueWrapper<Long>> = fun getLastDeviceStatusId(): Long? =
database.deviceStatusDao.getLastId() database.deviceStatusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// TEMPORARY BASAL // TEMPORARY BASAL
/* /*
@ -789,10 +769,8 @@ import kotlin.math.roundToInt
fun getOldestTemporaryBasalRecord(): TemporaryBasal? = fun getOldestTemporaryBasalRecord(): TemporaryBasal? =
database.temporaryBasalDao.getOldestRecord() database.temporaryBasalDao.getOldestRecord()
fun getLastTemporaryBasalIdWrapped(): Single<ValueWrapper<Long>> = fun getLastTemporaryBasalId(): Long? =
database.temporaryBasalDao.getLastId() database.temporaryBasalDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// EXTENDED BOLUS // EXTENDED BOLUS
/* /*
@ -847,10 +825,8 @@ import kotlin.math.roundToInt
fun getOldestExtendedBolusRecord(): ExtendedBolus? = fun getOldestExtendedBolusRecord(): ExtendedBolus? =
database.extendedBolusDao.getOldestRecord() database.extendedBolusDao.getOldestRecord()
fun getLastExtendedBolusIdWrapped(): Single<ValueWrapper<Long>> = fun getLastExtendedBolusId(): Long? =
database.extendedBolusDao.getLastId() database.extendedBolusDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
// TotalDailyDose // TotalDailyDose
fun getLastTotalDailyDoses(count: Int, ascending: Boolean): Single<List<TotalDailyDose>> = fun getLastTotalDailyDoses(count: Int, ascending: Boolean): Single<List<TotalDailyDose>> =
@ -918,10 +894,8 @@ import kotlin.math.roundToInt
fun deleteAllOfflineEventEntries() = fun deleteAllOfflineEventEntries() =
database.offlineEventDao.deleteAllEntries() database.offlineEventDao.deleteAllEntries()
fun getLastOfflineEventIdWrapped(): Single<ValueWrapper<Long>> = fun getLastOfflineEventId(): Long? =
database.offlineEventDao.getLastId() database.offlineEventDao.getLastId()
.subscribeOn(Schedulers.io())
.toWrappedSingle()
suspend fun collectNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int) = NewEntries( suspend fun collectNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int) = NewEntries(
apsResults = database.apsResultDao.getNewEntriesSince(since, until, limit, offset), apsResults = database.apsResultDao.getNewEntriesSince(since, until, limit, offset),

View file

@ -24,7 +24,7 @@ internal interface BolusCalculatorResultDao : TraceableDao<BolusCalculatorResult
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_BOLUS_CALCULATOR_RESULTS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_BOLUS_CALCULATOR_RESULTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_BOLUS_CALCULATOR_RESULTS WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): BolusCalculatorResult? fun findByTimestamp(timestamp: Long): BolusCalculatorResult?

View file

@ -24,7 +24,7 @@ internal interface BolusDao : TraceableDao<Bolus> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_BOLUSES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_BOLUSES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): Bolus? fun findByTimestamp(timestamp: Long): Bolus?

View file

@ -23,7 +23,7 @@ internal interface CarbsDao : TraceableDao<Carbs> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_CARBS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_CARBS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_CARBS WHERE nightscoutId = :nsId AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_CARBS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): Carbs? fun findByNSId(nsId: String): Carbs?

View file

@ -29,7 +29,7 @@ internal interface DeviceStatusDao {
fun deleteOlderThan(than: Long): Int fun deleteOlderThan(than: Long): Int
@Query("SELECT id FROM $TABLE_DEVICE_STATUS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_DEVICE_STATUS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("DELETE FROM $TABLE_DEVICE_STATUS WHERE id NOT IN (SELECT MAX(id) FROM $TABLE_DEVICE_STATUS)") @Query("DELETE FROM $TABLE_DEVICE_STATUS WHERE id NOT IN (SELECT MAX(id) FROM $TABLE_DEVICE_STATUS)")
fun deleteAllEntriesExceptLast() fun deleteAllEntriesExceptLast()

View file

@ -23,7 +23,7 @@ internal interface EffectiveProfileSwitchDao : TraceableDao<EffectiveProfileSwit
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_EFFECTIVE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): EffectiveProfileSwitch? fun findByTimestamp(timestamp: Long): EffectiveProfileSwitch?

View file

@ -24,7 +24,7 @@ internal interface ExtendedBolusDao : TraceableDao<ExtendedBolus> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_EXTENDED_BOLUSES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_EXTENDED_BOLUSES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_EXTENDED_BOLUSES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): ExtendedBolus? fun findByTimestamp(timestamp: Long): ExtendedBolus?

View file

@ -23,7 +23,7 @@ internal interface FoodDao : TraceableDao<Food> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_FOODS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_FOODS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_FOODS WHERE nightscoutId = :nsId AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_FOODS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): Food? fun findByNSId(nsId: String): Food?

View file

@ -26,7 +26,7 @@ internal interface GlucoseValueDao : TraceableDao<GlucoseValue> {
fun getLast(): Maybe<GlucoseValue> fun getLast(): Maybe<GlucoseValue>
@Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_GLUCOSE_VALUES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE nightscoutId = :nsId AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSIdMaybe(nsId: String): Maybe<GlucoseValue> fun findByNSIdMaybe(nsId: String): Maybe<GlucoseValue>

View file

@ -23,7 +23,7 @@ internal interface OfflineEventDao : TraceableDao<OfflineEvent> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_OFFLINE_EVENTS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_OFFLINE_EVENTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE nightscoutId = :nsId AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_OFFLINE_EVENTS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): OfflineEvent? fun findByNSId(nsId: String): OfflineEvent?

View file

@ -24,7 +24,7 @@ internal interface ProfileSwitchDao : info.nightscout.database.impl.daos.workaro
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_PROFILE_SWITCHES ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_PROFILE_SWITCHES ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_PROFILE_SWITCHES WHERE timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(timestamp: Long): ProfileSwitch? fun findByTimestamp(timestamp: Long): ProfileSwitch?

View file

@ -24,7 +24,7 @@ internal interface TemporaryBasalDao : TraceableDao<TemporaryBasal> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_TEMPORARY_BASALS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_TEMPORARY_BASALS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE temporaryId = :temporaryId") @Query("SELECT * FROM $TABLE_TEMPORARY_BASALS WHERE temporaryId = :temporaryId")
fun findByTempId(temporaryId: Long): TemporaryBasal? fun findByTempId(temporaryId: Long): TemporaryBasal?

View file

@ -23,7 +23,7 @@ internal interface TemporaryTargetDao : TraceableDao<TemporaryTarget> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_TEMPORARY_TARGETS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_TEMPORARY_TARGETS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_TEMPORARY_TARGETS WHERE nightscoutId = :nsId AND referenceId IS NULL")
fun findByNSId(nsId: String): TemporaryTarget? fun findByNSId(nsId: String): TemporaryTarget?

View file

@ -23,7 +23,7 @@ internal interface TherapyEventDao : TraceableDao<TherapyEvent> {
override fun deleteTrackedChanges(): Int override fun deleteTrackedChanges(): Int
@Query("SELECT id FROM $TABLE_THERAPY_EVENTS ORDER BY id DESC limit 1") @Query("SELECT id FROM $TABLE_THERAPY_EVENTS ORDER BY id DESC limit 1")
fun getLastId(): Maybe<Long> fun getLastId(): Long?
@Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL") @Query("SELECT * FROM $TABLE_THERAPY_EVENTS WHERE type = :type AND timestamp = :timestamp AND referenceId IS NULL")
fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent? fun findByTimestamp(type: TherapyEvent.Type, timestamp: Long): TherapyEvent?

View file

@ -24,7 +24,7 @@ import info.nightscout.interfaces.plugin.OwnDatabasePlugin
import info.nightscout.interfaces.protection.ProtectionCheck import info.nightscout.interfaces.protection.ProtectionCheck
import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES import info.nightscout.interfaces.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.interfaces.pump.PumpSync import info.nightscout.interfaces.pump.PumpSync
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
@ -51,7 +51,7 @@ class MaintenanceFragment : DaggerFragment() {
@Inject lateinit var persistenceLayer: PersistenceLayer @Inject lateinit var persistenceLayer: PersistenceLayer
@Inject lateinit var protectionCheck: ProtectionCheck @Inject lateinit var protectionCheck: ProtectionCheck
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelectorXdrip: DataSyncSelectorXdrip
@Inject lateinit var pumpSync: PumpSync @Inject lateinit var pumpSync: PumpSync
@Inject lateinit var iobCobCalculator: IobCobCalculator @Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var overviewData: OverviewData @Inject lateinit var overviewData: OverviewData
@ -93,7 +93,8 @@ class MaintenanceFragment : DaggerFragment() {
for (plugin in activePlugin.getSpecificPluginsListByInterface(OwnDatabasePlugin::class.java)) { for (plugin in activePlugin.getSpecificPluginsListByInterface(OwnDatabasePlugin::class.java)) {
(plugin as OwnDatabasePlugin).clearAllTables() (plugin as OwnDatabasePlugin).clearAllTables()
} }
dataSyncSelector.resetToNextFullSync() activePlugin.activeNsClient?.dataSyncSelector?.resetToNextFullSync()
dataSyncSelectorXdrip.resetToNextFullSync()
pumpSync.connectNewPump() pumpSync.connectNewPump()
overviewData.reset() overviewData.reset()
iobCobCalculator.ads.reset() iobCobCalculator.ads.reset()
@ -111,7 +112,7 @@ class MaintenanceFragment : DaggerFragment() {
binding.cleanupDb.setOnClickListener { binding.cleanupDb.setOnClickListener {
activity?.let { activity -> activity?.let { activity ->
var result = "" var result = ""
OKDialog.showConfirmation(activity, rh.gs(R.string.maintenance), rh.gs(R.string.cleanup_db_confirm), Runnable { OKDialog.showConfirmation(activity, rh.gs(R.string.maintenance), rh.gs(info.nightscout.core.ui.R.string.cleanup_db_confirm), Runnable {
disposable += Completable.fromAction { result = persistenceLayer.cleanupDatabase(93, deleteTrackedChanges = true) } disposable += Completable.fromAction { result = persistenceLayer.cleanupDatabase(93, deleteTrackedChanges = true) }
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main) .observeOn(aapsSchedulers.main)
@ -119,8 +120,12 @@ class MaintenanceFragment : DaggerFragment() {
onError = { aapsLogger.error("Error cleaning up databases", it) }, onError = { aapsLogger.error("Error cleaning up databases", it) },
onComplete = { onComplete = {
if (result.isNotEmpty()) if (result.isNotEmpty())
OKDialog.show(activity, rh.gs(info.nightscout.core.ui.R.string.result), HtmlHelper.fromHtml("<b>" + rh.gs(R.string.cleared_entries) + "</b><br>" + result) OKDialog.show(
.toSpanned()) activity,
rh.gs(info.nightscout.core.ui.R.string.result),
HtmlHelper.fromHtml("<b>" + rh.gs(info.nightscout.core.ui.R.string.cleared_entries) + "</b><br>" + result)
.toSpanned()
)
aapsLogger.info(LTag.CORE, "Cleaned up databases with result: $result") aapsLogger.info(LTag.CORE, "Cleaned up databases with result: $result")
} }
) )

View file

@ -122,8 +122,6 @@
<string name="maintenance_shortname">MAINT</string> <string name="maintenance_shortname">MAINT</string>
<string name="description_maintenance">Provides several functions for maintenance (eg. log sending, log deletion).</string> <string name="description_maintenance">Provides several functions for maintenance (eg. log sending, log deletion).</string>
<string name="database_cleanup">Database cleanup</string> <string name="database_cleanup">Database cleanup</string>
<string name="cleanup_db_confirm">Do you want to cleanup the database?\nIt will remove tracked changes and historic data older than 3 months.</string>
<string name="cleared_entries">Cleared entries</string>
<string name="reset_db_confirm">Do you really want to reset the databases?</string> <string name="reset_db_confirm">Do you really want to reset the databases?</string>
<string name="maintenance_settings">Maintenance Settings</string> <string name="maintenance_settings">Maintenance Settings</string>
<string name="maintenance_email">Email recipient</string> <string name="maintenance_email">Email recipient</string>

View file

@ -17,6 +17,7 @@ import info.nightscout.plugins.iob.iobCobCalculator.data.AutosensDataObject
FoodModule::class, FoodModule::class,
SMSCommunicatorModule::class, SMSCommunicatorModule::class,
ProfileModule::class, ProfileModule::class,
ProfileModule.Bindings::class,
SkinsModule::class, SkinsModule::class,
SkinsUiModule::class, SkinsUiModule::class,
ActionsModule::class, ActionsModule::class,

View file

@ -1,7 +1,9 @@
package info.nightscout.plugins.di package info.nightscout.plugins.di
import dagger.Binds
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.plugins.profile.ProfileFragment import info.nightscout.plugins.profile.ProfileFragment
import info.nightscout.plugins.profile.ProfilePlugin import info.nightscout.plugins.profile.ProfilePlugin
@ -9,6 +11,12 @@ import info.nightscout.plugins.profile.ProfilePlugin
@Suppress("unused") @Suppress("unused")
abstract class ProfileModule { abstract class ProfileModule {
@ContributesAndroidInjector abstract fun contributesNSProfileWorker(): ProfilePlugin.NSProfileWorker
@ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): ProfileFragment @ContributesAndroidInjector abstract fun contributesLocalProfileFragment(): ProfileFragment
@Module
interface Bindings {
@Binds fun bindProfileSource(profilePlugin: ProfilePlugin): ProfileSource
}
} }

View file

@ -1,9 +1,6 @@
package info.nightscout.plugins.profile package info.nightscout.plugins.profile
import android.content.Context
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.extensions.blockFromJsonArray import info.nightscout.core.extensions.blockFromJsonArray
@ -11,8 +8,6 @@ import info.nightscout.core.extensions.pureProfileFromJson
import info.nightscout.core.profile.ProfileSealed import info.nightscout.core.profile.ProfileSealed
import info.nightscout.core.ui.dialogs.OKDialog import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.ui.toast.ToastUtils import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit import info.nightscout.interfaces.GlucoseUnit
@ -39,7 +34,6 @@ import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@ -234,7 +228,7 @@ class ProfilePlugin @Inject constructor(
} }
@Synchronized @Synchronized
fun loadFromStore(store: ProfileStore) { override fun loadFromStore(store: ProfileStore) {
try { try {
val newProfiles: ArrayList<ProfileSource.SingleProfile> = ArrayList() val newProfiles: ArrayList<ProfileSource.SingleProfile> = ArrayList()
for (p in store.getProfileList()) { for (p in store.getProfileList()) {
@ -428,39 +422,4 @@ class ProfilePlugin @Inject constructor(
get() = rawProfile?.getDefaultProfile()?.let { get() = rawProfile?.getDefaultProfile()?.let {
DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U " DecimalFormatter.to2Decimal(ProfileSealed.Pure(it).percentageBasalSum()) + "U "
} ?: "INVALID" } ?: "INVALID"
// cannot be inner class because of needed injection
class NSProfileWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var sp: SP
@Inject lateinit var config: Config
@Inject lateinit var profilePlugin: ProfilePlugin
@Inject lateinit var instantiator: Instantiator
override suspend fun doWorkAndLog(): Result {
val profileJson = dataWorkerStorage.pickupJSONObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_store, true) || config.NSCLIENT) {
val store = instantiator.provideProfileStore(profileJson)
val createdAt = store.getStartDate()
val lastLocalChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: createdAt: $createdAt Local last modification: $lastLocalChange")
@Suppress("LiftReturnOrAssignment")
if (createdAt > lastLocalChange || createdAt % 1000 == 0L) {// whole second means edited in NS
profilePlugin.loadFromStore(store)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
return Result.success(workDataOf("Data" to profileJson.toString().substring(0..Integer.min(5000, profileJson.length()))))
} else
return Result.success(workDataOf("Result" to "Unchanged. Ignoring"))
}
return Result.success(workDataOf("Result" to "Sync not enabled"))
}
}
} }

View file

@ -35,6 +35,7 @@ import info.nightscout.rx.events.EventNewBG
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.extensions.toVisibility import info.nightscout.shared.extensions.toVisibility
import info.nightscout.shared.extensions.toVisibilityKeepSpace
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
@ -135,7 +136,7 @@ class BGSourceFragment : DaggerFragment(), MenuProvider {
override fun onBindViewHolder(holder: GlucoseValuesViewHolder, position: Int) { override fun onBindViewHolder(holder: GlucoseValuesViewHolder, position: Int) {
val glucoseValue = glucoseValues[position] val glucoseValue = glucoseValues[position]
holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibility() holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibilityKeepSpace()
holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility() holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility()
val newDay = position == 0 || !dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp) val newDay = position == 0 || !dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility() holder.binding.date.visibility = newDay.toVisibility()

View file

@ -1,38 +1,16 @@
package info.nightscout.source package info.nightscout.source
import android.content.Context
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.GlucoseValue import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSSgv
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.source.BgSource import info.nightscout.interfaces.source.BgSource
import info.nightscout.interfaces.source.DoingOwnUploadSource import info.nightscout.interfaces.source.DoingOwnUploadSource
import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import kotlinx.coroutines.Dispatchers
import org.json.JSONArray
import org.json.JSONObject
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -49,21 +27,15 @@ class NSClientSourcePlugin @Inject constructor(
.pluginIcon(info.nightscout.core.main.R.drawable.ic_nsclient_bg) .pluginIcon(info.nightscout.core.main.R.drawable.ic_nsclient_bg)
.pluginName(R.string.ns_client_bg) .pluginName(R.string.ns_client_bg)
.shortName(R.string.ns_client_bg_short) .shortName(R.string.ns_client_bg_short)
.description(R.string.description_source_ns_client), .description(R.string.description_source_ns_client)
.alwaysEnabled(config.NSCLIENT)
.setDefault(config.NSCLIENT),
aapsLogger, rh, injector aapsLogger, rh, injector
), BgSource, NSClientSource, DoingOwnUploadSource { ), BgSource, NSClientSource, DoingOwnUploadSource {
private var lastBGTimeStamp: Long = 0 private var lastBGTimeStamp: Long = 0
private var isAdvancedFilteringEnabled = false private var isAdvancedFilteringEnabled = false
init {
if (config.NSCLIENT) {
pluginDescription
.alwaysEnabled(true)
.setDefault()
}
}
override fun advancedFilteringSupported(): Boolean = isAdvancedFilteringEnabled override fun advancedFilteringSupported(): Boolean = isAdvancedFilteringEnabled
override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false override fun shouldUploadToNs(glucoseValue: GlucoseValue): Boolean = false
@ -80,93 +52,4 @@ class NSClientSourcePlugin @Inject constructor(
lastBGTimeStamp = glucoseValue.timestamp lastBGTimeStamp = glucoseValue.timestamp
} }
} }
// cannot be inner class because of needed injection
class NSClientSourceWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var nsClientSourcePlugin: NSClientSourcePlugin
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var sp: SP
@Inject lateinit var rxBus: RxBus
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var storeDataForDb: StoreDataForDb
private fun toGv(jsonObject: JSONObject): TransactionGlucoseValue? {
val sgv = NSSgv(jsonObject)
return TransactionGlucoseValue(
timestamp = sgv.mills ?: return null,
value = sgv.mgdl?.toDouble() ?: return null,
noise = null,
raw = sgv.filtered?.toDouble(),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction),
nightscoutId = sgv.id,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device)
)
}
private fun toGv(sgv: NSSgvV3): TransactionGlucoseValue {
return TransactionGlucoseValue(
timestamp = sgv.date ?: throw InvalidParameterException(),
value = sgv.sgv,
noise = sgv.noise,
raw = sgv.filtered,
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction?.nsName),
nightscoutId = sgv.identifier,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device),
isValid = sgv.isValid,
utcOffset = T.mins(sgv.utcOffset ?: 0L).msecs()
)
}
@Suppress("SpellCheckingInspection")
override suspend fun doWorkAndLog(): Result {
var ret = Result.success()
val sgvs = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
if (!nsClientSourcePlugin.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false))
return Result.success(workDataOf("Result" to "Sync not enabled"))
var latestDateInReceivedData: Long = 0
aapsLogger.debug(LTag.BGSOURCE, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<TransactionGlucoseValue>()
try {
if (sgvs is JSONArray) { // V1 client
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
} else if (sgvs is List<*>) { // V3 client
for (i in 0 until sgvs.size) {
val sgv = toGv(sgvs[i] as NSSgvV3)
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
}
activePlugin.activeNsClient?.updateLatestBgReceivedIfNewer(latestDateInReceivedData)
// Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
storeDataForDb.glucoseValues.addAll(glucoseValues)
} catch (e: Exception) {
aapsLogger.error("Unhandled exception", e)
ret = Result.failure(workDataOf("Error" to e.toString()))
}
return ret
}
}
} }

View file

@ -29,7 +29,6 @@ abstract class SourceModule {
@ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment @ContributesAndroidInjector abstract fun contributesBGSourceFragment(): BGSourceFragment
@ContributesAndroidInjector abstract fun contributesNSClientSourceWorker(): NSClientSourcePlugin.NSClientSourceWorker
@ContributesAndroidInjector abstract fun contributesXdripWorker(): XdripSourcePlugin.XdripSourceWorker @ContributesAndroidInjector abstract fun contributesXdripWorker(): XdripSourcePlugin.XdripSourceWorker
@ContributesAndroidInjector abstract fun contributesDexcomWorker(): DexcomPlugin.DexcomWorker @ContributesAndroidInjector abstract fun contributesDexcomWorker(): DexcomPlugin.DexcomWorker
@ContributesAndroidInjector abstract fun contributesMM640gWorker(): MM640gPlugin.MM640gWorker @ContributesAndroidInjector abstract fun contributesMM640gWorker(): MM640gPlugin.MM640gWorker

View file

@ -11,10 +11,12 @@ import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.nsclient.NSSettingsStatus import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData import info.nightscout.interfaces.nsclient.ProcessedDeviceStatusData
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.plugins.sync.nsShared.DataSyncSelectorImplementation import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.plugins.sync.nsShared.NSClientFragment import info.nightscout.plugins.sync.nsShared.NSClientFragment
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclient.DataSyncSelectorV1Impl
import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatusImpl import info.nightscout.plugins.sync.nsclient.data.NSSettingsStatusImpl
import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl import info.nightscout.plugins.sync.nsclient.data.ProcessedDeviceStatusDataImpl
import info.nightscout.plugins.sync.nsclient.services.NSClientService import info.nightscout.plugins.sync.nsclient.services.NSClientService
@ -22,17 +24,10 @@ import info.nightscout.plugins.sync.nsclient.workers.NSClientAddAckWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker import info.nightscout.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3Impl
import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker import info.nightscout.plugins.sync.nsclientV3.workers.*
import info.nightscout.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadFoodsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadProfileStoreWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
import info.nightscout.plugins.sync.tidepool.TidepoolFragment import info.nightscout.plugins.sync.tidepool.TidepoolFragment
import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
import info.nightscout.plugins.sync.xdrip.XdripFragment import info.nightscout.plugins.sync.xdrip.XdripFragment
import info.nightscout.plugins.sync.xdrip.XdripPlugin import info.nightscout.plugins.sync.xdrip.XdripPlugin
import info.nightscout.plugins.sync.xdrip.workers.XdripDataSyncWorker import info.nightscout.plugins.sync.xdrip.workers.XdripDataSyncWorker
@ -60,14 +55,9 @@ abstract class SyncModule {
@ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker @ContributesAndroidInjector abstract fun contributesLoadBgWorker(): LoadBgWorker
@ContributesAndroidInjector abstract fun contributesLoadFoodsWorker(): LoadFoodsWorker @ContributesAndroidInjector abstract fun contributesLoadFoodsWorker(): LoadFoodsWorker
@ContributesAndroidInjector abstract fun contributesLoadProfileStoreWorker(): LoadProfileStoreWorker @ContributesAndroidInjector abstract fun contributesLoadProfileStoreWorker(): LoadProfileStoreWorker
@ContributesAndroidInjector abstract fun contributesStoreBgWorker(): StoreDataForDbImpl.StoreBgWorker
@ContributesAndroidInjector abstract fun contributesStoreFoodWorker(): StoreDataForDbImpl.StoreFoodWorker
@ContributesAndroidInjector abstract fun contributesStoreTreatmentsWorker(): StoreDataForDbImpl.StoreTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker @ContributesAndroidInjector abstract fun contributesTreatmentWorker(): LoadTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesProcessTreatmentsWorker(): ProcessTreatmentsWorker
@ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker @ContributesAndroidInjector abstract fun contributesLoadDeviceStatusWorker(): LoadDeviceStatusWorker
@ContributesAndroidInjector abstract fun contributesDataSyncWorker(): DataSyncWorker @ContributesAndroidInjector abstract fun contributesDataSyncWorker(): DataSyncWorker
@ContributesAndroidInjector abstract fun contributesFoodWorker(): ProcessFoodWorker
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment @ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
@ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment @ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment
@ -85,7 +75,9 @@ abstract class SyncModule {
@Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData @Binds fun bindProcessedDeviceStatusData(processedDeviceStatusDataImpl: ProcessedDeviceStatusDataImpl): ProcessedDeviceStatusData
@Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus @Binds fun bindNSSettingsStatus(nsSettingsStatusImpl: NSSettingsStatusImpl): NSSettingsStatus
@Binds fun bindDataSyncSelectorInterface(dataSyncSelectorImplementation: DataSyncSelectorImplementation): DataSyncSelector @Binds fun bindDataSyncSelectorV1Interface(dataSyncSelectorV1Impl: DataSyncSelectorV1Impl): DataSyncSelectorV1
@Binds fun bindDataSyncSelectorV3Interface(dataSyncSelectorV3Impl: DataSyncSelectorV3Impl): DataSyncSelectorV3
@Binds fun bindDataSyncSelectorXdripInterface(dataSyncSelectorXdripImpl: DataSyncSelectorXdripImpl): DataSyncSelectorXdrip
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb @Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast @Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
} }

View file

@ -1,36 +1,51 @@
package info.nightscout.plugins.sync.nsShared package info.nightscout.plugins.sync.nsShared
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ScrollView import androidx.core.text.toSpanned
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import info.nightscout.core.ui.dialogs.OKDialog import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.database.entities.UserEntry import info.nightscout.database.entities.UserEntry
import info.nightscout.interfaces.Config import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.db.PersistenceLayer
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginFragment import info.nightscout.interfaces.plugin.PluginFragment
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.databinding.NsClientFragmentBinding import info.nightscout.plugins.sync.databinding.NsClientFragmentBinding
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI import info.nightscout.plugins.sync.databinding.NsClientLogItemBinding
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiInsert
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.events.EventNSClientRestart import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.interfaces.ResourceHelper import info.nightscout.shared.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.kotlin.subscribeBy
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment { class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
@ -40,11 +55,11 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dataSyncSelector: DataSyncSelector
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var persistenceLayer: PersistenceLayer
companion object { companion object {
@ -61,11 +76,19 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private var _binding: NsClientFragmentBinding? = null private var _binding: NsClientFragmentBinding? = null
private lateinit var logAdapter: RecyclerViewAdapter
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
// This property is only valid between onCreateView and // This property is only valid between onCreateView and onDestroyView.
// onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
// https://stackoverflow.com/questions/31759171/recyclerview-and-java-lang-indexoutofboundsexception-inconsistency-detected-in
class FixedLinearLayoutManager(context: Context?, @RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL, reverseLayout: Boolean = false) :
LinearLayoutManager(context, orientation, reverseLayout) {
override fun supportsPredictiveItemAnimations(): Boolean = false
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View = override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
NsClientFragmentBinding.inflate(inflater, container, false).also { NsClientFragmentBinding.inflate(inflater, container, false).also {
_binding = it _binding = it
@ -78,15 +101,17 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
binding.autoscroll.isChecked = sp.getBoolean(R.string.key_ns_client_autoscroll, true) binding.autoscroll.isChecked = sp.getBoolean(R.string.key_ns_client_autoscroll, true)
binding.autoscroll.setOnCheckedChangeListener { _, isChecked -> binding.autoscroll.setOnCheckedChangeListener { _, isChecked ->
sp.putBoolean(R.string.key_ns_client_autoscroll, isChecked) sp.putBoolean(R.string.key_ns_client_autoscroll, isChecked)
updateGui()
} }
binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false) binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false)
binding.paused.setOnCheckedChangeListener { _, isChecked -> binding.paused.setOnCheckedChangeListener { _, isChecked ->
uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME, UserEntry.Sources.NSClient) uel.log(if (isChecked) UserEntry.Action.NS_PAUSED else UserEntry.Action.NS_RESUME, UserEntry.Sources.NSClient)
nsClientPlugin?.pause(isChecked) nsClientPlugin?.pause(isChecked)
updateGui()
} }
logAdapter = RecyclerViewAdapter(nsClientPlugin?.listLog ?: emptyList())
binding.recyclerview.layoutManager = FixedLinearLayoutManager(context)
binding.recyclerview.adapter = logAdapter
} }
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
@ -100,7 +125,12 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
override fun onMenuItemSelected(item: MenuItem): Boolean = override fun onMenuItemSelected(item: MenuItem): Boolean =
when (item.itemId) { when (item.itemId) {
ID_MENU_CLEAR_LOG -> { ID_MENU_CLEAR_LOG -> {
nsClientPlugin?.clearLog() nsClientPlugin?.listLog?.let {
synchronized(it) {
logAdapter.notifyItemRangeRemoved(0, it.size)
it.clear()
}
}
true true
} }
@ -115,10 +145,40 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
} }
ID_MENU_FULL_SYNC -> { ID_MENU_FULL_SYNC -> {
var result = ""
context?.let { context -> context?.let { context ->
OKDialog.showConfirmation( OKDialog.showConfirmation(
context, rh.gs(R.string.ns_client), rh.gs(R.string.full_sync_comment), context, rh.gs(R.string.ns_client), rh.gs(R.string.full_sync_comment),
Runnable { nsClientPlugin?.resetToFullSync() } Runnable {
OKDialog.showConfirmation(requireContext(), rh.gs(R.string.ns_client), rh.gs(info.nightscout.core.ui.R.string.cleanup_db_confirm_sync), Runnable {
disposable += Completable.fromAction { result = persistenceLayer.cleanupDatabase(93, deleteTrackedChanges = true) }
.subscribeOn(aapsSchedulers.io)
.observeOn(aapsSchedulers.main)
.subscribeBy(
onError = { aapsLogger.error("Error cleaning up databases", it) },
onComplete = {
if (result.isNotEmpty())
OKDialog.show(
requireContext(),
rh.gs(info.nightscout.core.ui.R.string.result),
HtmlHelper.fromHtml("<b>" + rh.gs(info.nightscout.core.ui.R.string.cleared_entries) + "</b><br>" + result)
.toSpanned()
)
aapsLogger.info(LTag.CORE, "Cleaned up databases with result: $result")
handler.post {
nsClientPlugin?.resetToFullSync()
nsClientPlugin?.resend("FULL_SYNC")
}
}
)
uel.log(UserEntry.Action.CLEANUP_DATABASES, UserEntry.Sources.NSClient)
}, Runnable {
handler.post {
nsClientPlugin?.resetToFullSync()
nsClientPlugin?.resend("FULL_SYNC")
}
})
}
) )
} }
true true
@ -127,28 +187,78 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
else -> false else -> false
} }
@Synchronized override fun onResume() { @Synchronized
super.onResume() override fun onDestroyView() {
disposable += rxBus super.onDestroyView()
.toObservable(EventNSClientUpdateGUI::class.java) binding.recyclerview.adapter = null // avoid leaks
.observeOn(aapsSchedulers.main) _binding = null
.subscribe({ updateGui() }, fabricPrivacy::logException)
updateGui()
} }
@Synchronized override fun onPause() { @Synchronized
override fun onResume() {
super.onResume()
disposable += rxBus
.toObservable(EventNSClientUpdateGuiInsert::class.java)
.observeOn(aapsSchedulers.main)
.subscribe(
{
logAdapter.notifyItemInserted(it.position)
if (sp.getBoolean(R.string.key_ns_client_autoscroll, true))
_binding?.recyclerview?.scrollToPosition(it.position)
nsClientPlugin?.listLog?.let { listLog ->
synchronized(listLog) {
if (listLog.size > Constants.MAX_LOG_LINES)
logAdapter.notifyItemRemoved(listLog.size - 1)
}
}
}, fabricPrivacy::logException
)
disposable += rxBus
.toObservable(EventNSClientUpdateGuiQueue::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ updateQueue() }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventNSClientUpdateGuiStatus::class.java)
.debounce(3L, TimeUnit.SECONDS)
.observeOn(aapsSchedulers.main)
.subscribe({ updateStatus() }, fabricPrivacy::logException)
updateStatus()
updateQueue()
}
@Synchronized
override fun onPause() {
super.onPause() super.onPause()
disposable.clear() disposable.clear()
} }
private fun updateGui() { private fun updateQueue() {
val size = nsClientPlugin?.dataSyncSelector?.queueSize() ?: 0L
_binding?.queue?.text = if (size >= 0) size.toString() else rh.gs(info.nightscout.core.ui.R.string.value_unavailable_short)
}
private fun updateStatus() {
if (_binding == null) return if (_binding == null) return
binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false) binding.paused.isChecked = sp.getBoolean(R.string.key_ns_paused, false)
binding.log.text = nsClientPlugin?.textLog() //if (sp.getBoolean(R.string.key_ns_client_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
if (sp.getBoolean(R.string.key_ns_client_autoscroll, true)) binding.logScrollview.fullScroll(ScrollView.FOCUS_DOWN)
binding.url.text = nsClientPlugin?.address binding.url.text = nsClientPlugin?.address
binding.status.text = nsClientPlugin?.status binding.status.text = nsClientPlugin?.status
val size = dataSyncSelector.queueSize() }
binding.queue.text = if (size >= 0) size.toString() else rh.gs(info.nightscout.core.ui.R.string.value_unavailable_short)
private inner class RecyclerViewAdapter(private var logList: List<EventNSClientNewLog>) : RecyclerView.Adapter<RecyclerViewAdapter.NsClientLogViewHolder>() {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): NsClientLogViewHolder =
NsClientLogViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.ns_client_log_item, viewGroup, false))
override fun onBindViewHolder(holder: NsClientLogViewHolder, position: Int) {
holder.binding.logText.text = HtmlHelper.fromHtml(logList[position].toPreparedHtml().toString())
}
override fun getItemCount() = logList.size
inner class NsClientLogViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val binding = NsClientLogItemBinding.bind(view)
}
} }
} }

View file

@ -0,0 +1,232 @@
package info.nightscout.plugins.sync.nsShared
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.extensions.foodFromJson
import info.nightscout.database.entities.Food
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.transactions.TransactionGlucoseValue
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSSgv
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.Instantiator
import info.nightscout.interfaces.profile.ProfileSource
import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsclientV3.extensions.*
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.entry.NSSgvV3
import info.nightscout.sdk.localmodel.food.NSFood
import info.nightscout.sdk.localmodel.treatment.*
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T
import org.json.JSONArray
import org.json.JSONObject
import javax.inject.Inject
import javax.inject.Singleton
@OpenForTesting
@Singleton
class NsIncomingDataProcessor @Inject constructor(
private val aapsLogger: AAPSLogger,
private val nsClientSource: NSClientSource,
private val sp: SP,
private val rxBus: RxBus,
private val dateUtil: DateUtil,
private val activePlugin: ActivePlugin,
private val storeDataForDb: StoreDataForDb,
private val config: Config,
private val instantiator: Instantiator,
private val profileSource: ProfileSource
) {
private fun toGv(jsonObject: JSONObject): TransactionGlucoseValue? {
val sgv = NSSgv(jsonObject)
return TransactionGlucoseValue(
timestamp = sgv.mills ?: return null,
value = sgv.mgdl?.toDouble() ?: return null,
noise = null,
raw = sgv.filtered?.toDouble(),
trendArrow = GlucoseValue.TrendArrow.fromString(sgv.direction),
nightscoutId = sgv.id,
sourceSensor = GlucoseValue.SourceSensor.fromString(sgv.device)
)
}
@Suppress("SpellCheckingInspection")
fun processSgvs(sgvs: Any) {
if (!nsClientSource.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false)) return
var latestDateInReceivedData: Long = 0
aapsLogger.debug(LTag.NSCLIENT, "Received NS Data: $sgvs")
val glucoseValues = mutableListOf<TransactionGlucoseValue>()
if (sgvs is JSONArray) { // V1 client
for (i in 0 until sgvs.length()) {
val sgv = toGv(sgvs.getJSONObject(i)) ?: continue
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
} else if (sgvs is List<*>) { // V3 client
for (i in 0 until sgvs.size) {
val sgv = (sgvs[i] as NSSgvV3).toTransactionGlucoseValue()
if (sgv.timestamp < dateUtil.now() && sgv.timestamp > latestDateInReceivedData) latestDateInReceivedData = sgv.timestamp
glucoseValues += sgv
}
}
activePlugin.activeNsClient?.updateLatestBgReceivedIfNewer(latestDateInReceivedData)
// Was that sgv more less 5 mins ago ?
if (T.msecs(dateUtil.now() - latestDateInReceivedData).mins() < 5L) {
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
storeDataForDb.glucoseValues.addAll(glucoseValues)
}
fun processTreatments(treatments: List<NSTreatment>) {
try {
var latestDateInReceivedData: Long = 0
for (treatment in treatments) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
val date = treatment.date ?: continue
if (date > latestDateInReceivedData) latestDateInReceivedData = date
when (treatment) {
is NSBolus ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT)
storeDataForDb.boluses.add(treatment.toBolus())
is NSCarbs ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_carbs, false) || config.NSCLIENT)
storeDataForDb.carbs.add(treatment.toCarbs())
is NSTemporaryTarget ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
if (treatment.duration > 0L) {
// not ending event
if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl()
) {
aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment")
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)
}
}
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 ->
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)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
}
}
fun processFood(data: Any) {
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data")
try {
val foods = mutableListOf<Food>()
if (data is JSONArray) {
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" -> {
val delFood = Food(
name = "",
portion = 0.0,
carbs = 0,
isValid = false
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
foods += delFood
}
else -> {
val food = foodFromJson(jsonFood)
if (food != null) foods += food
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()
}
storeDataForDb.foods.addAll(foods)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
}
}
fun processProfile(profileJson: JSONObject) {
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_profile_store, true) || config.NSCLIENT) {
val store = instantiator.provideProfileStore(profileJson)
val createdAt = store.getStartDate()
val lastLocalChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: createdAt: $createdAt Local last modification: $lastLocalChange")
@Suppress("LiftReturnOrAssignment")
if (createdAt > lastLocalChange || createdAt % 1000 == 0L) {// whole second means edited in NS
profileSource.loadFromStore(store)
aapsLogger.debug(LTag.PROFILE, "Received profileStore: $profileJson")
}
}
}
}

View file

@ -1,9 +1,6 @@
package info.nightscout.plugins.sync.nsShared package info.nightscout.plugins.sync.nsShared
import android.content.Context
import android.os.SystemClock import android.os.SystemClock
import androidx.work.WorkerParameters
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.Bolus import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.BolusCalculatorResult import info.nightscout.database.entities.BolusCalculatorResult
import info.nightscout.database.entities.Carbs import info.nightscout.database.entities.Carbs
@ -60,7 +57,6 @@ import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -119,45 +115,6 @@ class StoreDataForDbImpl @Inject constructor(
private val pause = 1000L // to slow down db operations private val pause = 1000L // to slow down db operations
class StoreBgWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
storeDataForDb.storeGlucoseValuesToDb()
return Result.success()
}
}
class StoreFoodWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
storeDataForDb.storeFoodsToDb()
return Result.success()
}
}
class StoreTreatmentsWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
storeDataForDb.storeTreatmentsToDb()
return Result.success()
}
}
fun <T> HashMap<T, Long>.inc(key: T) = fun <T> HashMap<T, Long>.inc(key: T) =
if (containsKey(key)) merge(key, 1, Long::plus) if (containsKey(key)) merge(key, 1, Long::plus)
else put(key, 1) else put(key, 1)
@ -803,6 +760,8 @@ class StoreDataForDbImpl @Inject constructor(
private val eventWorker = Executors.newSingleThreadScheduledExecutor() private val eventWorker = Executors.newSingleThreadScheduledExecutor()
private var scheduledEventPost: ScheduledFuture<*>? = null private var scheduledEventPost: ScheduledFuture<*>? = null
@Synchronized
override fun scheduleNsIdUpdate() { override fun scheduleNsIdUpdate() {
class PostRunnable : Runnable { class PostRunnable : Runnable {
@ -818,7 +777,8 @@ class StoreDataForDbImpl @Inject constructor(
scheduledEventPost = eventWorker.schedule(task, 10, TimeUnit.SECONDS) scheduledEventPost = eventWorker.schedule(task, 10, TimeUnit.SECONDS)
} }
private fun updateNsIds() { @Synchronized
override fun updateNsIds() {
repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(nsIdTemporaryTargets)) repository.runTransactionForResult(UpdateNsIdTemporaryTargetTransaction(nsIdTemporaryTargets))
.doOnError { error -> .doOnError { error ->
aapsLogger.error(LTag.DATABASE, "Updated nsId of TemporaryTarget failed", error) aapsLogger.error(LTag.DATABASE, "Updated nsId of TemporaryTarget failed", error)
@ -1003,27 +963,27 @@ class StoreDataForDbImpl @Inject constructor(
private fun sendLog(item: String, clazz: String) { private fun sendLog(item: String, clazz: String) {
inserted[clazz]?.let { inserted[clazz]?.let {
rxBus.send(EventNSClientNewLog("INSERT", "$item $it")) rxBus.send(EventNSClientNewLog("INSERT", "$item $it"))
} }
inserted.remove(clazz) inserted.remove(clazz)
updated[clazz]?.let { updated[clazz]?.let {
rxBus.send(EventNSClientNewLog("UPDATE", "$item $it")) rxBus.send(EventNSClientNewLog("UPDATE", "$item $it"))
} }
updated.remove(clazz) updated.remove(clazz)
invalidated[clazz]?.let { invalidated[clazz]?.let {
rxBus.send(EventNSClientNewLog("INVALIDATE", "$item $it")) rxBus.send(EventNSClientNewLog("INVALIDATE", "$item $it"))
} }
invalidated.remove(clazz) invalidated.remove(clazz)
nsIdUpdated[clazz]?.let { nsIdUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("NS_ID", "$item $it")) rxBus.send(EventNSClientNewLog("NS_ID", "$item $it"))
} }
nsIdUpdated.remove(clazz) nsIdUpdated.remove(clazz)
durationUpdated[clazz]?.let { durationUpdated[clazz]?.let {
rxBus.send(EventNSClientNewLog("DURATION", "$item $it")) rxBus.send(EventNSClientNewLog("DURATION", "$item $it"))
} }
durationUpdated.remove(clazz) durationUpdated.remove(clazz)
ended[clazz]?.let { ended[clazz]?.let {
rxBus.send(EventNSClientNewLog("CUT", "$item $it")) rxBus.send(EventNSClientNewLog("CUT", "$item $it"))
} }
ended.remove(clazz) ended.remove(clazz)
} }

View file

@ -0,0 +1,5 @@
package info.nightscout.plugins.sync.nsShared.events
import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGuiInsert(val position: Int) : EventUpdateGui()

View file

@ -2,4 +2,4 @@ package info.nightscout.plugins.sync.nsShared.events
import info.nightscout.rx.events.EventUpdateGui import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGUI : EventUpdateGui() class EventNSClientUpdateGuiQueue : EventUpdateGui()

View file

@ -0,0 +1,5 @@
package info.nightscout.plugins.sync.nsShared.events
import info.nightscout.rx.events.EventUpdateGui
class EventNSClientUpdateGuiStatus : EventUpdateGui()

View file

@ -1,12 +1,15 @@
package info.nightscout.plugins.sync.nsShared package info.nightscout.plugins.sync.nsclient
import info.nightscout.database.ValueWrapper
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
@ -15,14 +18,15 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class DataSyncSelectorImplementation @Inject constructor( class DataSyncSelectorV1Impl @Inject constructor(
private val sp: SP, private val sp: SP,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val appRepository: AppRepository private val appRepository: AppRepository,
) : DataSyncSelector { private val rxBus: RxBus
) : DataSyncSelectorV1 {
class QueueCounter( class QueueCounter(
var bolusesRemaining: Long = -1L, var bolusesRemaining: Long = -1L,
@ -61,8 +65,23 @@ class DataSyncSelectorImplementation @Inject constructor(
override fun queueSize(): Long = queueCounter.size() override fun queueSize(): Long = queueCounter.size()
override fun doUpload() { override suspend fun doUpload() {
rxBus.send(EventNSClientUpdateGuiStatus())
if (sp.getBoolean(R.string.key_ns_upload, true) && !isPaused) { if (sp.getBoolean(R.string.key_ns_upload, true) && !isPaused) {
queueCounter.bolusesRemaining = (appRepository.getLastBolusId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
queueCounter.carbsRemaining = (appRepository.getLastCarbsId() ?: 0L) - sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
queueCounter.bcrRemaining = (appRepository.getLastBolusCalculatorResultId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
queueCounter.ttsRemaining = (appRepository.getLastTempTargetId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
queueCounter.foodsRemaining = (appRepository.getLastFoodId() ?: 0L) - sp.getLong(R.string.key_ns_food_last_synced_id, 0)
queueCounter.gvsRemaining = (appRepository.getLastGlucoseValueId() ?: 0L) - sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
queueCounter.tesRemaining = (appRepository.getLastTherapyEventId() ?: 0L) - sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
queueCounter.dssRemaining = (appRepository.getLastDeviceStatusId() ?: 0L) - sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
queueCounter.tbrsRemaining = (appRepository.getLastTemporaryBasalId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
queueCounter.ebsRemaining = (appRepository.getLastExtendedBolusId() ?: 0L) - sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
queueCounter.pssRemaining = (appRepository.getLastProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
queueCounter.epssRemaining = (appRepository.getLastEffectiveProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
queueCounter.oesRemaining = (appRepository.getLastOfflineEventId() ?: 0L) - sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
rxBus.send(EventNSClientUpdateGuiQueue())
processChangedBoluses() processChangedBoluses()
processChangedCarbs() processChangedCarbs()
processChangedBolusCalculatorResults() processChangedBolusCalculatorResults()
@ -78,6 +97,7 @@ class DataSyncSelectorImplementation @Inject constructor(
processChangedOfflineEvents() processChangedOfflineEvents()
processChangedProfileStore() processChangedProfileStore()
} }
rxBus.send(EventNSClientUpdateGuiStatus())
} }
override fun resetToNextFullSync() { override fun resetToNextFullSync() {
@ -95,8 +115,8 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.remove(R.string.key_ns_offline_event_last_synced_id) sp.remove(R.string.key_ns_offline_event_last_synced_id)
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp) sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
val lastDeviceStatusDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet() val lastDeviceStatusDbId = appRepository.getLastDeviceStatusId()
if (lastDeviceStatusDbIdWrapped is ValueWrapper.Existing) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbIdWrapped.value) if (lastDeviceStatusDbId != null) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbId)
else sp.remove(R.string.key_ns_device_status_last_synced_id) else sp.remove(R.string.key_ns_device_status_last_synced_id)
} }
@ -107,16 +127,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedBoluses() { override tailrec suspend fun processChangedBoluses() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet() val lastDbId = appRepository.getLastBolusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0) sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.bolusesRemaining = lastDbId - startId queueCounter.bolusesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus -> appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ")
when { when {
@ -136,18 +156,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null -> bolus.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), " $startId/$lastDbId")
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
" $startId/$lastDbId"
)
// with nsId = update if it's modified record // with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id -> bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairBolus(bolus.first, bolus.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -160,16 +172,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedCarbs() { override tailrec suspend fun processChangedCarbs() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet() val lastDbId = appRepository.getLastCarbsId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0) sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.carbsRemaining = lastDbId - startId queueCounter.carbsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb -> appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ")
when { when {
@ -209,16 +221,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedBolusCalculatorResults() { override tailrec suspend fun processChangedBolusCalculatorResults() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet() val lastDbId = appRepository.getLastBolusCalculatorResultId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0) sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.bcrRemaining = lastDbId - startId queueCounter.bcrRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult -> appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ")
when { when {
@ -238,17 +250,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null -> bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
)
// with nsId = update if it's modified record // with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id -> bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id), "$startId/$lastDbId"
)
} }
return return
} }
@ -261,16 +266,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedTempTargets() { override tailrec suspend fun processChangedTempTargets() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet() val lastDbId = appRepository.getLastTempTargetId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0) sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.ttsRemaining = lastDbId - startId queueCounter.ttsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt -> appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ")
when { when {
@ -290,18 +295,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
tt.first.interfaceIDs.nightscoutId == null -> tt.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
// existing with nsId = update // existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null -> tt.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -314,16 +311,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedFoods() { override tailrec suspend fun processChangedFoods() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet() val lastDbId = appRepository.getLastFoodId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_food_last_synced_id, 0) sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.foodsRemaining = lastDbId - startId queueCounter.foodsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food -> appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ")
when { when {
@ -346,11 +343,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
food.first.interfaceIDs.nightscoutId != null -> food.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId")
"food",
DataSyncSelector.PairFood(food.first, food.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -363,16 +356,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedGlucoseValues() { override tailrec suspend fun processChangedGlucoseValues() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet() val lastDbId = appRepository.getLastGlucoseValueId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0) sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.gvsRemaining = lastDbId - startId queueCounter.gvsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv -> appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) { if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
@ -396,11 +389,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null else -> // gv.first.interfaceIDs.nightscoutId != null
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId")
"entries",
DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id),
"$startId/$lastDbId"
)
} }
} else { } else {
confirmLastGlucoseValueIdIfGreater(gv.second.id) confirmLastGlucoseValueIdIfGreater(gv.second.id)
@ -417,16 +406,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedTherapyEvents() { override tailrec suspend fun processChangedTherapyEvents() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet() val lastDbId = appRepository.getLastTherapyEventId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0) sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.tesRemaining = lastDbId - startId queueCounter.tesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te -> appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ")
when { when {
@ -449,11 +438,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
// nsId = update // nsId = update
te.first.interfaceIDs.nightscoutId != null -> te.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairTherapyEvent(te.first, te.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -466,16 +451,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override fun processChangedDeviceStatuses() { override suspend fun processChangedDeviceStatuses() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet() val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0) sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.dssRemaining = lastDbId - startId queueCounter.dssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus -> appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus") aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
when { when {
@ -496,16 +481,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedTemporaryBasals() { override tailrec suspend fun processChangedTemporaryBasals() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet() val lastDbId = appRepository.getLastTemporaryBasalId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0) sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.tbrsRemaining = lastDbId - startId queueCounter.tbrsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb -> appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ")
when { when {
@ -525,18 +510,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
tb.first.interfaceIDs.nightscoutId == null -> tb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
// with nsId = update // with nsId = update
tb.first.interfaceIDs.nightscoutId != null -> tb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -549,16 +526,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedExtendedBoluses() { override tailrec suspend fun processChangedExtendedBoluses() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet() val lastDbId = appRepository.getLastExtendedBolusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0) sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.ebsRemaining = lastDbId - startId queueCounter.ebsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb -> appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ")
val profile = profileFunction.getProfile(eb.first.timestamp) val profile = profileFunction.getProfile(eb.first.timestamp)
@ -580,18 +557,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
eb.first.interfaceIDs.nightscoutId == null -> eb.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
// with nsId = update // with nsId = update
eb.first.interfaceIDs.nightscoutId != null -> eb.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id),
"$startId/$lastDbId"
)
} }
return return
} else { } else {
@ -610,16 +579,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedProfileSwitches() { override tailrec suspend fun processChangedProfileSwitches() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet() val lastDbId = appRepository.getLastProfileSwitchId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0) sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.pssRemaining = lastDbId - startId queueCounter.pssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps -> appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when { when {
@ -642,11 +611,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
// with nsId = update // with nsId = update
ps.first.interfaceIDs.nightscoutId != null -> ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -659,16 +624,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedEffectiveProfileSwitches() { override tailrec suspend fun processChangedEffectiveProfileSwitches() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet() val lastDbId = appRepository.getLastEffectiveProfileSwitchId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0) sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.epssRemaining = lastDbId - startId queueCounter.epssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps -> appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when { when {
@ -688,18 +653,10 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
// without nsId = create new // without nsId = create new
ps.first.interfaceIDs.nightscoutId == null -> ps.first.interfaceIDs.nightscoutId == null ->
activePlugin.activeNsClient?.nsAdd( activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
// with nsId = update // with nsId = update
ps.first.interfaceIDs.nightscoutId != null -> ps.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -712,16 +669,16 @@ class DataSyncSelectorImplementation @Inject constructor(
} }
} }
override tailrec fun processChangedOfflineEvents() { override tailrec suspend fun processChangedOfflineEvents() {
if (isPaused) return if (isPaused) return
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet() val lastDbId = appRepository.getLastOfflineEventId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0) var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
if (startId > lastDbId) { if (startId > lastDbId) {
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0) sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0 startId = 0
} }
queueCounter.oesRemaining = lastDbId - startId queueCounter.oesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe -> appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ") aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ")
when { when {
@ -744,11 +701,7 @@ class DataSyncSelectorImplementation @Inject constructor(
activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
// existing with nsId = update // existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null -> oe.first.interfaceIDs.nightscoutId != null ->
activePlugin.activeNsClient?.nsUpdate( activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId")
"treatments",
DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id),
"$startId/$lastDbId"
)
} }
return return
} }
@ -758,7 +711,7 @@ class DataSyncSelectorImplementation @Inject constructor(
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced) sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
} }
override fun processChangedProfileStore() { override suspend fun processChangedProfileStore() {
if (isPaused) return if (isPaused) return
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0) val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0) val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)

View file

@ -4,10 +4,7 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder import android.os.IBinder
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
@ -25,15 +22,15 @@ import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.source.DoingOwnUploadSource import info.nightscout.interfaces.source.DoingOwnUploadSource
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper.fromHtml
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.NSClientFragment import info.nightscout.plugins.sync.nsShared.NSClientFragment
import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiInsert
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.plugins.sync.nsclient.data.AlarmAck import info.nightscout.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.plugins.sync.nsclient.extensions.toJson import info.nightscout.plugins.sync.nsclient.extensions.toJson
import info.nightscout.plugins.sync.nsclient.services.NSClientService import info.nightscout.plugins.sync.nsclient.services.NSClientService
@ -65,8 +62,7 @@ class NSClientPlugin @Inject constructor(
private val sp: SP, private val sp: SP,
private val receiverDelegate: ReceiverDelegate, private val receiverDelegate: ReceiverDelegate,
private val config: Config, private val config: Config,
private val dataSyncSelector: DataSyncSelector, private val dataSyncSelectorV1: DataSyncSelectorV1,
private val uiInteraction: UiInteraction,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
@ -84,8 +80,8 @@ class NSClientPlugin @Inject constructor(
) { ) {
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) override val listLog: MutableList<EventNSClientNewLog> = ArrayList()
private val listLog: MutableList<EventNSClientNewLog> = ArrayList() override val dataSyncSelector: DataSyncSelector get() = dataSyncSelectorV1
override var status = "" override var status = ""
var nsClientService: NSClientService? = null var nsClientService: NSClientService? = null
val isAllowed: Boolean val isAllowed: Boolean
@ -101,10 +97,10 @@ class NSClientPlugin @Inject constructor(
.toObservable(EventNSClientStatus::class.java) .toObservable(EventNSClientStatus::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ event -> .subscribe({ event ->
status = event.getStatus(context) status = event.getStatus(context)
rxBus.send(EventNSClientUpdateGUI()) rxBus.send(EventNSClientUpdateGuiStatus())
// Pass to setup wizard // Pass to setup wizard
rxBus.send(EventSWSyncStatus(event.getStatus(context))) rxBus.send(EventSWSyncStatus(event.getStatus(context)))
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventAppExit::class.java) .toObservable(EventAppExit::class.java)
@ -159,37 +155,17 @@ class NSClientPlugin @Inject constructor(
} }
} }
override fun clearLog() {
handler.post {
synchronized(listLog) { listLog.clear() }
rxBus.send(EventNSClientUpdateGUI())
}
}
override fun detectedNsVersion(): String = nsSettingsStatus.getVersion() override fun detectedNsVersion(): String = nsSettingsStatus.getVersion()
private fun addToLog(ev: EventNSClientNewLog) { private fun addToLog(ev: EventNSClientNewLog) {
synchronized(listLog) { synchronized(listLog) {
listLog.add(ev) listLog.add(0, ev)
rxBus.send(EventNSClientUpdateGuiInsert(0))
// remove the first line if log is too large // remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) { if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0) listLog.removeAt(listLog.size - 1)
} }
} }
rxBus.send(EventNSClientUpdateGUI())
}
override fun textLog(): Spanned {
try {
val newTextLog = StringBuilder()
synchronized(listLog) {
for (log in listLog) newTextLog.append(log.toPreparedHtml())
}
return fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) {
uiInteraction.showToastAndNotification(context, "Out of memory!\nStop using this phone !!!", info.nightscout.core.ui.R.raw.error)
}
return fromHtml("")
} }
override fun resend(reason: String) { override fun resend(reason: String) {
@ -229,7 +205,7 @@ class NSClientPlugin @Inject constructor(
dataSyncSelector.resetToNextFullSync() dataSyncSelector.resetToNextFullSync()
} }
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) { override suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean {
when (dataPair) { when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.toJson(true, dateUtil) is DataSyncSelector.PairBolus -> dataPair.value.toJson(true, dateUtil)
is DataSyncSelector.PairCarbs -> dataPair.value.toJson(true, dateUtil) is DataSyncSelector.PairCarbs -> dataPair.value.toJson(true, dateUtil)
@ -249,9 +225,10 @@ class NSClientPlugin @Inject constructor(
}?.let { data -> }?.let { data ->
nsClientService?.dbAdd(collection, data, dataPair, progress) nsClientService?.dbAdd(collection, data, dataPair, progress)
} }
return true
} }
override fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) { override suspend fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean {
val id = when (dataPair) { val id = when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.interfaceIDs.nightscoutId is DataSyncSelector.PairBolus -> dataPair.value.interfaceIDs.nightscoutId
is DataSyncSelector.PairCarbs -> dataPair.value.interfaceIDs.nightscoutId is DataSyncSelector.PairCarbs -> dataPair.value.interfaceIDs.nightscoutId
@ -284,5 +261,6 @@ class NSClientPlugin @Inject constructor(
}?.let { data -> }?.let { data ->
nsClientService?.dbUpdate(collection, id, data, dataPair, progress) nsClientService?.dbUpdate(collection, id, data, dataPair, progress)
} }
return true
} }
} }

View file

@ -24,16 +24,16 @@ import info.nightscout.interfaces.Config
import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSAlarm import info.nightscout.interfaces.nsclient.NSAlarm
import info.nightscout.interfaces.nsclient.NSSettingsStatus import info.nightscout.interfaces.nsclient.NSSettingsStatus
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.JsonHelper.safeGetString import info.nightscout.interfaces.utils.JsonHelper.safeGetString
import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull import info.nightscout.interfaces.utils.JsonHelper.safeGetStringAllowNull
import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged
import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus import info.nightscout.plugins.sync.nsShared.events.EventNSClientStatus
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.plugins.sync.nsclient.NSClientPlugin import info.nightscout.plugins.sync.nsclient.NSClientPlugin
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck import info.nightscout.plugins.sync.nsclient.acks.NSAuthAck
@ -42,16 +42,9 @@ import info.nightscout.plugins.sync.nsclient.data.AlarmAck
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker import info.nightscout.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker import info.nightscout.plugins.sync.nsclient.workers.NSClientMbgWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit import info.nightscout.rx.events.*
import info.nightscout.rx.events.EventConfigBuilderChange
import info.nightscout.rx.events.EventDismissNotification
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.events.EventNSClientRestart
import info.nightscout.rx.events.EventNewHistoryData
import info.nightscout.rx.events.EventPreferenceChange
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus import info.nightscout.sdk.localmodel.devicestatus.NSDeviceStatus
@ -64,14 +57,19 @@ import io.reactivex.rxjava3.kotlin.plusAssign
import io.socket.client.IO import io.socket.client.IO
import io.socket.client.Socket import io.socket.client.Socket
import io.socket.emitter.Emitter import io.socket.emitter.Emitter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import java.net.URISyntaxException import java.net.URISyntaxException
import java.util.Locale import java.util.*
import javax.inject.Inject import javax.inject.Inject
class NSClientService : DaggerService() { @Suppress("SpellCheckingInspection") class NSClientService : DaggerService() {
@Inject lateinit var injector: HasAndroidInjector @Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@ -86,10 +84,11 @@ class NSClientService : DaggerService() {
@Inject lateinit var config: Config @Inject lateinit var config: Config
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var uiInteraction: UiInteraction @Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var workerClasses: WorkerClasses @Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Inject lateinit var storeDataForDb: StoreDataForDb
companion object { companion object {
@ -99,6 +98,7 @@ class NSClientService : DaggerService() {
} }
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private var scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var wakeLock: PowerManager.WakeLock? = null private var wakeLock: PowerManager.WakeLock? = null
private val binder: IBinder = LocalBinder() private val binder: IBinder = LocalBinder()
@ -196,12 +196,12 @@ class NSClientService : DaggerService() {
isConnected = true isConnected = true
hasWriteAuth = ack.write && ack.writeTreatment hasWriteAuth = ack.write && ack.writeTreatment
rxBus.send(EventNSClientStatus(connectionStatus)) rxBus.send(EventNSClientStatus(connectionStatus))
rxBus.send(EventNSClientNewLog("AUTH", connectionStatus)) rxBus.send(EventNSClientNewLog("AUTH", connectionStatus))
if (!ack.write) { if (!ack.write) {
rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted ")) rxBus.send(EventNSClientNewLog("ERROR", "Write permission not granted "))
} }
if (!ack.writeTreatment) { if (!ack.writeTreatment) {
rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted ")) rxBus.send(EventNSClientNewLog("ERROR", "Write treatment permission not granted "))
} }
if (!hasWriteAuth) { if (!hasWriteAuth) {
val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.no_write_permission), Notification.URGENT) val noWritePerm = Notification(Notification.NSCLIENT_NO_WRITE_PERMISSION, rh.gs(R.string.no_write_permission), Notification.URGENT)
@ -227,14 +227,14 @@ class NSClientService : DaggerService() {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString() if (nsAPISecret != "") nsApiHashCode = Hashing.sha1().hashString(nsAPISecret, Charsets.UTF_8).toString()
rxBus.send(EventNSClientStatus("Initializing")) rxBus.send(EventNSClientStatus("Initializing"))
if (nsClientPlugin.isAllowed != true) { if (!nsClientPlugin.isAllowed) {
rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason)) rxBus.send(EventNSClientNewLog("NSCLIENT", nsClientPlugin.blockingReason))
rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason)) rxBus.send(EventNSClientStatus(nsClientPlugin.blockingReason))
} else if (sp.getBoolean(R.string.key_ns_paused, false)) { } else if (sp.getBoolean(R.string.key_ns_paused, false)) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "paused")) rxBus.send(EventNSClientNewLog("NSCLIENT", "paused"))
rxBus.send(EventNSClientStatus("Paused")) rxBus.send(EventNSClientStatus("Paused"))
} else if (!nsEnabled) { } else if (!nsEnabled) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled")) rxBus.send(EventNSClientNewLog("NSCLIENT", "disabled"))
rxBus.send(EventNSClientStatus("Disabled")) rxBus.send(EventNSClientStatus("Disabled"))
} else if (nsURL != "" && (nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) { } else if (nsURL != "" && (nsURL.lowercase(Locale.getDefault()).startsWith("https://"))) {
try { try {
@ -243,7 +243,7 @@ class NSClientService : DaggerService() {
socket = IO.socket(nsURL, opt).also { socket -> socket = IO.socket(nsURL, opt).also { socket ->
socket.on(Socket.EVENT_CONNECT, onConnect) socket.on(Socket.EVENT_CONNECT, onConnect)
socket.on(Socket.EVENT_DISCONNECT, onDisconnect) socket.on(Socket.EVENT_DISCONNECT, onDisconnect)
rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect")) rxBus.send(EventNSClientNewLog("NSCLIENT", "do connect"))
socket.connect() socket.connect()
socket.on("dataUpdate", onDataUpdate) socket.on("dataUpdate", onDataUpdate)
socket.on("announcement", onAnnouncement) socket.on("announcement", onAnnouncement)
@ -252,17 +252,17 @@ class NSClientService : DaggerService() {
socket.on("clear_alarm", onClearAlarm) socket.on("clear_alarm", onClearAlarm)
} }
} catch (e: URISyntaxException) { } catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax")) rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax")) rxBus.send(EventNSClientStatus("Wrong URL syntax"))
} catch (e: RuntimeException) { } catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax")) rxBus.send(EventNSClientNewLog("NSCLIENT", "Wrong URL syntax"))
rxBus.send(EventNSClientStatus("Wrong URL syntax")) rxBus.send(EventNSClientStatus("Wrong URL syntax"))
} }
} else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) { } else if (nsURL.lowercase(Locale.getDefault()).startsWith("http://")) {
rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted")) rxBus.send(EventNSClientNewLog("NSCLIENT", "NS URL not encrypted"))
rxBus.send(EventNSClientStatus("Not encrypted")) rxBus.send(EventNSClientStatus("Not encrypted"))
} else { } else {
rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified")) rxBus.send(EventNSClientNewLog("NSCLIENT", "No NS URL specified"))
rxBus.send(EventNSClientStatus("Not configured")) rxBus.send(EventNSClientStatus("Not configured"))
} }
} }
@ -270,7 +270,7 @@ class NSClientService : DaggerService() {
private val onConnect = Emitter.Listener { private val onConnect = Emitter.Listener {
connectCounter++ connectCounter++
val socketId = socket?.id() ?: "NULL" val socketId = socket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId")) rxBus.send(EventNSClientNewLog("NSCLIENT", "connect #$connectCounter event. ID: $socketId"))
if (socket != null) sendAuthMessage(NSAuthAck(rxBus)) if (socket != null) sendAuthMessage(NSAuthAck(rxBus))
watchdog() watchdog()
} }
@ -284,16 +284,16 @@ class NSClientService : DaggerService() {
reconnections.remove(r) reconnections.remove(r)
} }
} }
rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS)) rxBus.send(EventNSClientNewLog("WATCHDOG", "connections in last " + WATCHDOG_INTERVAL_MINUTES + " minutes: " + reconnections.size + "/" + WATCHDOG_MAX_CONNECTIONS))
if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) { if (reconnections.size >= WATCHDOG_MAX_CONNECTIONS) {
val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.ns_malfunction), Notification.URGENT) val n = Notification(Notification.NS_MALFUNCTION, rh.gs(R.string.ns_malfunction), Notification.URGENT)
rxBus.send(EventNewNotification(n)) rxBus.send(EventNewNotification(n))
rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes")) rxBus.send(EventNSClientNewLog("WATCHDOG", "pausing for $WATCHDOG_RECONNECT_IN minutes"))
nsClientPlugin.pause(true) nsClientPlugin.pause(true)
rxBus.send(EventNSClientUpdateGUI()) rxBus.send(EventNSClientUpdateGuiStatus())
Thread { Thread {
SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs()) SystemClock.sleep(mins(WATCHDOG_RECONNECT_IN.toLong()).msecs())
rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient")) rxBus.send(EventNSClientNewLog("WATCHDOG", "re-enabling NSClient"))
nsClientPlugin.pause(false) nsClientPlugin.pause(false)
}.start() }.start()
} }
@ -302,7 +302,7 @@ class NSClientService : DaggerService() {
private val onDisconnect = Emitter.Listener { args -> private val onDisconnect = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *args) aapsLogger.debug(LTag.NSCLIENT, "disconnect reason: {}", *args)
rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event")) rxBus.send(EventNSClientNewLog("NSCLIENT", "disconnect event"))
} }
@Synchronized fun destroy() { @Synchronized fun destroy() {
@ -313,7 +313,7 @@ class NSClientService : DaggerService() {
socket?.off("alarm") socket?.off("alarm")
socket?.off("urgent_alarm") socket?.off("urgent_alarm")
socket?.off("clear_alarm") socket?.off("clear_alarm")
rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy")) rxBus.send(EventNSClientNewLog("NSCLIENT", "destroy"))
isConnected = false isConnected = false
hasWriteAuth = false hasWriteAuth = false
socket?.disconnect() socket?.disconnect()
@ -332,7 +332,7 @@ class NSClientService : DaggerService() {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
return return
} }
rxBus.send(EventNSClientNewLog("AUTH", "requesting auth")) rxBus.send(EventNSClientNewLog("AUTH", "requesting auth"))
socket?.emit("authorize", authMessage, ack) socket?.emit("authorize", authMessage, ack)
} }
@ -409,7 +409,7 @@ class NSClientService : DaggerService() {
val data: JSONObject val data: JSONObject
try { try {
data = args[0] as JSONObject data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("CLEARALARM", "received")) rxBus.send(EventNSClientNewLog("CLEARALARM", "received"))
rxBus.send(EventDismissNotification(Notification.NS_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM)) rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
aapsLogger.debug(LTag.NSCLIENT, data.toString()) aapsLogger.debug(LTag.NSCLIENT, data.toString())
@ -428,30 +428,26 @@ class NSClientService : DaggerService() {
try { try {
// delta means only increment/changes are coming // delta means only increment/changes are coming
val isDelta = data.has("delta") val isDelta = data.has("delta")
rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full")) rxBus.send(EventNSClientNewLog("DATA", "Data packet #" + dataCounter++ + if (isDelta) " delta" else " full"))
if (data.has("status")) { if (data.has("status")) {
val status = data.getJSONObject("status") val status = data.getJSONObject("status")
nsSettingsStatus.handleNewData(status) nsSettingsStatus.handleNewData(status)
} else if (!isDelta) { } else if (!isDelta) {
rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version ")) rxBus.send(EventNSClientNewLog("ERROR", "Unsupported Nightscout version "))
} }
if (data.has("profiles")) { if (data.has("profiles")) {
val profiles = data.getJSONArray("profiles") val profiles = data.getJSONArray("profiles")
if (profiles.length() > 0) { if (profiles.length() > 0) {
// take the newest // take the newest
val profileStoreJson = profiles[profiles.length() - 1] as JSONObject val profileStoreJson = profiles[profiles.length() - 1] as JSONObject
rxBus.send(EventNSClientNewLog("PROFILE", "profile received")) rxBus.send(EventNSClientNewLog("◄ PROFILE", "profile received"))
dataWorkerStorage.enqueue( nsIncomingDataProcessor.processProfile(profileStoreJson)
OneTimeWorkRequest.Builder(workerClasses.nsProfileWorker)
.setInputData(dataWorkerStorage.storeInputData(profileStoreJson))
.build()
)
} }
} }
if (data.has("treatments")) { if (data.has("treatments")) {
val treatments = data.getJSONArray("treatments") val treatments = data.getJSONArray("treatments")
val addedOrUpdatedTreatments = JSONArray() val addedOrUpdatedTreatments = JSONArray()
if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments")) if (treatments.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + treatments.length() + " treatments"))
for (index in 0 until treatments.length()) { for (index in 0 until treatments.length()) {
val jsonTreatment = treatments.getJSONObject(index) val jsonTreatment = treatments.getJSONObject(index)
val action = safeGetStringAllowNull(jsonTreatment, "action", null) val action = safeGetStringAllowNull(jsonTreatment, "action", null)
@ -497,7 +493,7 @@ class NSClientService : DaggerService() {
aapsLogger.warn( aapsLogger.warn(
LTag.NSCLIENT, LTag.NSCLIENT,
"JSON devicestatus object #$arrayIndex (out of ${devicestatusJsonArray.length()}) " + "JSON devicestatus object #$arrayIndex (out of ${devicestatusJsonArray.length()}) " +
"has invalid value \"$batteryValue\" (expected integer); replacing with hardcoded integer 100" "has invalid value \"$batteryValue\" (expected integer); replacing with hardcoded integer 100"
) )
uploaderObject.put("battery", 100) uploaderObject.put("battery", 100)
} }
@ -507,7 +503,7 @@ class NSClientService : DaggerService() {
val devicestatuses = gson.fromJson(data.getString("devicestatus"), Array<NSDeviceStatus>::class.java) val devicestatuses = gson.fromJson(data.getString("devicestatus"), Array<NSDeviceStatus>::class.java)
if (devicestatuses.isNotEmpty()) { if (devicestatuses.isNotEmpty()) {
rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.size + " device statuses")) rxBus.send(EventNSClientNewLog("DATA", "received " + devicestatuses.size + " device statuses"))
nsDeviceStatusHandler.handleNewData(devicestatuses) nsDeviceStatusHandler.handleNewData(devicestatuses)
} }
} catch (e: JSONException) { } catch (e: JSONException) {
@ -516,19 +512,13 @@ class NSClientService : DaggerService() {
} }
if (data.has("food")) { if (data.has("food")) {
val foods = data.getJSONArray("food") val foods = data.getJSONArray("food")
if (foods.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + foods.length() + " foods")) if (foods.length() > 0) rxBus.send(EventNSClientNewLog("◄ DATA", "received " + foods.length() + " foods"))
dataWorkerStorage nsIncomingDataProcessor.processFood(foods)
.beginUniqueWork( storeDataForDb.storeFoodsToDb()
"ProcessFoods",
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(foods))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
.enqueue()
} }
if (data.has("mbgs")) { if (data.has("mbgs")) {
val mbgArray = data.getJSONArray("mbgs") val mbgArray = data.getJSONArray("mbgs")
if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + mbgArray.length() + " mbgs")) if (mbgArray.length() > 0) rxBus.send(EventNSClientNewLog("◄ DATA", "received " + mbgArray.length() + " mbgs"))
dataWorkerStorage.enqueue( dataWorkerStorage.enqueue(
OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java) OneTimeWorkRequest.Builder(NSClientMbgWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(mbgArray)) .setInputData(dataWorkerStorage.storeInputData(mbgArray))
@ -537,26 +527,20 @@ class NSClientService : DaggerService() {
} }
if (data.has("cals")) { if (data.has("cals")) {
val cals = data.getJSONArray("cals") val cals = data.getJSONArray("cals")
if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals")) if (cals.length() > 0) rxBus.send(EventNSClientNewLog("DATA", "received " + cals.length() + " cals"))
// Calibrations ignored // Calibrations ignored
} }
if (data.has("sgvs")) { if (data.has("sgvs")) {
val sgvs = data.getJSONArray("sgvs") val sgvs = data.getJSONArray("sgvs")
if (sgvs.length() > 0) { if (sgvs.length() > 0) {
rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs")) rxBus.send(EventNSClientNewLog("DATA", "received " + sgvs.length() + " sgvs"))
// Objective0 // Objective0
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true) sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true)
dataWorkerStorage nsIncomingDataProcessor.processSgvs(sgvs)
.beginUniqueWork( storeDataForDb.storeGlucoseValuesToDb()
"ProcessBg",
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker)
.setInputData(dataWorkerStorage.storeInputData(sgvs))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build())
.enqueue()
} }
} }
rxBus.send(EventNSClientNewLog("LAST", dateUtil.dateAndTimeString(latestDateInReceivedData))) rxBus.send(EventNSClientNewLog("◄ LAST", dateUtil.dateAndTimeString(latestDateInReceivedData)))
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
} }
@ -578,7 +562,7 @@ class NSClientService : DaggerService() {
socket?.emit("dbUpdate", message, NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject)) socket?.emit("dbUpdate", message, NSUpdateAck("dbUpdate", _id, aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject))
rxBus.send( rxBus.send(
EventNSClientNewLog( EventNSClientNewLog(
"UPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " + "UPDATE $collection", "Sent " + originalObject.javaClass.simpleName + " " +
"" + _id + " " + data + progress "" + _id + " " + data + progress
) )
) )
@ -594,7 +578,7 @@ class NSClientService : DaggerService() {
message.put("collection", collection) message.put("collection", collection)
message.put("data", data) message.put("data", data)
socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject)) socket?.emit("dbAdd", message, NSAddAck(aapsLogger, rxBus, this, dateUtil, dataWorkerStorage, originalObject))
rxBus.send(EventNSClientNewLog("ADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress)) rxBus.send(EventNSClientNewLog("ADD $collection", "Sent " + originalObject.javaClass.simpleName + " " + data + " " + progress))
} catch (e: JSONException) { } catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e) aapsLogger.error("Unhandled exception", e)
} }
@ -603,29 +587,22 @@ class NSClientService : DaggerService() {
fun sendAlarmAck(alarmAck: AlarmAck) { fun sendAlarmAck(alarmAck: AlarmAck) {
if (!isConnected || !hasWriteAuth) return if (!isConnected || !hasWriteAuth) return
socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime) socket?.emit("ack", alarmAck.level, alarmAck.group, alarmAck.silenceTime)
rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime)) rxBus.send(EventNSClientNewLog("ALARMACK ", alarmAck.level.toString() + " " + alarmAck.group + " " + alarmAck.silenceTime))
} }
fun resend(reason: String) { @Synchronized
if (!isConnected || !hasWriteAuth) return fun resend(reason: String) = runBlocking {
handler.post { if (!isConnected || !hasWriteAuth) return@runBlocking
if (socket?.connected() != true) return@post scope.async {
if (socket?.connected() != true) return@async
if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) { if (lastAckTime > System.currentTimeMillis() - 10 * 1000L) {
aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec") aapsLogger.debug(LTag.NSCLIENT, "Skipping resend by lastAckTime: " + (System.currentTimeMillis() - lastAckTime) / 1000L + " sec")
return@post return@async
} }
// val powerManager = getSystemService(POWER_SERVICE) as PowerManager rxBus.send(EventNSClientNewLog("● QUEUE", "Resend started: $reason"))
// val wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, dataSyncSelectorV1.doUpload()
// "AndroidAPS:NSClientService_onDataUpdate") rxBus.send(EventNSClientNewLog("● QUEUE", "Resend ended: $reason"))
// wakeLock.acquire(mins(10).msecs()) }.join()
try {
rxBus.send(EventNSClientNewLog("QUEUE", "Resend started: $reason"))
dataSyncSelector.doUpload()
rxBus.send(EventNSClientNewLog("QUEUE", "Resend ended: $reason"))
} finally {
// if (wakeLock.isHeld) wakeLock.release()
}
}
} }
fun restart() { fun restart() {
@ -638,7 +615,7 @@ class NSClientService : DaggerService() {
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, defaultVal)) { if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_announcements, defaultVal)) {
val nsAlarm = NSAlarm(announcement) val nsAlarm = NSAlarm(announcement)
uiInteraction.addNotificationWithAction(injector, nsAlarm) uiInteraction.addNotificationWithAction(injector, nsAlarm)
rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received"))) rxBus.send(EventNSClientNewLog("ANNOUNCEMENT", safeGetString(announcement, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, announcement.toString()) aapsLogger.debug(LTag.NSCLIENT, announcement.toString())
} }
} }
@ -651,7 +628,7 @@ class NSClientService : DaggerService() {
val nsAlarm = NSAlarm(alarm) val nsAlarm = NSAlarm(alarm)
uiInteraction.addNotificationWithAction(injector, nsAlarm) uiInteraction.addNotificationWithAction(injector, nsAlarm)
} }
rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received"))) rxBus.send(EventNSClientNewLog("ALARM", safeGetString(alarm, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
} }
} }
@ -664,7 +641,7 @@ class NSClientService : DaggerService() {
val nsAlarm = NSAlarm(alarm) val nsAlarm = NSAlarm(alarm)
uiInteraction.addNotificationWithAction(injector, nsAlarm) uiInteraction.addNotificationWithAction(injector, nsAlarm)
} }
rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received"))) rxBus.send(EventNSClientNewLog("URGENTALARM", safeGetString(alarm, "message", "received")))
aapsLogger.debug(LTag.NSCLIENT, alarm.toString()) aapsLogger.debug(LTag.NSCLIENT, alarm.toString())
} }
} }

View file

@ -22,6 +22,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector.PairProfileSwitch
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsclient.acks.NSAddAck import info.nightscout.plugins.sync.nsclient.acks.NSAddAck
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
@ -39,7 +40,7 @@ class NSClientAddAckWorker(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var storeDataForDb: StoreDataForDb @Inject lateinit var storeDataForDb: StoreDataForDb
@ -60,148 +61,148 @@ class NSClientAddAckWorker(
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTemporaryTargets.add(pair.value) storeDataForDb.nsIdTemporaryTargets.add(pair.value)
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryTarget " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTempTargets() dataSyncSelectorV1.processChangedTempTargets()
} }
is PairGlucoseValue -> { is PairGlucoseValue -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdGlucoseValues.add(pair.value) storeDataForDb.nsIdGlucoseValues.add(pair.value)
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked GlucoseValue " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedGlucoseValues() dataSyncSelectorV1.processChangedGlucoseValues()
} }
is PairFood -> { is PairFood -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdFoods.add(pair.value) storeDataForDb.nsIdFoods.add(pair.value)
dataSyncSelector.confirmLastFoodIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked Food " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedFoods() dataSyncSelectorV1.processChangedFoods()
} }
is PairTherapyEvent -> { is PairTherapyEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTherapyEvents.add(pair.value) storeDataForDb.nsIdTherapyEvents.add(pair.value)
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked TherapyEvent " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTherapyEvents() dataSyncSelectorV1.processChangedTherapyEvents()
} }
is PairBolus -> { is PairBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdBoluses.add(pair.value) storeDataForDb.nsIdBoluses.add(pair.value)
dataSyncSelector.confirmLastBolusIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked Bolus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedBoluses() dataSyncSelectorV1.processChangedBoluses()
} }
is PairCarbs -> { is PairCarbs -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdCarbs.add(pair.value) storeDataForDb.nsIdCarbs.add(pair.value)
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked Carbs " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedCarbs() dataSyncSelectorV1.processChangedCarbs()
} }
is PairBolusCalculatorResult -> { is PairBolusCalculatorResult -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdBolusCalculatorResults.add(pair.value) storeDataForDb.nsIdBolusCalculatorResults.add(pair.value)
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked BolusCalculatorResult " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResults() dataSyncSelectorV1.processChangedBolusCalculatorResults()
} }
is PairTemporaryBasal -> { is PairTemporaryBasal -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdTemporaryBasals.add(pair.value) storeDataForDb.nsIdTemporaryBasals.add(pair.value)
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked TemporaryBasal " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTemporaryBasals() dataSyncSelectorV1.processChangedTemporaryBasals()
} }
is PairExtendedBolus -> { is PairExtendedBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdExtendedBoluses.add(pair.value) storeDataForDb.nsIdExtendedBoluses.add(pair.value)
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked ExtendedBolus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedExtendedBoluses() dataSyncSelectorV1.processChangedExtendedBoluses()
} }
is PairProfileSwitch -> { is PairProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdProfileSwitches.add(pair.value) storeDataForDb.nsIdProfileSwitches.add(pair.value)
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedProfileSwitches() dataSyncSelectorV1.processChangedProfileSwitches()
} }
is PairEffectiveProfileSwitch -> { is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value) storeDataForDb.nsIdEffectiveProfileSwitches.add(pair.value)
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked EffectiveProfileSwitch " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitches() dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
} }
is DataSyncSelector.PairDeviceStatus -> { is DataSyncSelector.PairDeviceStatus -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdDeviceStatuses.add(pair.value) storeDataForDb.nsIdDeviceStatuses.add(pair.value)
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(pair.value.id) dataSyncSelectorV1.confirmLastDeviceStatusIdIfGreater(pair.value.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked DeviceStatus " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedDeviceStatuses() dataSyncSelectorV1.processChangedDeviceStatuses()
} }
is PairProfileStore -> { is PairProfileStore -> {
dataSyncSelector.confirmLastProfileStore(ack.originalObject.id) dataSyncSelectorV1.confirmLastProfileStore(ack.originalObject.id)
rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id)) rxBus.send(EventNSClientNewLog("DBADD", "Acked ProfileStore " + ack.id))
} }
is PairOfflineEvent -> { is PairOfflineEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
pair.value.interfaceIDs.nightscoutId = ack.id pair.value.interfaceIDs.nightscoutId = ack.id
storeDataForDb.nsIdOfflineEvents.add(pair.value) storeDataForDb.nsIdOfflineEvents.add(pair.value)
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
storeDataForDb.scheduleNsIdUpdate() storeDataForDb.scheduleNsIdUpdate()
rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId)) rxBus.send(EventNSClientNewLog("DBADD", "Acked OfflineEvent " + pair.value.interfaceIDs.nightscoutId))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedOfflineEvents() dataSyncSelectorV1.processChangedOfflineEvents()
} }
} }

View file

@ -6,7 +6,6 @@ import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelector.PairBolus import info.nightscout.interfaces.sync.DataSyncSelector.PairBolus
import info.nightscout.interfaces.sync.DataSyncSelector.PairBolusCalculatorResult import info.nightscout.interfaces.sync.DataSyncSelector.PairBolusCalculatorResult
import info.nightscout.interfaces.sync.DataSyncSelector.PairCarbs import info.nightscout.interfaces.sync.DataSyncSelector.PairCarbs
@ -19,6 +18,7 @@ import info.nightscout.interfaces.sync.DataSyncSelector.PairProfileSwitch
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryBasal
import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget import info.nightscout.interfaces.sync.DataSyncSelector.PairTemporaryTarget
import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent import info.nightscout.interfaces.sync.DataSyncSelector.PairTherapyEvent
import info.nightscout.interfaces.sync.DataSyncSelectorV1
import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck import info.nightscout.plugins.sync.nsclient.acks.NSUpdateAck
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
@ -34,7 +34,7 @@ class NSClientUpdateRemoveAckWorker(
@Inject lateinit var dataWorkerStorage: DataWorkerStorage @Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelectorV1: DataSyncSelectorV1
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
@ -47,109 +47,109 @@ class NSClientUpdateRemoveAckWorker(
when (ack.originalObject) { when (ack.originalObject) {
is PairTemporaryTarget -> { is PairTemporaryTarget -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTempTargetsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTempTargetsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryTarget" + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTempTargets() dataSyncSelectorV1.processChangedTempTargets()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairGlucoseValue -> { is PairGlucoseValue -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastGlucoseValueIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked GlucoseValue " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedGlucoseValues() dataSyncSelectorV1.processChangedGlucoseValues()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairFood -> { is PairFood -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastFoodIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastFoodIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Food " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedFoods() dataSyncSelectorV1.processChangedFoods()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairTherapyEvent -> { is PairTherapyEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTherapyEventIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTherapyEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TherapyEvent " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTherapyEvents() dataSyncSelectorV1.processChangedTherapyEvents()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairBolus -> { is PairBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastBolusIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Bolus " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedBoluses() dataSyncSelectorV1.processChangedBoluses()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairCarbs -> { is PairCarbs -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastCarbsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastCarbsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked Carbs " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedCarbs() dataSyncSelectorV1.processChangedCarbs()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairBolusCalculatorResult -> { is PairBolusCalculatorResult -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastBolusCalculatorResultsIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked BolusCalculatorResult " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedBolusCalculatorResults() dataSyncSelectorV1.processChangedBolusCalculatorResults()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairTemporaryBasal -> { is PairTemporaryBasal -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastTemporaryBasalIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked TemporaryBasal " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedTemporaryBasals() dataSyncSelectorV1.processChangedTemporaryBasals()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairExtendedBolus -> { is PairExtendedBolus -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastExtendedBolusIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ExtendedBolus " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedExtendedBoluses() dataSyncSelectorV1.processChangedExtendedBoluses()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairProfileSwitch -> { is PairProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked ProfileSwitch " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedProfileSwitches() dataSyncSelectorV1.processChangedProfileSwitches()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairEffectiveProfileSwitch -> { is PairEffectiveProfileSwitch -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastEffectiveProfileSwitchIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked EffectiveProfileSwitch " + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedEffectiveProfileSwitches() dataSyncSelectorV1.processChangedEffectiveProfileSwitches()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
is PairOfflineEvent -> { is PairOfflineEvent -> {
val pair = ack.originalObject val pair = ack.originalObject
dataSyncSelector.confirmLastOfflineEventIdIfGreater(pair.id) dataSyncSelectorV1.confirmLastOfflineEventIdIfGreater(pair.id)
rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id)) rxBus.send(EventNSClientNewLog("DBUPDATE", "Acked OfflineEvent" + ack._id))
// Send new if waiting // Send new if waiting
dataSyncSelector.processChangedOfflineEvents() dataSyncSelectorV1.processChangedOfflineEvents()
ret = Result.success(workDataOf("ProcessedData" to pair.toString())) ret = Result.success(workDataOf("ProcessedData" to pair.toString()))
} }
} }

View file

@ -0,0 +1,695 @@
package info.nightscout.plugins.sync.nsclientV3
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiQueue
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import javax.inject.Inject
import javax.inject.Singleton
@OpenForTesting
@Singleton
class DataSyncSelectorV3Impl @Inject constructor(
private val sp: SP,
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val profileFunction: ProfileFunction,
private val activePlugin: ActivePlugin,
private val appRepository: AppRepository,
private val rxBus: RxBus,
private val storeDataForDb: StoreDataForDb
) : DataSyncSelectorV3 {
class QueueCounter(
var bolusesRemaining: Long = -1L,
var carbsRemaining: Long = -1L,
var bcrRemaining: Long = -1L,
var ttsRemaining: Long = -1L,
var foodsRemaining: Long = -1L,
var gvsRemaining: Long = -1L,
var tesRemaining: Long = -1L,
var dssRemaining: Long = -1L,
var tbrsRemaining: Long = -1L,
var ebsRemaining: Long = -1L,
var pssRemaining: Long = -1L,
var epssRemaining: Long = -1L,
var oesRemaining: Long = -1L
) {
fun size(): Long =
bolusesRemaining +
carbsRemaining +
bcrRemaining +
ttsRemaining +
foodsRemaining +
gvsRemaining +
tesRemaining +
dssRemaining +
tbrsRemaining +
ebsRemaining +
pssRemaining +
epssRemaining +
oesRemaining
}
private val queueCounter = QueueCounter()
private val isPaused get() = sp.getBoolean(R.string.key_ns_paused, false)
override fun queueSize(): Long = queueCounter.size()
override suspend fun doUpload() {
rxBus.send(EventNSClientUpdateGuiStatus())
if (sp.getBoolean(R.string.key_ns_upload, true) && !isPaused) {
queueCounter.bolusesRemaining = (appRepository.getLastBolusId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
queueCounter.carbsRemaining = (appRepository.getLastCarbsId() ?: 0L) - sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
queueCounter.bcrRemaining = (appRepository.getLastBolusCalculatorResultId() ?: 0L) - sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
queueCounter.ttsRemaining = (appRepository.getLastTempTargetId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
queueCounter.foodsRemaining = (appRepository.getLastFoodId() ?: 0L) - sp.getLong(R.string.key_ns_food_last_synced_id, 0)
queueCounter.gvsRemaining = (appRepository.getLastGlucoseValueId() ?: 0L) - sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
queueCounter.tesRemaining = (appRepository.getLastTherapyEventId() ?: 0L) - sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
queueCounter.dssRemaining = (appRepository.getLastDeviceStatusId() ?: 0L) - sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
queueCounter.tbrsRemaining = (appRepository.getLastTemporaryBasalId() ?: 0L) - sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
queueCounter.ebsRemaining = (appRepository.getLastExtendedBolusId() ?: 0L) - sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
queueCounter.pssRemaining = (appRepository.getLastProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
queueCounter.epssRemaining = (appRepository.getLastEffectiveProfileSwitchId() ?: 0L) - sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
queueCounter.oesRemaining = (appRepository.getLastOfflineEventId() ?: 0L) - sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
rxBus.send(EventNSClientUpdateGuiQueue())
processChangedGlucoseValues()
processChangedBoluses()
processChangedCarbs()
processChangedBolusCalculatorResults()
processChangedTemporaryBasals()
processChangedExtendedBoluses()
processChangedProfileSwitches()
processChangedEffectiveProfileSwitches()
processChangedTempTargets()
processChangedFoods()
processChangedTherapyEvents()
processChangedDeviceStatuses()
processChangedOfflineEvents()
processChangedProfileStore()
storeDataForDb.updateNsIds()
}
rxBus.send(EventNSClientUpdateGuiStatus())
}
override fun resetToNextFullSync() {
sp.remove(R.string.key_ns_glucose_value_last_synced_id)
sp.remove(R.string.key_ns_temporary_basal_last_synced_id)
sp.remove(R.string.key_ns_temporary_target_last_synced_id)
sp.remove(R.string.key_ns_extended_bolus_last_synced_id)
sp.remove(R.string.key_ns_food_last_synced_id)
sp.remove(R.string.key_ns_bolus_last_synced_id)
sp.remove(R.string.key_ns_carbs_last_synced_id)
sp.remove(R.string.key_ns_bolus_calculator_result_last_synced_id)
sp.remove(R.string.key_ns_therapy_event_last_synced_id)
sp.remove(R.string.key_ns_profile_switch_last_synced_id)
sp.remove(R.string.key_ns_effective_profile_switch_last_synced_id)
sp.remove(R.string.key_ns_offline_event_last_synced_id)
sp.remove(R.string.key_ns_profile_store_last_synced_timestamp)
val lastDeviceStatusDbId = appRepository.getLastDeviceStatusId()
if (lastDeviceStatusDbId != null) sp.putLong(R.string.key_ns_device_status_last_synced_id, lastDeviceStatusDbId)
else sp.remove(R.string.key_ns_device_status_last_synced_id)
}
fun confirmLastBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Bolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_last_synced_id, lastSynced)
}
}
suspend fun processChangedBoluses() {
val lastDbId = appRepository.getLastBolusId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_bolus_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.bolusesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolus(startId).blockingGet()?.let { bolus ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Bolus data Start: $startId ${bolus.first} forID: ${bolus.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
bolus.first.id == bolus.second.id && bolus.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Loaded from NS: ${bolus.second.id} ")
// only NsId changed, no need to upload
bolus.first.onlyNsIdAdded(bolus.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Bolus. Only NS id changed: ${bolus.second.id} ")
// without nsId = create new
bolus.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), " $startId/$lastDbId") ?: false
// with nsId = update if it's modified record
bolus.first.interfaceIDs.nightscoutId != null && bolus.first.id != bolus.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairBolus(bolus.first, bolus.second.id), "$startId/$lastDbId") ?: false
}
confirmLastBolusIdIfGreater(bolus.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Carbs data sync from $lastSynced")
sp.putLong(R.string.key_ns_carbs_last_synced_id, lastSynced)
}
}
suspend fun processChangedCarbs() {
val lastDbId = appRepository.getLastCarbsId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_carbs_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_carbs_last_synced_id, 0)
startId = 0
}
queueCounter.carbsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementCarbs(startId).blockingGet()?.let { carb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Carbs data Start: $startId ${carb.first} forID: ${carb.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
carb.first.id == carb.second.id && carb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Loaded from NS: ${carb.second.id} ")
// only NsId changed, no need to upload
carb.first.onlyNsIdAdded(carb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Carbs. Only NS id changed ID: ${carb.second.id} ")
// without nsId = create new
carb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update if it's modified record
carb.first.interfaceIDs.nightscoutId != null && carb.first.id != carb.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairCarbs(carb.first, carb.second.id), "$startId/$lastDbId") ?: false
}
confirmLastCarbsIdIfGreater(carb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting BolusCalculatorResult data sync from $lastSynced")
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, lastSynced)
}
}
suspend fun processChangedBolusCalculatorResults() {
val lastDbId = appRepository.getLastBolusCalculatorResultId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_bolus_calculator_result_last_synced_id, 0)
startId = 0
}
queueCounter.bcrRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementBolusCalculatorResult(startId).blockingGet()?.let { bolusCalculatorResult ->
//aapsLogger.info(LTag.NSCLIENT, "Loading BolusCalculatorResult data Start: $startId ${bolusCalculatorResult.first} forID: ${bolusCalculatorResult.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
bolusCalculatorResult.first.id == bolusCalculatorResult.second.id && bolusCalculatorResult.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Loaded from NS: ${bolusCalculatorResult.second.id} ")
// only NsId changed, no need to upload
bolusCalculatorResult.first.onlyNsIdAdded(bolusCalculatorResult.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring BolusCalculatorResult. Only NS id changed ID: ${bolusCalculatorResult.second.id} ")
// without nsId = create new
bolusCalculatorResult.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
) ?: false
// with nsId = update if it's modified record
bolusCalculatorResult.first.interfaceIDs.nightscoutId != null && bolusCalculatorResult.first.id != bolusCalculatorResult.second.id ->
cont = activePlugin.activeNsClient?.nsUpdate(
"treatments",
DataSyncSelector.PairBolusCalculatorResult(bolusCalculatorResult.first, bolusCalculatorResult.second.id),
"$startId/$lastDbId"
) ?: false
}
confirmLastBolusCalculatorResultsIdIfGreater(bolusCalculatorResult.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryTarget data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, lastSynced)
}
}
suspend fun processChangedTempTargets() {
val lastDbId = appRepository.getLastTempTargetId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_temporary_target_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_target_last_synced_id, 0)
startId = 0
}
queueCounter.ttsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryTarget(startId).blockingGet()?.let { tt ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryTarget data Start: $startId ${tt.first} forID: ${tt.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
tt.first.id == tt.second.id && tt.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Loaded from NS: ${tt.second.id} ")
// only NsId changed, no need to upload
tt.first.onlyNsIdAdded(tt.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryTarget. Only NS id changed ID: ${tt.second.id} ")
// without nsId = create new
tt.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId") ?: false
// existing with nsId = update
tt.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryTarget(tt.first, tt.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTempTargetsIdIfGreater(tt.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastFoodIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_food_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting Food data sync from $lastSynced")
sp.putLong(R.string.key_ns_food_last_synced_id, lastSynced)
}
}
suspend fun processChangedFoods() {
val lastDbId = appRepository.getLastFoodId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_food_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_food_last_synced_id, 0)
startId = 0
}
queueCounter.foodsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementFood(startId).blockingGet()?.let { food ->
//aapsLogger.info(LTag.NSCLIENT, "Loading Food data Start: $startId ${food.first} forID: ${food.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
food.first.id == food.second.id && food.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Loaded from NS: ${food.second.id} ")
// only NsId changed, no need to upload
food.first.onlyNsIdAdded(food.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring Food. Only NS id changed ID: ${food.second.id} ")
// without nsId = create new
food.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
food.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("food", DataSyncSelector.PairFood(food.first, food.second.id), "$startId/$lastDbId") ?: false
}
confirmLastFoodIdIfGreater(food.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting GlucoseValue data sync from $lastSynced")
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, lastSynced)
}
}
suspend fun processChangedGlucoseValues() {
val lastDbId = appRepository.getLastGlucoseValueId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_glucose_value_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_glucose_value_last_synced_id, 0)
startId = 0
}
queueCounter.gvsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementGlucoseValue(startId).blockingGet()?.let { gv ->
//aapsLogger.info(LTag.NSCLIENT, "Loading GlucoseValue data Start: $startId ${gv.first} forID: ${gv.second.id} ")
if (activePlugin.activeBgSource.shouldUploadToNs(gv.first)) {
when {
// new record with existing NS id => must be coming from NS => ignore
gv.first.id == gv.second.id && gv.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Loaded from NS: ${gv.second.id} ")
// only NsId changed, no need to upload
gv.first.onlyNsIdAdded(gv.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring GlucoseValue. Only NS id changed ID: ${gv.second.id} ")
// without nsId = create new
gv.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
else -> // gv.first.interfaceIDs.nightscoutId != null
cont = activePlugin.activeNsClient?.nsUpdate("entries", DataSyncSelector.PairGlucoseValue(gv.first, gv.second.id), "$startId/$lastDbId") ?: false
}
}
confirmLastGlucoseValueIdIfGreater(gv.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TherapyEvents data sync from $lastSynced")
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, lastSynced)
}
}
suspend fun processChangedTherapyEvents() {
val lastDbId = appRepository.getLastTherapyEventId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_therapy_event_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_therapy_event_last_synced_id, 0)
startId = 0
}
queueCounter.tesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTherapyEvent(startId).blockingGet()?.let { te ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TherapyEvents data Start: $startId ${te.first} forID: ${te.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
te.first.id == te.second.id && te.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Loaded from NS: ${te.second.id} ")
// only NsId changed, no need to upload
te.first.onlyNsIdAdded(te.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TherapyEvent. Only NS id changed ID: ${te.second.id} ")
// without nsId = create new
te.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") ?: false
// nsId = update
te.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTherapyEvent(te.first, te.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTherapyEventIdIfGreater(te.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting DeviceStatus data sync from $lastSynced")
sp.putLong(R.string.key_ns_device_status_last_synced_id, lastSynced)
}
}
suspend fun processChangedDeviceStatuses() {
if (isPaused) return
val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
var startId = sp.getLong(R.string.key_ns_device_status_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_device_status_last_synced_id, 0)
startId = 0
}
queueCounter.dssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementDeviceStatus(startId).blockingGet()?.let { deviceStatus ->
//aapsLogger.info(LTag.NSCLIENT, "Loading DeviceStatus data Start: $startId $deviceStatus")
// without nsId = create new
if (deviceStatus.interfaceIDs.nightscoutId == null) {
if (activePlugin.activeNsClient?.nsAdd("devicestatus", DataSyncSelector.PairDeviceStatus(deviceStatus, lastDbId), "$startId/$lastDbId") == true)
confirmLastDeviceStatusIdIfGreater(lastDbId)
}
// with nsId = ignore
}
queueCounter.dssRemaining = 0
}
fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting TemporaryBasal data sync from $lastSynced")
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, lastSynced)
}
}
suspend fun processChangedTemporaryBasals() {
val lastDbId = appRepository.getLastTemporaryBasalId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_temporary_basal_last_synced_id, 0)
startId = 0
}
queueCounter.tbrsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementTemporaryBasal(startId).blockingGet()?.let { tb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading TemporaryBasal data Start: $startId ${tb.first} forID: ${tb.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
tb.first.id == tb.second.id && tb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Loaded from NS: ${tb.second.id} ")
// only NsId changed, no need to upload
tb.first.onlyNsIdAdded(tb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring TemporaryBasal. Only NS id changed ID: ${tb.second.id} ")
// without nsId = create new
tb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
tb.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairTemporaryBasal(tb.first, tb.second.id), "$startId/$lastDbId") ?: false
}
confirmLastTemporaryBasalIdIfGreater(tb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting ExtendedBolus data sync from $lastSynced")
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, lastSynced)
}
}
suspend fun processChangedExtendedBoluses() {
val lastDbId = appRepository.getLastExtendedBolusId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_extended_bolus_last_synced_id, 0)
startId = 0
}
queueCounter.ebsRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementExtendedBolus(startId).blockingGet()?.let { eb ->
//aapsLogger.info(LTag.NSCLIENT, "Loading ExtendedBolus data Start: $startId ${eb.first} forID: ${eb.second.id} ")
val profile = profileFunction.getProfile(eb.first.timestamp)
if (profile != null) {
when {
// new record with existing NS id => must be coming from NS => ignore
eb.first.id == eb.second.id && eb.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Loaded from NS: ${eb.second.id} ")
// only NsId changed, no need to upload
eb.first.onlyNsIdAdded(eb.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. Only NS id changed ID: ${eb.second.id} ")
// without nsId = create new
eb.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
eb.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairExtendedBolus(eb.first, eb.second.id), "$startId/$lastDbId") ?: false
}
} else aapsLogger.info(LTag.NSCLIENT, "Ignoring ExtendedBolus. No profile: ${eb.second.id} ")
confirmLastExtendedBolusIdIfGreater(eb.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting ProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, lastSynced)
}
}
suspend fun processChangedProfileSwitches() {
val lastDbId = appRepository.getLastProfileSwitchId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.pssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementProfileSwitch(startId).blockingGet()?.let { ps ->
//aapsLogger.info(LTag.NSCLIENT, "Loading ProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Loaded from NS: ${ps.second.id} ")
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring ProfileSwitch. Only NS id changed ID: ${ps.second.id} ")
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
}
confirmLastProfileSwitchIdIfGreater(ps.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting EffectiveProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, lastSynced)
}
}
suspend fun processChangedEffectiveProfileSwitches() {
val lastDbId = appRepository.getLastEffectiveProfileSwitchId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_effective_profile_switch_last_synced_id, 0)
startId = 0
}
queueCounter.epssRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementEffectiveProfileSwitch(startId).blockingGet()?.let { ps ->
//aapsLogger.info(LTag.NSCLIENT, "Loading EffectiveProfileSwitch data Start: $startId ${ps.first} forID: ${ps.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
ps.first.id == ps.second.id && ps.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Loaded from NS: ${ps.second.id} ")
// only NsId changed, no need to upload
ps.first.onlyNsIdAdded(ps.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring EffectiveProfileSwitch. Only NS id changed ID: ${ps.second.id} ")
// without nsId = create new
ps.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
// with nsId = update
ps.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairEffectiveProfileSwitch(ps.first, ps.second.id), "$startId/$lastDbId") ?: false
}
confirmLastEffectiveProfileSwitchIdIfGreater(ps.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.NSCLIENT, "Setting OfflineEvent data sync from $lastSynced")
sp.putLong(R.string.key_ns_offline_event_last_synced_id, lastSynced)
}
}
suspend fun processChangedOfflineEvents() {
val lastDbId = appRepository.getLastOfflineEventId() ?: 0L
var cont = true
while (cont) {
if (isPaused) return
var startId = sp.getLong(R.string.key_ns_offline_event_last_synced_id, 0)
if (startId > lastDbId) {
sp.putLong(R.string.key_ns_offline_event_last_synced_id, 0)
startId = 0
}
queueCounter.oesRemaining = lastDbId - startId
rxBus.send(EventNSClientUpdateGuiQueue())
appRepository.getNextSyncElementOfflineEvent(startId).blockingGet()?.let { oe ->
//aapsLogger.info(LTag.NSCLIENT, "Loading OfflineEvent data Start: $startId ${oe.first} forID: ${oe.second.id} ")
when {
// new record with existing NS id => must be coming from NS => ignore
oe.first.id == oe.second.id && oe.first.interfaceIDs.nightscoutId != null ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Loaded from NS: ${oe.second.id} ")
// only NsId changed, no need to upload
oe.first.onlyNsIdAdded(oe.second) ->
aapsLogger.info(LTag.NSCLIENT, "Ignoring OfflineEvent. Only NS id changed ID: ${oe.second.id} ")
// without nsId = create new
oe.first.interfaceIDs.nightscoutId == null ->
cont = activePlugin.activeNsClient?.nsAdd("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") ?: false
// existing with nsId = update
oe.first.interfaceIDs.nightscoutId != null ->
cont = activePlugin.activeNsClient?.nsUpdate("treatments", DataSyncSelector.PairOfflineEvent(oe.first, oe.second.id), "$startId/$lastDbId") ?: false
}
confirmLastOfflineEventIdIfGreater(oe.second.id)
} ?: run {
cont = false
}
}
}
fun confirmLastProfileStore(lastSynced: Long) {
sp.putLong(R.string.key_ns_profile_store_last_synced_timestamp, lastSynced)
}
suspend fun processChangedProfileStore() {
if (isPaused) return
val lastSync = sp.getLong(R.string.key_ns_profile_store_last_synced_timestamp, 0)
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
if (lastChange == 0L) return
if (lastChange > lastSync) {
if (activePlugin.activeProfileSource.profile?.allProfilesValid != true) return
val profileStore = activePlugin.activeProfileSource.profile
val profileJson = profileStore?.data ?: return
// add for v3
if (JsonHelper.safeGetLongAllowNull(profileJson, "date") == null)
profileJson.put("date", profileStore.getStartDate())
val now = dateUtil.now()
if (activePlugin.activeNsClient?.nsAdd("profile", DataSyncSelector.PairProfileStore(profileJson, now), "") == true)
confirmLastProfileStore(now)
}
}
}

View file

@ -4,7 +4,6 @@ import android.content.Context
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.SystemClock import android.os.SystemClock
import android.text.Spanned
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
@ -17,7 +16,6 @@ import com.google.gson.GsonBuilder
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.database.ValueWrapper import info.nightscout.database.ValueWrapper
import info.nightscout.database.entities.interfaces.TraceableDBEntry import info.nightscout.database.entities.interfaces.TraceableDBEntry
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
@ -25,23 +23,24 @@ import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.notifications.Notification import info.nightscout.interfaces.notifications.Notification
import info.nightscout.interfaces.nsclient.NSAlarm import info.nightscout.interfaces.nsclient.NSAlarm
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.PluginBase import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.plugin.PluginDescription import info.nightscout.interfaces.plugin.PluginDescription
import info.nightscout.interfaces.plugin.PluginType import info.nightscout.interfaces.plugin.PluginType
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.HtmlHelper
import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsShared.NSClientFragment import info.nightscout.plugins.sync.nsShared.NSClientFragment
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged import info.nightscout.plugins.sync.nsShared.events.EventConnectivityOptionChanged
import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend import info.nightscout.plugins.sync.nsShared.events.EventNSClientResend
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiInsert
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolus import info.nightscout.plugins.sync.nsclientV3.extensions.toNSBolus
@ -59,10 +58,12 @@ import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget
import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTherapyEvent import info.nightscout.plugins.sync.nsclientV3.extensions.toNSTherapyEvent
import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker import info.nightscout.plugins.sync.nsclientV3.workers.DataSyncWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadBgWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadFoodsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadLastModificationWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadProfileStoreWorker
import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadStatusWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessFoodWorker import info.nightscout.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import info.nightscout.plugins.sync.nsclientV3.workers.ProcessTreatmentsWorker
import info.nightscout.rx.AapsSchedulers import info.nightscout.rx.AapsSchedulers
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventAppExit import info.nightscout.rx.events.EventAppExit
@ -90,18 +91,16 @@ import io.socket.client.Ack
import io.socket.client.IO import io.socket.client.IO
import io.socket.client.Socket import io.socket.client.Socket
import io.socket.emitter.Emitter import io.socket.emitter.Emitter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.net.URISyntaxException import java.net.URISyntaxException
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Suppress("SpellCheckingInspection")
@OpenForTesting @OpenForTesting
@Singleton @Singleton
class NSClientV3Plugin @Inject constructor( class NSClientV3Plugin @Inject constructor(
@ -117,14 +116,13 @@ class NSClientV3Plugin @Inject constructor(
private val config: Config, private val config: Config,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val uiInteraction: UiInteraction, private val uiInteraction: UiInteraction,
private val dataSyncSelector: DataSyncSelector, private val dataSyncSelectorV3: DataSyncSelectorV3,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val repository: AppRepository, private val repository: AppRepository,
private val nsDeviceStatusHandler: NSDeviceStatusHandler, private val nsDeviceStatusHandler: NSDeviceStatusHandler,
private val workManager: WorkManager, private val nsClientSource: NSClientSource,
private val workerClasses: WorkerClasses, private val nsIncomingDataProcessor: NsIncomingDataProcessor,
private val dataWorkerStorage: DataWorkerStorage, private val storeDataForDb: StoreDataForDb
private val nsClientSource: NSClientSource
) : NsClient, Sync, PluginBase( ) : NsClient, Sync, PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.SYNC) .mainType(PluginType.SYNC)
@ -146,10 +144,10 @@ class NSClientV3Plugin @Inject constructor(
} }
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
var scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private lateinit var runLoop: Runnable private lateinit var runLoop: Runnable
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventNSClientNewLog> = ArrayList() override val listLog: MutableList<EventNSClientNewLog> = ArrayList()
override val dataSyncSelector: DataSyncSelector get() = dataSyncSelectorV3
override val status override val status
get() = get() =
when { when {
@ -159,7 +157,7 @@ class NSClientV3Plugin @Inject constructor(
sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true) && !wsConnected -> "WS: " + rh.gs(R.string.not_connected) sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true) && !wsConnected -> "WS: " + rh.gs(R.string.not_connected)
lastOperationError != null -> rh.gs(info.nightscout.core.ui.R.string.error) lastOperationError != null -> rh.gs(info.nightscout.core.ui.R.string.error)
nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected) nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected)
workIsRunning(arrayOf(JOB_NAME)) -> rh.gs(R.string.working) workIsRunning() -> rh.gs(R.string.working)
nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected) nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected)
nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only) nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only)
else -> rh.gs(info.nightscout.core.ui.R.string.unknown) else -> rh.gs(info.nightscout.core.ui.R.string.unknown)
@ -196,6 +194,7 @@ class NSClientV3Plugin @Inject constructor(
rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason)) rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason))
setClient("CONNECTIVITY") setClient("CONNECTIVITY")
if (isAllowed) executeLoop("CONNECTIVITY", forceNew = false) if (isAllowed) executeLoop("CONNECTIVITY", forceNew = false)
rxBus.send(EventNSClientUpdateGuiStatus())
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventPreferenceChange::class.java) .toObservable(EventPreferenceChange::class.java)
@ -290,10 +289,14 @@ class NSClientV3Plugin @Inject constructor(
override val hasWritePermission: Boolean get() = nsAndroidClient?.lastStatus?.apiPermissions?.isFull() ?: false override val hasWritePermission: Boolean get() = nsAndroidClient?.lastStatus?.apiPermissions?.isFull() ?: false
override val connected: Boolean get() = nsAndroidClient?.lastStatus != null override val connected: Boolean get() = nsAndroidClient?.lastStatus != null
override fun clearLog() { private fun addToLog(ev: EventNSClientNewLog) {
handler.post { synchronized(listLog) {
synchronized(listLog) { listLog.clear() } listLog.add(0, ev)
rxBus.send(EventNSClientUpdateGUI()) rxBus.send(EventNSClientUpdateGuiInsert(0))
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(listLog.size - 1)
}
} }
} }
@ -433,40 +436,21 @@ class NSClientV3Plugin @Inject constructor(
when (collection) { when (collection) {
"devicestatus" -> docString.toNSDeviceStatus().let { nsDeviceStatusHandler.handleNewData(arrayOf(it)) } "devicestatus" -> docString.toNSDeviceStatus().let { nsDeviceStatusHandler.handleNewData(arrayOf(it)) }
"entries" -> docString.toNSSgvV3()?.let { "entries" -> docString.toNSSgvV3()?.let {
workManager.beginUniqueWork( nsIncomingDataProcessor.processSgvs(listOf(it))
JOB_NAME + collection, storeDataForDb.storeGlucoseValuesToDb()
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build()
)
.then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build())
.enqueue()
} }
"profile" -> "profile" ->
workManager.enqueueUniqueWork( nsIncomingDataProcessor.processProfile(docJson)
JOB_NAME + collection,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(workerClasses.nsProfileWorker).setInputData(dataWorkerStorage.storeInputData(docJson)).build()
)
"treatments" -> docString.toNSTreatment()?.let { "treatments" -> docString.toNSTreatment()?.let {
workManager.beginUniqueWork( nsIncomingDataProcessor.processTreatments(listOf(it))
JOB_NAME + collection, storeDataForDb.storeTreatmentsToDb()
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build()
)
.then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build())
.enqueue()
} }
"foods" -> docString.toNSFood()?.let { "foods" -> docString.toNSFood()?.let {
workManager.beginUniqueWork( nsIncomingDataProcessor.processFood(listOf(it))
JOB_NAME + collection, storeDataForDb.storeFoodsToDb()
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java).setInputData(dataWorkerStorage.storeInputData(listOf(it))).build()
)
.then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
.enqueue()
} }
"settings" -> {} "settings" -> {}
@ -565,30 +549,6 @@ class NSClientV3Plugin @Inject constructor(
WS code end WS code end
**********************/ **********************/
private fun addToLog(ev: EventNSClientNewLog) {
synchronized(listLog) {
listLog.add(ev)
// remove the first line if log is too large
if (listLog.size >= Constants.MAX_LOG_LINES) {
listLog.removeAt(0)
}
}
rxBus.send(EventNSClientUpdateGUI())
}
override fun textLog(): Spanned {
try {
val newTextLog = StringBuilder()
synchronized(listLog) {
for (log in listLog) newTextLog.append(log.toPreparedHtml())
}
return HtmlHelper.fromHtml(newTextLog.toString())
} catch (e: OutOfMemoryError) {
uiInteraction.showToastAndNotification(context, "Out of memory!\nStop using this phone !!!", info.nightscout.core.ui.R.raw.error)
}
return HtmlHelper.fromHtml("")
}
override fun resend(reason: String) { override fun resend(reason: String) {
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true)) if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_use_ws, true))
executeUpload("RESEND", forceNew = false) executeUpload("RESEND", forceNew = false)
@ -596,10 +556,10 @@ class NSClientV3Plugin @Inject constructor(
executeLoop("RESEND", forceNew = false) executeLoop("RESEND", forceNew = false)
} }
override fun pause(newState: Boolean) { override fun pause(newState: Boolean) {
sp.putBoolean(R.string.key_ns_paused, newState) sp.putBoolean(R.string.key_ns_paused, newState)
rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_paused))) rxBus.send(EventPreferenceChange(rh.gs(R.string.key_ns_paused)))
} }
override fun detectedNsVersion(): String? = nsAndroidClient?.lastStatus?.version override fun detectedNsVersion(): String? = nsAndroidClient?.lastStatus?.version
@ -626,191 +586,165 @@ class NSClientV3Plugin @Inject constructor(
lastLoadedSrvModified = LastModified(LastModified.Collections()) lastLoadedSrvModified = LastModified(LastModified.Collections())
initialLoadFinished = false initialLoadFinished = false
storeLastLoadedSrvModified() storeLastLoadedSrvModified()
dataSyncSelector.resetToNextFullSync() dataSyncSelectorV3.resetToNextFullSync()
} }
override fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) { override suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean =
dbOperation(collection, dataPair, progress, Operation.CREATE) dbOperation(collection, dataPair, progress, Operation.CREATE)
}
override fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) { override suspend fun nsUpdate(collection: String, dataPair: DataSyncSelector.DataPair, progress: String): Boolean =
dbOperation(collection, dataPair, progress, Operation.UPDATE) dbOperation(collection, dataPair, progress, Operation.UPDATE)
}
enum class Operation { CREATE, UPDATE } enum class Operation { CREATE, UPDATE }
private val gson: Gson = GsonBuilder().create() private val gson: Gson = GsonBuilder().create()
private fun dbOperationProfileStore(collection: String = "profile", dataPair: DataSyncSelector.DataPair, progress: String) {
private suspend fun slowDown() {
if (sp.getBoolean(R.string.key_ns_sync_slow, false)) SystemClock.sleep(250)
else SystemClock.sleep(10)
}
private suspend fun dbOperationProfileStore(collection: String = "profile", dataPair: DataSyncSelector.DataPair, progress: String): Boolean {
val data = (dataPair as DataSyncSelector.PairProfileStore).value val data = (dataPair as DataSyncSelector.PairProfileStore).value
scope.launch { try {
try { rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} <i>$data</i> $progress"))
rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} <i>$data</i> $progress")) nsAndroidClient?.createProfileStore(data)?.let { result ->
nsAndroidClient?.createProfileStore(data)?.let { result -> when (result.response) {
when (result.response) { 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ProfileStore"))
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ProfileStore")) 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ProfileStore"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ProfileStore")) 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
else -> { else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "ProfileStore")) rxBus.send(EventNSClientNewLog("◄ ERROR", "ProfileStore"))
return@launch return true
}
} }
// if (result.response == 201) { // created
// dataPair.value.interfaceIDs.nightscoutId = result.identifier
// storeDataForDb.nsIdDeviceStatuses.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastProfileStore(dataPair.id)
dataSyncSelector.processChangedProfileStore()
} }
} catch (e: Exception) { slowDown()
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
return false
} }
return true
} }
private fun dbOperationDeviceStatus(collection: String = "devicestatus", dataPair: DataSyncSelector.DataPair, progress: String) { private suspend fun dbOperationDeviceStatus(collection: String = "devicestatus", dataPair: DataSyncSelector.PairDeviceStatus, progress: String): Boolean {
val data = (dataPair as DataSyncSelector.PairDeviceStatus).value.toNSDeviceStatus() try {
scope.launch { val data = dataPair.value.toNSDeviceStatus()
try { rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress"))
rxBus.send(EventNSClientNewLog("► ADD $collection", "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress")) nsAndroidClient?.createDeviceStatus(data)?.let { result ->
nsAndroidClient?.createDeviceStatus(data)?.let { result -> when (result.response) {
when (result.response) { 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}")) 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName} ${result.identifier}")) 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
else -> { else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} ")) rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
return@launch return true
}
} }
// if (result.response == 201) { // created
// dataPair.value.interfaceIDs.nightscoutId = result.identifier
// storeDataForDb.nsIdDeviceStatuses.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastDeviceStatusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedDeviceStatuses()
} }
} catch (e: Exception) { result.identifier?.let {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e) dataPair.value.interfaceIDs.nightscoutId = it
storeDataForDb.nsIdDeviceStatuses.add(dataPair.value)
}
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
} }
return true
} }
private fun dbOperationEntries(collection: String = "entries", dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) { private suspend fun dbOperationEntries(collection: String = "entries", dataPair: DataSyncSelector.PairGlucoseValue, progress: String, operation: Operation): Boolean {
val call = when (operation) { val call = when (operation) {
Operation.CREATE -> nsAndroidClient?.let { return@let it::createSvg } Operation.CREATE -> nsAndroidClient?.let { return@let it::createSgv }
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateSvg } Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateSvg }
} }
when (dataPair) { try {
is DataSyncSelector.PairGlucoseValue -> dataPair.value.toNSSvgV3() val data = dataPair.value.toNSSvgV3()
else -> null val id = dataPair.value.interfaceIDs.nightscoutId
}?.let { data -> rxBus.send(
scope.launch { EventNSClientNewLog(
try { when (operation) {
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else "" Operation.CREATE -> "► ADD $collection"
rxBus.send( Operation.UPDATE -> "► UPDATE $collection"
EventNSClientNewLog( },
when (operation) { when (operation) {
Operation.CREATE -> "► ADD $collection" Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress"
Operation.UPDATE -> "► UPDATE $collection" Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress"
}, }
when (operation) { )
Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress" )
Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress" call?.let { it(data) }?.let { result ->
} when (result.response) {
) 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
) 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}"))
call?.let { it(data) }?.let { result -> 400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
when (result.response) { 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}")) else -> {
400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) return true
else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
return@launch
}
}
when (dataPair) {
is DataSyncSelector.PairGlucoseValue -> {
// if (result.response == 201) { // created
// dataPair.value.interfaceIDs.nightscoutId = result.identifier
// storeDataForDb.nsIdGlucoseValues.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastGlucoseValueIdIfGreater(dataPair.id)
dataSyncSelector.processChangedGlucoseValues()
}
}
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
} }
result.identifier?.let {
dataPair.value.interfaceIDs.nightscoutId = it
storeDataForDb.nsIdGlucoseValues.add(dataPair.value)
}
slowDown()
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
return false
} }
return true
} }
private fun dbOperationFood(collection: String = "food", dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) { private suspend fun dbOperationFood(collection: String = "food", dataPair: DataSyncSelector.PairFood, progress: String, operation: Operation): Boolean {
val call = when (operation) { val call = when (operation) {
Operation.CREATE -> nsAndroidClient?.let { return@let it::createFood } Operation.CREATE -> nsAndroidClient?.let { return@let it::createFood }
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateFood } Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateFood }
} }
when (dataPair) { try {
is DataSyncSelector.PairFood -> dataPair.value.toNSFood() val data = dataPair.value.toNSFood()
else -> null val id = dataPair.value.interfaceIDs.nightscoutId
}?.let { data -> rxBus.send(
scope.launch { EventNSClientNewLog(
try { when (operation) {
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else "" Operation.CREATE -> "► ADD $collection"
rxBus.send( Operation.UPDATE -> "► UPDATE $collection"
EventNSClientNewLog( },
when (operation) { when (operation) {
Operation.CREATE -> "► ADD $collection" Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress"
Operation.UPDATE -> "► UPDATE $collection" Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress"
}, }
when (operation) { )
Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress" )
Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress" call?.let { it(data) }?.let { result ->
} when (result.response) {
) 200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
) 201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}"))
call?.let { it(data) }?.let { result -> 400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
when (result.response) { 404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}")) else -> {
400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}")) return true
else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
return@launch
}
}
when (dataPair) {
is DataSyncSelector.PairFood -> {
// if (result.response == 201) { // created
// dataPair.value.interfaceIDs.nightscoutId = result.identifier
// storeDataForDb.nsIdFoods.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastFoodIdIfGreater(dataPair.id)
dataSyncSelector.processChangedFoods()
}
}
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
} }
result.identifier?.let {
dataPair.value.interfaceIDs.nightscoutId = it
storeDataForDb.nsIdFoods.add(dataPair.value)
}
slowDown()
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
return false
} }
return true
} }
private fun dbOperationTreatments(collection: String = "treatments", dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) { private suspend fun dbOperationTreatments(collection: String = "treatments", dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation): Boolean {
val call = when (operation) { val call = when (operation) {
Operation.CREATE -> nsAndroidClient?.let { return@let it::createTreatment } Operation.CREATE -> nsAndroidClient?.let { return@let it::createTreatment }
Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateTreatment } Operation.UPDATE -> nsAndroidClient?.let { return@let it::updateTreatment }
@ -823,22 +757,12 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairTherapyEvent -> dataPair.value.toNSTherapyEvent() is DataSyncSelector.PairTherapyEvent -> dataPair.value.toNSTherapyEvent()
is DataSyncSelector.PairTemporaryBasal -> { is DataSyncSelector.PairTemporaryBasal -> {
val profile = profileFunction.getProfile(dataPair.value.timestamp) val profile = profileFunction.getProfile(dataPair.value.timestamp) ?: return true
if (profile == null) {
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTemporaryBasals()
return
}
dataPair.value.toNSTemporaryBasal(profile) dataPair.value.toNSTemporaryBasal(profile)
} }
is DataSyncSelector.PairExtendedBolus -> { is DataSyncSelector.PairExtendedBolus -> {
val profile = profileFunction.getProfile(dataPair.value.timestamp) val profile = profileFunction.getProfile(dataPair.value.timestamp) ?: return true
if (profile == null) {
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedExtendedBoluses()
return
}
dataPair.value.toNSExtendedBolus(profile) dataPair.value.toNSExtendedBolus(profile)
} }
@ -847,151 +771,109 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent() is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent()
else -> null else -> null
}?.let { data -> }?.let { data ->
scope.launch { try {
try { val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else ""
val id = if (dataPair.value is TraceableDBEntry) (dataPair.value as TraceableDBEntry).interfaceIDs.nightscoutId else "" rxBus.send(
rxBus.send( EventNSClientNewLog(
EventNSClientNewLog( when (operation) {
when (operation) { Operation.CREATE -> "► ADD $collection"
Operation.CREATE -> "► ADD $collection" Operation.UPDATE -> "► UPDATE $collection"
Operation.UPDATE -> "► UPDATE $collection" },
}, when (operation) {
when (operation) { Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress"
Operation.CREATE -> "Sent ${dataPair.javaClass.simpleName} <i>${gson.toJson(data)}</i> $progress" Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress"
Operation.UPDATE -> "Sent ${dataPair.javaClass.simpleName} $id <i>${gson.toJson(data)}</i> $progress"
}
)
)
call?.let { it(data) }?.let { result ->
when (result.response) {
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}"))
400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
return@launch
}
} }
)
)
call?.let { it(data) }?.let { result ->
when (result.response) {
200 -> rxBus.send(EventNSClientNewLog("◄ UPDATED", "OK ${dataPair.value.javaClass.simpleName}"))
201 -> rxBus.send(EventNSClientNewLog("◄ ADDED", "OK ${dataPair.value.javaClass.simpleName}"))
400 -> rxBus.send(EventNSClientNewLog("◄ FAIL", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
404 -> rxBus.send(EventNSClientNewLog("◄ NOT_FOUND", "${dataPair.value.javaClass.simpleName} ${result.errorResponse}"))
else -> {
rxBus.send(EventNSClientNewLog("◄ ERROR", "${dataPair.value.javaClass.simpleName} "))
return true
}
}
result.identifier?.let {
when (dataPair) { when (dataPair) {
is DataSyncSelector.PairBolus -> { is DataSyncSelector.PairBolus -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdBoluses.add(dataPair.value)
// storeDataForDb.nsIdBoluses.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedBoluses()
} }
is DataSyncSelector.PairCarbs -> { is DataSyncSelector.PairCarbs -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdCarbs.add(dataPair.value)
// storeDataForDb.nsIdCarbs.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastCarbsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedCarbs()
} }
is DataSyncSelector.PairBolusCalculatorResult -> { is DataSyncSelector.PairBolusCalculatorResult -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdBolusCalculatorResults.add(dataPair.value)
// storeDataForDb.nsIdBolusCalculatorResults.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastBolusCalculatorResultsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedBolusCalculatorResults()
} }
is DataSyncSelector.PairTemporaryTarget -> { is DataSyncSelector.PairTemporaryTarget -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdTemporaryTargets.add(dataPair.value)
// storeDataForDb.nsIdTemporaryTargets.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastTempTargetsIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTempTargets()
} }
is DataSyncSelector.PairTherapyEvent -> { is DataSyncSelector.PairTherapyEvent -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdTherapyEvents.add(dataPair.value)
// storeDataForDb.nsIdTherapyEvents.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastTherapyEventIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTherapyEvents()
} }
is DataSyncSelector.PairTemporaryBasal -> { is DataSyncSelector.PairTemporaryBasal -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdTemporaryBasals.add(dataPair.value)
// storeDataForDb.nsIdTemporaryBasals.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastTemporaryBasalIdIfGreater(dataPair.id)
dataSyncSelector.processChangedTemporaryBasals()
} }
is DataSyncSelector.PairExtendedBolus -> { is DataSyncSelector.PairExtendedBolus -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdExtendedBoluses.add(dataPair.value)
// storeDataForDb.nsIdExtendedBoluses.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastExtendedBolusIdIfGreater(dataPair.id)
dataSyncSelector.processChangedExtendedBoluses()
} }
is DataSyncSelector.PairProfileSwitch -> { is DataSyncSelector.PairProfileSwitch -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdProfileSwitches.add(dataPair.value)
// storeDataForDb.nsIdProfileSwitches.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastProfileSwitchIdIfGreater(dataPair.id)
dataSyncSelector.processChangedProfileSwitches()
} }
is DataSyncSelector.PairEffectiveProfileSwitch -> { is DataSyncSelector.PairEffectiveProfileSwitch -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdEffectiveProfileSwitches.add(dataPair.value)
// storeDataForDb.nsIdEffectiveProfileSwitches.add(dataPair.value)
// storeDataForDb.scheduleNsIdUpdate()
// }
dataSyncSelector.confirmLastEffectiveProfileSwitchIdIfGreater(dataPair.id)
dataSyncSelector.processChangedEffectiveProfileSwitches()
} }
is DataSyncSelector.PairOfflineEvent -> { is DataSyncSelector.PairOfflineEvent -> {
// if (result.response == 201) { // created dataPair.value.interfaceIDs.nightscoutId = it
// dataPair.value.interfaceIDs.nightscoutId = result.identifier storeDataForDb.nsIdOfflineEvents.add(dataPair.value)
// storeDataForDb.nsIdOfflineEvents.add(dataPair.value) }
// storeDataForDb.scheduleNsIdUpdate()
// } else -> {
dataSyncSelector.confirmLastOfflineEventIdIfGreater(dataPair.id) throw InvalidParameterException()
dataSyncSelector.processChangedOfflineEvents()
} }
} }
} }
} catch (e: Exception) { slowDown()
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
} }
} catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
return false
} }
} }
return true
} }
private fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation) { private suspend fun dbOperation(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, operation: Operation): Boolean =
when (collection) { when (collection) {
"profile" -> dbOperationProfileStore(dataPair = dataPair, progress = progress) "profile" -> dbOperationProfileStore(dataPair = dataPair, progress = progress)
"devicestatus" -> dbOperationDeviceStatus(dataPair = dataPair, progress = progress) "devicestatus" -> dbOperationDeviceStatus(dataPair = dataPair as DataSyncSelector.PairDeviceStatus, progress = progress)
"entries" -> dbOperationEntries(dataPair = dataPair, progress = progress, operation = operation) "entries" -> dbOperationEntries(dataPair = dataPair as DataSyncSelector.PairGlucoseValue, progress = progress, operation = operation)
"food" -> dbOperationFood(dataPair = dataPair, progress = progress, operation = operation) "food" -> dbOperationFood(dataPair = dataPair as DataSyncSelector.PairFood, progress = progress, operation = operation)
"treatments" -> dbOperationTreatments(dataPair = dataPair, progress = progress, operation = operation) "treatments" -> dbOperationTreatments(dataPair = dataPair, progress = progress, operation = operation)
else -> false
} }
}
fun storeLastLoadedSrvModified() { fun storeLastLoadedSrvModified() {
sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified)) sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified))
@ -1007,13 +889,14 @@ class NSClientV3Plugin @Inject constructor(
rxBus.send(EventNSClientNewLog("● RUN", "$blockingReason $origin")) rxBus.send(EventNSClientNewLog("● RUN", "$blockingReason $origin"))
return return
} }
if (workIsRunning(arrayOf(JOB_NAME))) { if (workIsRunning()) {
rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin")) rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin"))
if (!forceNew) return if (!forceNew) return
// Wait for end and start new cycle // Wait for end and start new cycle
while (workIsRunning(arrayOf(JOB_NAME))) Thread.sleep(5000) while (workIsRunning()) Thread.sleep(5000)
} }
rxBus.send(EventNSClientNewLog("● RUN", "Starting next round $origin")) rxBus.send(EventNSClientNewLog("● RUN", "Starting next round $origin"))
rxBus.send(EventNSClientUpdateGuiStatus())
WorkManager.getInstance(context) WorkManager.getInstance(context)
.beginUniqueWork( .beginUniqueWork(
JOB_NAME, JOB_NAME,
@ -1022,12 +905,11 @@ class NSClientV3Plugin @Inject constructor(
) )
.then(OneTimeWorkRequest.Builder(LoadLastModificationWorker::class.java).build()) .then(OneTimeWorkRequest.Builder(LoadLastModificationWorker::class.java).build())
.then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build()) .then(OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build())
// Other Workers are enqueued after BG finish .then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
// LoadTreatmentsWorker .then(OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build())
// LoadFoodsWorker .then(OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build())
// LoadProfileStoreWorker .then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build())
// LoadDeviceStatusWorker .then(OneTimeWorkRequest.Builder(DataSyncWorker::class.java).build())
// DataSyncWorker
.enqueue() .enqueue()
} }
@ -1040,11 +922,11 @@ class NSClientV3Plugin @Inject constructor(
rxBus.send(EventNSClientNewLog("● RUN", blockingReason)) rxBus.send(EventNSClientNewLog("● RUN", blockingReason))
return return
} }
if (workIsRunning(arrayOf(JOB_NAME))) { if (workIsRunning()) {
rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin")) rxBus.send(EventNSClientNewLog("● RUN", "Already running $origin"))
if (!forceNew) return if (!forceNew) return
// Wait for end and start new cycle // Wait for end and start new cycle
while (workIsRunning(arrayOf(JOB_NAME))) Thread.sleep(5000) while (workIsRunning()) Thread.sleep(5000)
} }
rxBus.send(EventNSClientNewLog("● RUN", "Starting upload $origin")) rxBus.send(EventNSClientNewLog("● RUN", "Starting upload $origin"))
WorkManager.getInstance(context) WorkManager.getInstance(context)
@ -1055,11 +937,10 @@ class NSClientV3Plugin @Inject constructor(
) )
} }
private fun workIsRunning(workNames: Array<String>): Boolean { private fun workIsRunning(workName: String = JOB_NAME): Boolean {
for (workName in workNames) for (workInfo in WorkManager.getInstance(context).getWorkInfosForUniqueWork(workName).get())
for (workInfo in WorkManager.getInstance(context).getWorkInfosForUniqueWork(workName).get()) if (workInfo.state == WorkInfo.State.BLOCKED || workInfo.state == WorkInfo.State.ENQUEUED || workInfo.state == WorkInfo.State.RUNNING)
if (workInfo.state == WorkInfo.State.BLOCKED || workInfo.state == WorkInfo.State.ENQUEUED || workInfo.state == WorkInfo.State.RUNNING) return true
return true
return false return false
} }
} }

View file

@ -8,7 +8,6 @@ import info.nightscout.sdk.localmodel.entry.NsUnits
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
import java.security.InvalidParameterException import java.security.InvalidParameterException
// copy of NSClientSourcePlugin for testing
fun NSSgvV3.toTransactionGlucoseValue(): TransactionGlucoseValue { fun NSSgvV3.toTransactionGlucoseValue(): TransactionGlucoseValue {
return TransactionGlucoseValue( return TransactionGlucoseValue(
timestamp = date ?: throw InvalidParameterException(), timestamp = date ?: throw InvalidParameterException(),

View file

@ -5,8 +5,7 @@ import androidx.work.WorkerParameters
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.plugins.sync.nsShared.events.EventNSClientUpdateGUI
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
@ -18,7 +17,7 @@ class DataSyncWorker(
context: Context, params: WorkerParameters context: Context, params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var dataSyncSelector: DataSyncSelector @Inject lateinit var dataSyncSelectorV3: DataSyncSelectorV3
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@ -26,14 +25,13 @@ class DataSyncWorker(
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
if (activePlugin.activeNsClient?.hasWritePermission == true || nsClientV3Plugin.wsConnected) { if (activePlugin.activeNsClient?.hasWritePermission == true || nsClientV3Plugin.wsConnected) {
rxBus.send(EventNSClientNewLog("► UPL", "Start")) rxBus.send(EventNSClientNewLog("► UPL", "Start"))
dataSyncSelector.doUpload() dataSyncSelectorV3.doUpload()
rxBus.send(EventNSClientNewLog("► UPL", "End")) rxBus.send(EventNSClientNewLog("► UPL", "End"))
} else { } else {
rxBus.send(EventNSClientNewLog("► ERROR", "Not connected or write permission")) rxBus.send(EventNSClientNewLog("► ERROR", "Not connected or write permission"))
// refresh token // refresh token
nsClientV3Plugin.scheduleIrregularExecution(refreshToken = true) nsClientV3Plugin.scheduleIrregularExecution(refreshToken = true)
} }
rxBus.send(EventNSClientUpdateGUI())
return Result.success() return Result.success()
} }
} }

View file

@ -1,18 +1,13 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.core.utils.worker.then import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
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
@ -29,94 +24,68 @@ class LoadBgWorker(
context: Context, params: WorkerParameters context: Context, params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var sp: SP @Inject lateinit var sp: SP
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var nsClientSource: NSClientSource @Inject lateinit var nsClientSource: NSClientSource
@Inject lateinit var workerClasses: WorkerClasses @Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Inject lateinit var workManager: WorkManager @Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
if (!nsClientSource.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false)) { if (!nsClientSource.isEnabled() && !sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_cgm, false))
workManager
.enqueueUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()
)
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"))
var continueLoading = true
try { try {
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) while (continueLoading) {
val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.ENTRIES) val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.ENTRIES)
val lastLoaded = val lastLoaded =
if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) if (isFirstLoad) max(nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge)
else max(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge) else max(nsClientV3Plugin.lastLoadedSrvModified.collections.entries, dateUtil.now() - nsClientV3Plugin.maxAge)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) { if ((nsClientV3Plugin.newestDataOnServer?.collections?.entries ?: Long.MAX_VALUE) > lastLoaded) {
val sgvs: List<NSSgvV3> val sgvs: List<NSSgvV3>
val response: NSAndroidClient.ReadResponse<List<NSSgvV3>>? val response: NSAndroidClient.ReadResponse<List<NSSgvV3>>?
if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) if (isFirstLoad) response = nsAndroidClient.getSgvsNewerThan(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD)
else { else {
response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) response = nsAndroidClient.getSgvsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD)
aapsLogger.debug(LTag.NSCLIENT, "lastLoadedSrvModified: ${response.lastServerModified}") aapsLogger.debug(LTag.NSCLIENT, "lastLoadedSrvModified: ${response.lastServerModified}")
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.entries = it } response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.entries = it }
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
nsClientV3Plugin.scheduleIrregularExecution() // Idea is to run after 5 min after last BG nsClientV3Plugin.scheduleIrregularExecution() // Idea is to run after 5 min after last BG
} }
sgvs = response.values sgvs = response.values
aapsLogger.debug(LTag.NSCLIENT, "SGVS: $sgvs") aapsLogger.debug(LTag.NSCLIENT, "SGVS: $sgvs")
if (sgvs.isNotEmpty()) { if (sgvs.isNotEmpty()) {
val action = if (isFirstLoad) "RCV-FIRST" else "RCV" val action = if (isFirstLoad) "RCV-F" else "RCV"
rxBus.send(EventNSClientNewLog("$action", "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("$action", "${sgvs.size} SVGs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
// Objective0 // Objective0
sp.putBoolean(info.nightscout.core.utils.R.string.key_objectives_bg_is_available_in_ns, true) 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 // Schedule processing of fetched data and continue of loading
val stopLoading = sgvs.size != NSClientV3Plugin.RECORDS_TO_LOAD || response.code == 304 continueLoading = !(sgvs.size != NSClientV3Plugin.RECORDS_TO_LOAD || response.code == 304)
workManager nsIncomingDataProcessor.processSgvs(sgvs)
.beginUniqueWork( } else {
nsClientV3Plugin.JOB_NAME, // End first load
ExistingWorkPolicy.APPEND_OR_REPLACE, if (isFirstLoad) {
OneTimeWorkRequest.Builder(workerClasses.nsClientSourceWorker).setInputData(dataWorkerStorage.storeInputData(sgvs)).build() nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
) nsClientV3Plugin.storeLastLoadedSrvModified()
// response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload }
.then(!stopLoading, OneTimeWorkRequest.Builder(LoadBgWorker::class.java).build()) rxBus.send(EventNSClientNewLog("◄ RCV BG END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
.then(stopLoading, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()) storeDataForDb.storeGlucoseValuesToDb()
.enqueue() continueLoading = false
}
} 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 BG END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("◄ RCV BG END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
workManager storeDataForDb.storeGlucoseValuesToDb()
.beginUniqueWork( continueLoading = false
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreBgWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build())
.enqueue()
} }
} else {
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("◄ RCV BG END", "No new data 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()
} }
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)

View file

@ -1,9 +1,6 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.receivers.DataWorkerStorage
@ -46,12 +43,6 @@ class LoadDeviceStatusWorker(
} else { } else {
rxBus.send(EventNSClientNewLog("◄ RCV DS END", "No data from ${dateUtil.dateAndTimeAndSecondsString(from)}")) rxBus.send(EventNSClientNewLog("◄ RCV DS END", "No data from ${dateUtil.dateAndTimeAndSecondsString(from)}"))
} }
WorkManager.getInstance(context)
.enqueueUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(DataSyncWorker::class.java).build()
)
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))

View file

@ -1,15 +1,11 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
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
@ -24,12 +20,12 @@ class LoadFoodsWorker(
params: WorkerParameters params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var storeDataForDb: StoreDataForDb @Inject lateinit var storeDataForDb: StoreDataForDb
@Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
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"))
@ -42,24 +38,10 @@ class LoadFoodsWorker(
aapsLogger.debug(LTag.NSCLIENT, "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) nsIncomingDataProcessor.processFood(foods)
.beginUniqueWork( storeDataForDb.storeFoodsToDb()
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(ProcessFoodWorker::class.java)
.setInputData(dataWorkerStorage.storeInputData(foods))
.build()
).then(OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreFoodWorker::class.java).build())
.then(OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build())
.enqueue()
} else { } else {
rxBus.send(EventNSClientNewLog("● RCV FOOD", "skipped")) rxBus.send(EventNSClientNewLog("● RCV FOOD", "skipped"))
WorkManager.getInstance(context)
.enqueueUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadProfileStoreWorker::class.java).build()
)
} }
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)

View file

@ -1,16 +1,13 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
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
@ -32,7 +29,7 @@ class LoadProfileStoreWorker(
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var workerClasses: WorkerClasses @Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
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"))
@ -59,32 +56,12 @@ class LoadProfileStoreWorker(
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
aapsLogger.debug(LTag.NSCLIENT, "PROFILE: $profile") aapsLogger.debug(LTag.NSCLIENT, "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) nsIncomingDataProcessor.processProfile(profile)
.beginUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder((workerClasses.nsProfileWorker))
.setInputData(dataWorkerStorage.storeInputData(profile))
.build()
).then(OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build())
.enqueue()
} else { } else {
rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
WorkManager.getInstance(context)
.enqueueUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
)
} }
} else { } else {
rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("◄ RCV PROFILE END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
WorkManager.getInstance(context)
.enqueueUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(LoadDeviceStatusWorker::class.java).build()
)
} }
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
@ -94,4 +71,5 @@ class LoadProfileStoreWorker(
return Result.success() return Result.success()
} }
} }

View file

@ -4,6 +4,7 @@ import android.content.Context
import androidx.work.WorkerParameters 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.nsShared.events.EventNSClientUpdateGuiStatus
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
@ -28,9 +29,11 @@ class LoadStatusWorker(
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage nsClientV3Plugin.lastOperationError = error.localizedMessage
rxBus.send(EventNSClientUpdateGuiStatus())
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null nsClientV3Plugin.lastOperationError = null
rxBus.send(EventNSClientUpdateGuiStatus())
return Result.success() return Result.success()
} }
} }

View file

@ -1,17 +1,12 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.core.utils.worker.then
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
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
@ -28,83 +23,63 @@ class LoadTreatmentsWorker(
params: WorkerParameters params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var context: Context @Inject lateinit var context: Context
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var storeDataForDb: StoreDataForDb @Inject lateinit var storeDataForDb: StoreDataForDb
@Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
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 continueLoading = true
try { try {
val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.TREATMENTS) while (continueLoading) {
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)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > lastLoaded) { else max(nsClientV3Plugin.lastLoadedSrvModified.collections.treatments, dateUtil.now() - nsClientV3Plugin.maxAge)
val treatments: List<NSTreatment> if ((nsClientV3Plugin.newestDataOnServer?.collections?.treatments ?: Long.MAX_VALUE) > lastLoaded) {
val response: NSAndroidClient.ReadResponse<List<NSTreatment>>? val treatments: List<NSTreatment>
if (isFirstLoad) { val response: NSAndroidClient.ReadResponse<List<NSTreatment>>?
val lastLoadedIso = dateUtil.toISOString(lastLoaded) if (isFirstLoad) {
response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, NSClientV3Plugin.RECORDS_TO_LOAD) val lastLoadedIso = dateUtil.toISOString(lastLoaded)
} else { response = nsAndroidClient.getTreatmentsNewerThan(lastLoadedIso, NSClientV3Plugin.RECORDS_TO_LOAD)
response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD) } else {
aapsLogger.debug(LTag.NSCLIENT, "lastLoadedSrvModified: ${response.lastServerModified}") response = nsAndroidClient.getTreatmentsModifiedSince(lastLoaded, NSClientV3Plugin.RECORDS_TO_LOAD)
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = it } aapsLogger.debug(LTag.NSCLIENT, "lastLoadedSrvModified: ${response.lastServerModified}")
nsClientV3Plugin.storeLastLoadedSrvModified() response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = it }
} nsClientV3Plugin.storeLastLoadedSrvModified()
treatments = response.values }
aapsLogger.debug(LTag.NSCLIENT, "TREATMENTS: $treatments") treatments = response.values
if (treatments.isNotEmpty()) { aapsLogger.debug(LTag.NSCLIENT, "TREATMENTS: $treatments")
val action = if (isFirstLoad) "RCV-FIRST" else "RCV" if (treatments.isNotEmpty()) {
rxBus.send(EventNSClientNewLog("$action", "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) val action = if (isFirstLoad) "RCV-F" else "RCV"
// Schedule processing of fetched data and continue of loading rxBus.send(EventNSClientNewLog("$action", "${treatments.size} TRs from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
val stopLoading = treatments.size != NSClientV3Plugin.RECORDS_TO_LOAD || response.code == 304 // Schedule processing of fetched data and continue of loading
WorkManager.getInstance(context) continueLoading = !(treatments.size != NSClientV3Plugin.RECORDS_TO_LOAD || response.code == 304)
.beginUniqueWork( nsIncomingDataProcessor.processTreatments(response.values)
nsClientV3Plugin.JOB_NAME, } else {
ExistingWorkPolicy.APPEND_OR_REPLACE, // End first load
OneTimeWorkRequest.Builder(ProcessTreatmentsWorker::class.java) if (isFirstLoad) {
.setInputData(dataWorkerStorage.storeInputData(response.values)) nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
.build() nsClientV3Plugin.storeLastLoadedSrvModified()
) }
// response 304 == Not modified (happens when date > srvModified => bad time on phone or server during upload rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
.then(!stopLoading, OneTimeWorkRequest.Builder(LoadTreatmentsWorker::class.java).build()) storeDataForDb.storeTreatmentsToDb()
.then(stopLoading, OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build()) continueLoading = false
.enqueue() }
} else { } else {
// End first load // End first load
if (isFirstLoad) { if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
} }
rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
WorkManager.getInstance(context) storeDataForDb.storeTreatmentsToDb()
.beginUniqueWork( continueLoading = false
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build())
.enqueue()
} }
} else {
// End first load
if (isFirstLoad) {
nsClientV3Plugin.lastLoadedSrvModified.collections.treatments = lastLoaded
nsClientV3Plugin.storeLastLoadedSrvModified()
}
rxBus.send(EventNSClientNewLog("◄ RCV TR END", "No new data from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))
WorkManager.getInstance(context)
.beginUniqueWork(
nsClientV3Plugin.JOB_NAME,
ExistingWorkPolicy.APPEND_OR_REPLACE,
OneTimeWorkRequest.Builder(StoreDataForDbImpl.StoreTreatmentsWorker::class.java).build()
)
.then(OneTimeWorkRequest.Builder(LoadFoodsWorker::class.java).build())
.enqueue()
} }
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)

View file

@ -1,81 +0,0 @@
package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import dagger.android.HasAndroidInjector
import info.nightscout.core.extensions.foodFromJson
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.Food
import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.utils.JsonHelper
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.sdk.localmodel.food.NSFood
import info.nightscout.shared.sharedPreferences.SP
import kotlinx.coroutines.Dispatchers
import org.json.JSONArray
import org.json.JSONObject
import javax.inject.Inject
class ProcessFoodWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var repository: AppRepository
@Inject lateinit var sp: SP
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var storeDataForDb: StoreDataForDb
@Inject lateinit var rxBus: RxBus
override suspend fun doWorkAndLog(): Result {
val data = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1))
?: return Result.failure(workDataOf("Error" to "missing input data"))
aapsLogger.debug(LTag.DATABASE, "Received Food Data: $data")
try {
val foods = mutableListOf<Food>()
if (data is JSONArray) {
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" -> {
val delFood = Food(
name = "",
portion = 0.0,
carbs = 0,
isValid = false
).also { it.interfaceIDs.nightscoutId = JsonHelper.safeGetString(jsonFood, "_id") }
foods += delFood
}
else -> {
val food = foodFromJson(jsonFood)
if (food != null) foods += food
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()
}
storeDataForDb.foods.addAll(foods)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
}
return Result.success()
}
}

View file

@ -1,146 +0,0 @@
package info.nightscout.plugins.sync.nsclientV3.workers
import android.content.Context
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.database.impl.AppRepository
import info.nightscout.interfaces.Config
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.sync.R
import info.nightscout.plugins.sync.nsclientV3.extensions.toBolus
import info.nightscout.plugins.sync.nsclientV3.extensions.toBolusCalculatorResult
import info.nightscout.plugins.sync.nsclientV3.extensions.toCarbs
import info.nightscout.plugins.sync.nsclientV3.extensions.toEffectiveProfileSwitch
import info.nightscout.plugins.sync.nsclientV3.extensions.toExtendedBolus
import info.nightscout.plugins.sync.nsclientV3.extensions.toOfflineEvent
import info.nightscout.plugins.sync.nsclientV3.extensions.toProfileSwitch
import info.nightscout.plugins.sync.nsclientV3.extensions.toTemporaryBasal
import info.nightscout.plugins.sync.nsclientV3.extensions.toTemporaryTarget
import info.nightscout.plugins.sync.nsclientV3.extensions.toTherapyEvent
import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventNSClientNewLog
import info.nightscout.rx.logging.LTag
import info.nightscout.sdk.localmodel.treatment.NSBolus
import info.nightscout.sdk.localmodel.treatment.NSBolusWizard
import info.nightscout.sdk.localmodel.treatment.NSCarbs
import info.nightscout.sdk.localmodel.treatment.NSEffectiveProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSExtendedBolus
import info.nightscout.sdk.localmodel.treatment.NSOfflineEvent
import info.nightscout.sdk.localmodel.treatment.NSProfileSwitch
import info.nightscout.sdk.localmodel.treatment.NSTemporaryBasal
import info.nightscout.sdk.localmodel.treatment.NSTemporaryTarget
import info.nightscout.sdk.localmodel.treatment.NSTherapyEvent
import info.nightscout.sdk.localmodel.treatment.NSTreatment
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil
import kotlinx.coroutines.Dispatchers
import javax.inject.Inject
class ProcessTreatmentsWorker(
context: Context,
params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.Default) {
@Inject lateinit var dataWorkerStorage: DataWorkerStorage
@Inject lateinit var config: Config
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var repository: AppRepository
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var storeDataForDb: StoreDataForDb
override suspend fun doWorkAndLog(): Result {
@Suppress("UNCHECKED_CAST")
val treatments = dataWorkerStorage.pickupObject(inputData.getLong(DataWorkerStorage.STORE_KEY, -1)) as List<NSTreatment>?
?: return Result.failure(workDataOf("Error" to "missing input data"))
try {
var latestDateInReceivedData: Long = 0
for (treatment in treatments) {
aapsLogger.debug(LTag.DATABASE, "Received NS treatment: $treatment")
val date = treatment.date ?: continue
if (date > latestDateInReceivedData) latestDateInReceivedData = date
when (treatment) {
is NSBolus ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_insulin, false) || config.NSCLIENT)
storeDataForDb.boluses.add(treatment.toBolus())
is NSCarbs ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_carbs, false) || config.NSCLIENT)
storeDataForDb.carbs.add(treatment.toCarbs())
is NSTemporaryTarget ->
if (sp.getBoolean(info.nightscout.core.utils.R.string.key_ns_receive_temp_target, false) || config.NSCLIENT) {
if (treatment.duration > 0L) {
// not ending event
if (treatment.targetBottomAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetBottomAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetTopAsMgdl() < Constants.MIN_TT_MGDL
|| treatment.targetTopAsMgdl() > Constants.MAX_TT_MGDL
|| treatment.targetBottomAsMgdl() > treatment.targetTopAsMgdl()
) {
aapsLogger.debug(LTag.DATABASE, "Ignored TemporaryTarget $treatment")
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)
}
}
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 ->
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)
// xDripBroadcast.sendTreatments(treatments)
} catch (error: Exception) {
aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("◄ ERROR", error.localizedMessage))
return Result.failure(workDataOf("Error" to error.localizedMessage))
}
return Result.success()
}
}

View file

@ -1,7 +1,6 @@
package info.nightscout.plugins.sync.tidepool.utils package info.nightscout.plugins.sync.tidepool.utils
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
import info.nightscout.rx.logging.LTag
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 javax.inject.Inject import javax.inject.Inject
@ -21,7 +20,7 @@ class RateLimit @Inject constructor(
// check if over limit // check if over limit
rateLimits[name]?.let { rateLimits[name]?.let {
if (dateUtil.now() - it < T.secs(seconds.toLong()).msecs()) { if (dateUtil.now() - it < T.secs(seconds.toLong()).msecs()) {
aapsLogger.debug(LTag.TIDEPOOL, "$name rate limited: $seconds seconds") //aapsLogger.debug(LTag.TIDEPOOL, "$name rate limited: $seconds seconds")
return false return false
} }
} }

View file

@ -1,12 +1,12 @@
package info.nightscout.plugins.sync.xdrip package info.nightscout.plugins.sync.xdrip
import dagger.Lazy import dagger.Lazy
import info.nightscout.database.ValueWrapper
import info.nightscout.database.impl.AppRepository import info.nightscout.database.impl.AppRepository
import info.nightscout.interfaces.XDripBroadcast import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.plugins.sync.R import info.nightscout.plugins.sync.R
import info.nightscout.rx.logging.AAPSLogger import info.nightscout.rx.logging.AAPSLogger
@ -18,7 +18,7 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class XdripDataSyncSelectorImplementation @Inject constructor( class DataSyncSelectorXdripImpl @Inject constructor(
private val sp: SP, private val sp: SP,
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
@ -26,7 +26,7 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
private val xdripBroadcast: Lazy<XDripBroadcast>, private val xdripBroadcast: Lazy<XDripBroadcast>,
private val appRepository: AppRepository private val appRepository: AppRepository
) : DataSyncSelector { ) : DataSyncSelectorXdrip {
class QueueCounter( class QueueCounter(
var bolusesRemaining: Long = -1L, var bolusesRemaining: Long = -1L,
@ -72,7 +72,7 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
override fun queueSize(): Long = queueCounter.size() override fun queueSize(): Long = queueCounter.size()
override fun doUpload() { override suspend fun doUpload() {
if (isEnabled) { if (isEnabled) {
processChangedGlucoseValues() processChangedGlucoseValues()
processChangedBoluses() processChangedBoluses()
@ -113,22 +113,21 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sp.remove(R.string.key_xdrip_offline_event_last_synced_id) sp.remove(R.string.key_xdrip_offline_event_last_synced_id)
sp.remove(R.string.key_xdrip_profile_store_last_synced_timestamp) sp.remove(R.string.key_xdrip_profile_store_last_synced_timestamp)
val lastDeviceStatusDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet() val lastDeviceStatusDbId = appRepository.getLastDeviceStatusId()
if (lastDeviceStatusDbIdWrapped is ValueWrapper.Existing) sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastDeviceStatusDbIdWrapped.value) if (lastDeviceStatusDbId != null) sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastDeviceStatusDbId)
else sp.remove(R.string.key_xdrip_device_status_last_synced_id) else sp.remove(R.string.key_xdrip_device_status_last_synced_id)
} }
override fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) { fun confirmLastGlucoseValueIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting GlucoseValue data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting GlucoseValue data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_glucose_value_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_glucose_value_last_synced_id, lastSynced)
} }
} }
override fun processChangedGlucoseValues() { private fun processChangedGlucoseValues() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastGlucoseValueIdWrapped().blockingGet() val lastDbId = appRepository.getLastGlucoseValueId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_glucose_value_last_synced_id, 0)
@ -170,17 +169,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
} }
} }
override fun confirmLastBolusIdIfGreater(lastSynced: Long) { fun confirmLastBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting Bolus data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting Bolus data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_bolus_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_bolus_last_synced_id, lastSynced)
} }
} }
override fun processChangedBoluses() { private fun processChangedBoluses() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastBolusIdWrapped().blockingGet() val lastDbId = appRepository.getLastBolusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_bolus_last_synced_id, 0)
@ -201,17 +199,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastCarbsIdIfGreater(lastSynced: Long) { fun confirmLastCarbsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting Carbs data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting Carbs data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_carbs_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_carbs_last_synced_id, lastSynced)
} }
} }
override fun processChangedCarbs() { private fun processChangedCarbs() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastCarbsIdWrapped().blockingGet() val lastDbId = appRepository.getLastCarbsId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_carbs_last_synced_id, 0)
@ -232,17 +229,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) { fun confirmLastBolusCalculatorResultsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting BolusCalculatorResult data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting BolusCalculatorResult data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, lastSynced)
} }
} }
override fun processChangedBolusCalculatorResults() { private fun processChangedBolusCalculatorResults() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastBolusCalculatorResultIdWrapped().blockingGet() val lastDbId = appRepository.getLastBolusCalculatorResultId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_bolus_calculator_result_last_synced_id, 0)
@ -263,17 +259,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) { fun confirmLastTempTargetsIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting TemporaryTarget data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting TemporaryTarget data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_temporary_target_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_temporary_target_last_synced_id, lastSynced)
} }
} }
override fun processChangedTempTargets() { private fun processChangedTempTargets() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastTempTargetIdWrapped().blockingGet() val lastDbId = appRepository.getLastTempTargetId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_temporary_target_last_synced_id, 0)
@ -294,17 +289,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastFoodIdIfGreater(lastSynced: Long) { fun confirmLastFoodIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_food_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_food_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting Food data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting Food data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_food_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_food_last_synced_id, lastSynced)
} }
} }
override fun processChangedFoods() { private fun processChangedFoods() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastFoodIdWrapped().blockingGet() val lastDbId = appRepository.getLastFoodId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_food_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_food_last_synced_id, 0)
@ -324,17 +318,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendFoods(force = true, progress) sendFoods(force = true, progress)
} }
override fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) { fun confirmLastTherapyEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting TherapyEvents data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting TherapyEvents data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_therapy_event_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_therapy_event_last_synced_id, lastSynced)
} }
} }
override fun processChangedTherapyEvents() { private fun processChangedTherapyEvents() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastTherapyEventIdWrapped().blockingGet() val lastDbId = appRepository.getLastTherapyEventId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_therapy_event_last_synced_id, 0)
@ -355,16 +348,15 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) { fun confirmLastDeviceStatusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting DeviceStatus data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting DeviceStatus data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_device_status_last_synced_id, lastSynced)
} }
} }
override fun processChangedDeviceStatuses() { private fun processChangedDeviceStatuses() {
val lastDbIdWrapped = appRepository.getLastDeviceStatusIdWrapped().blockingGet() val lastDbId = appRepository.getLastDeviceStatusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_device_status_last_synced_id, 0)
@ -382,17 +374,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
} }
} }
override fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) { fun confirmLastTemporaryBasalIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting TemporaryBasal data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting TemporaryBasal data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_temporary_basal_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_temporary_basal_last_synced_id, lastSynced)
} }
} }
override fun processChangedTemporaryBasals() { private fun processChangedTemporaryBasals() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastTemporaryBasalIdWrapped().blockingGet() val lastDbId = appRepository.getLastTemporaryBasalId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_temporary_basal_last_synced_id, 0)
@ -413,17 +404,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) { fun confirmLastExtendedBolusIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting ExtendedBolus data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting ExtendedBolus data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_extended_bolus_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_extended_bolus_last_synced_id, lastSynced)
} }
} }
override fun processChangedExtendedBoluses() { private fun processChangedExtendedBoluses() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastExtendedBolusIdWrapped().blockingGet() val lastDbId = appRepository.getLastExtendedBolusId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_extended_bolus_last_synced_id, 0)
@ -447,17 +437,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) { fun confirmLastProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting ProfileSwitch data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting ProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_profile_switch_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_profile_switch_last_synced_id, lastSynced)
} }
} }
override fun processChangedProfileSwitches() { private fun processChangedProfileSwitches() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastProfileSwitchIdWrapped().blockingGet() val lastDbId = appRepository.getLastProfileSwitchId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_profile_switch_last_synced_id, 0)
@ -478,17 +467,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) { fun confirmLastEffectiveProfileSwitchIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting EffectiveProfileSwitch data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting EffectiveProfileSwitch data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, lastSynced)
} }
} }
override fun processChangedEffectiveProfileSwitches() { private fun processChangedEffectiveProfileSwitches() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastEffectiveProfileSwitchIdWrapped().blockingGet() val lastDbId = appRepository.getLastEffectiveProfileSwitchId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_effective_profile_switch_last_synced_id, 0)
@ -509,17 +497,16 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) { fun confirmLastOfflineEventIdIfGreater(lastSynced: Long) {
if (lastSynced > sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0)) { if (lastSynced > sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0)) {
//aapsLogger.debug(LTag.XDRIP, "Setting OfflineEvent data sync from $lastSynced") //aapsLogger.debug(LTag.XDRIP, "Setting OfflineEvent data sync from $lastSynced")
sp.putLong(R.string.key_xdrip_offline_event_last_synced_id, lastSynced) sp.putLong(R.string.key_xdrip_offline_event_last_synced_id, lastSynced)
} }
} }
override fun processChangedOfflineEvents() { private fun processChangedOfflineEvents() {
var progress: String var progress: String
val lastDbIdWrapped = appRepository.getLastOfflineEventIdWrapped().blockingGet() val lastDbId = appRepository.getLastOfflineEventId() ?: 0L
val lastDbId = if (lastDbIdWrapped is ValueWrapper.Existing) lastDbIdWrapped.value else 0L
while (true) { while (true) {
if (!isEnabled) return if (!isEnabled) return
var startId = sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0) var startId = sp.getLong(R.string.key_xdrip_offline_event_last_synced_id, 0)
@ -540,11 +527,11 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
sendTreatments(force = true, progress) sendTreatments(force = true, progress)
} }
override fun confirmLastProfileStore(lastSynced: Long) { fun confirmLastProfileStore(lastSynced: Long) {
sp.putLong(R.string.key_xdrip_profile_store_last_synced_timestamp, lastSynced) sp.putLong(R.string.key_xdrip_profile_store_last_synced_timestamp, lastSynced)
} }
override fun processChangedProfileStore() { private fun processChangedProfileStore() {
if (!isEnabled) return if (!isEnabled) return
val lastSync = sp.getLong(R.string.key_xdrip_profile_store_last_synced_timestamp, 0) val lastSync = sp.getLong(R.string.key_xdrip_profile_store_last_synced_timestamp, 0)
val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0) val lastChange = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, 0)
@ -556,7 +543,10 @@ class XdripDataSyncSelectorImplementation @Inject constructor(
// add for v3 // add for v3
if (JsonHelper.safeGetLongAllowNull(profileJson, "date") == null) if (JsonHelper.safeGetLongAllowNull(profileJson, "date") == null)
profileJson.put("date", profileStore.getStartDate()) profileJson.put("date", profileStore.getStartDate())
xdripPlugin.sendToXdrip("profile", DataSyncSelector.PairProfileStore(profileJson, dateUtil.now()), "") val now = dateUtil.now()
xdripPlugin.sendToXdrip("profile", DataSyncSelector.PairProfileStore(profileJson, now), "")
confirmLastProfileStore(now)
processChangedProfileStore()
} }
} }
} }

View file

@ -35,7 +35,7 @@ class XdripFragment : DaggerFragment(), MenuProvider, PluginFragment {
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus
@Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var aapsSchedulers: AapsSchedulers @Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var dataSyncSelector: XdripDataSyncSelectorImplementation @Inject lateinit var dataSyncSelector: DataSyncSelectorXdripImpl
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var xdripPlugin: XdripPlugin @Inject lateinit var xdripPlugin: XdripPlugin
@Inject lateinit var config: Config @Inject lateinit var config: Config

View file

@ -29,6 +29,7 @@ import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.receivers.Intents import info.nightscout.interfaces.receivers.Intents
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.DataSyncSelectorXdrip
import info.nightscout.interfaces.sync.Sync import info.nightscout.interfaces.sync.Sync
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.utils.DecimalFormatter import info.nightscout.interfaces.utils.DecimalFormatter
@ -54,6 +55,10 @@ import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.utils.DateUtil import info.nightscout.shared.utils.DateUtil
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import org.json.JSONArray import org.json.JSONArray
import java.util.concurrent.Executors import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture import java.util.concurrent.ScheduledFuture
@ -74,7 +79,7 @@ class XdripPlugin @Inject constructor(
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val rxBus: RxBus, private val rxBus: RxBus,
private val uiInteraction: UiInteraction, private val uiInteraction: UiInteraction,
private val dataSyncSelector: XdripDataSyncSelectorImplementation, private val dataSyncSelector: DataSyncSelectorXdrip,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
aapsLogger: AAPSLogger aapsLogger: AAPSLogger
) : XDripBroadcast, Sync, PluginBase( ) : XDripBroadcast, Sync, PluginBase(
@ -92,6 +97,7 @@ class XdripPlugin @Inject constructor(
@Suppress("PrivatePropertyName") @Suppress("PrivatePropertyName")
private val XDRIP_JOB_NAME: String = this::class.java.simpleName private val XDRIP_JOB_NAME: String = this::class.java.simpleName
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper) private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val listLog: MutableList<EventXdripNewLog> = ArrayList() private val listLog: MutableList<EventXdripNewLog> = ArrayList()
@ -316,23 +322,27 @@ class XdripPlugin @Inject constructor(
*/ */
override fun sendToXdrip(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) { override fun sendToXdrip(collection: String, dataPair: DataSyncSelector.DataPair, progress: String) {
when (collection) { scope.launch {
"profile" -> sendProfileStore(dataPair = dataPair, progress = progress) when (collection) {
"devicestatus" -> sendDeviceStatus(dataPair = dataPair, progress = progress) "profile" -> sendProfileStore(dataPair = dataPair, progress = progress)
else -> throw IllegalStateException() "devicestatus" -> sendDeviceStatus(dataPair = dataPair, progress = progress)
else -> throw IllegalStateException()
}
} }
} }
override fun sendToXdrip(collection: String, dataPairs: List<DataSyncSelector.DataPair>, progress: String) { override fun sendToXdrip(collection: String, dataPairs: List<DataSyncSelector.DataPair>, progress: String) {
when (collection) { scope.launch {
"entries" -> sendEntries(dataPairs = dataPairs, progress = progress) when (collection) {
"food" -> sendFood(dataPairs = dataPairs, progress = progress) "entries" -> sendEntries(dataPairs = dataPairs, progress = progress)
"treatments" -> sendTreatments(dataPairs = dataPairs, progress = progress) "food" -> sendFood(dataPairs = dataPairs, progress = progress)
else -> throw IllegalStateException() "treatments" -> sendTreatments(dataPairs = dataPairs, progress = progress)
else -> throw IllegalStateException()
}
} }
} }
private fun sendProfileStore(dataPair: DataSyncSelector.DataPair, progress: String) { private suspend fun sendProfileStore(dataPair: DataSyncSelector.DataPair, progress: String) {
val data = (dataPair as DataSyncSelector.PairProfileStore).value val data = (dataPair as DataSyncSelector.PairProfileStore).value
rxBus.send(EventXdripNewLog("SENDING", "Sent 1 PROFILE ($progress)")) rxBus.send(EventXdripNewLog("SENDING", "Sent 1 PROFILE ($progress)"))
broadcast( broadcast(
@ -340,8 +350,6 @@ class XdripPlugin @Inject constructor(
.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
.putExtras(Bundle().apply { putString("profile", data.toString()) }) .putExtras(Bundle().apply { putString("profile", data.toString()) })
) )
dataSyncSelector.confirmLastProfileStore(dataPair.id)
dataSyncSelector.processChangedProfileStore()
} }
private fun sendDeviceStatus(dataPair: DataSyncSelector.DataPair, progress: String) { private fun sendDeviceStatus(dataPair: DataSyncSelector.DataPair, progress: String) {

View file

@ -5,7 +5,7 @@ import androidx.work.WorkerParameters
import info.nightscout.androidaps.annotations.OpenForTesting import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.plugins.sync.xdrip.XdripDataSyncSelectorImplementation import info.nightscout.plugins.sync.xdrip.DataSyncSelectorXdripImpl
import info.nightscout.plugins.sync.xdrip.events.EventXdripUpdateGUI import info.nightscout.plugins.sync.xdrip.events.EventXdripUpdateGUI
import info.nightscout.rx.bus.RxBus import info.nightscout.rx.bus.RxBus
import info.nightscout.rx.events.EventXdripNewLog import info.nightscout.rx.events.EventXdripNewLog
@ -17,7 +17,7 @@ class XdripDataSyncWorker(
context: Context, params: WorkerParameters context: Context, params: WorkerParameters
) : LoggingWorker(context, params, Dispatchers.IO) { ) : LoggingWorker(context, params, Dispatchers.IO) {
@Inject lateinit var dataSyncSelector: XdripDataSyncSelectorImplementation @Inject lateinit var dataSyncSelector: DataSyncSelectorXdripImpl
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus @Inject lateinit var rxBus: RxBus

View file

@ -96,18 +96,14 @@
</LinearLayout> </LinearLayout>
<ScrollView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/log_scrollview" android:id="@+id/recyclerview"
android:layout_width="fill_parent" android:layout_width="match_parent"
android:layout_height="fill_parent" android:layout_height="match_parent"
android:layout_marginStart="5dp" android:fadeScrollbars="true"
android:layout_marginEnd="5dp"> android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical">
<TextView </androidx.recyclerview.widget.RecyclerView>
android:id="@+id/log"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="" />
</ScrollView>
</LinearLayout> </LinearLayout>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/log_card"
style="@style/Widget.MaterialComponents.CardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:cardCornerRadius="4dp"
app:cardElevation="1dp"
app:cardUseCompatPadding="true"
app:contentPadding="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<TextView
android:id="@+id/log_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:text="LogText" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -1,11 +1,9 @@
package info.nightscout.plugins.sync.nsclientV3 package info.nightscout.plugins.sync.nsclientV3
import androidx.work.WorkManager
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.core.extensions.fromConstant import info.nightscout.core.extensions.fromConstant
import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.database.entities.Bolus import info.nightscout.database.entities.Bolus
import info.nightscout.database.entities.BolusCalculatorResult import info.nightscout.database.entities.BolusCalculatorResult
import info.nightscout.database.entities.Carbs import info.nightscout.database.entities.Carbs
@ -20,7 +18,6 @@ import info.nightscout.database.entities.TemporaryBasal
import info.nightscout.database.entities.TemporaryTarget import info.nightscout.database.entities.TemporaryTarget
import info.nightscout.database.entities.TherapyEvent import info.nightscout.database.entities.TherapyEvent
import info.nightscout.database.entities.embedments.InterfaceIDs import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.interfaces.XDripBroadcast
import info.nightscout.interfaces.logging.UserEntryLogger import info.nightscout.interfaces.logging.UserEntryLogger
import info.nightscout.interfaces.nsclient.StoreDataForDb import info.nightscout.interfaces.nsclient.StoreDataForDb
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
@ -28,16 +25,15 @@ import info.nightscout.interfaces.pump.VirtualPump
import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl import info.nightscout.plugins.sync.nsShared.StoreDataForDbImpl
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclient.extensions.fromConstant import info.nightscout.plugins.sync.nsclient.extensions.fromConstant
import info.nightscout.sdk.interfaces.NSAndroidClient import info.nightscout.sdk.interfaces.NSAndroidClient
import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse import info.nightscout.sdk.localmodel.treatment.CreateUpdateResponse
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mock import org.mockito.Mock
@ -51,17 +47,14 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
@Mock lateinit var receiverDelegate: ReceiverDelegate @Mock lateinit var receiverDelegate: ReceiverDelegate
@Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var uiInteraction: UiInteraction
@Mock lateinit var dataSyncSelector: DataSyncSelector @Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
@Mock lateinit var nsAndroidClient: NSAndroidClient @Mock lateinit var nsAndroidClient: NSAndroidClient
@Mock lateinit var uel: UserEntryLogger @Mock lateinit var uel: UserEntryLogger
@Mock lateinit var nsClientSource: NSClientSource @Mock lateinit var nsClientSource: NSClientSource
@Mock lateinit var xDripBroadcast: XDripBroadcast
@Mock lateinit var virtualPump: VirtualPump @Mock lateinit var virtualPump: VirtualPump
@Mock lateinit var mockedProfileFunction: ProfileFunction @Mock lateinit var mockedProfileFunction: ProfileFunction
@Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler @Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
@Mock lateinit var workManager: WorkManager @Mock lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Mock lateinit var workerClasses: WorkerClasses
@Mock lateinit var dataWorkerStorage: DataWorkerStorage
private lateinit var storeDataForDb: StoreDataForDb private lateinit var storeDataForDb: StoreDataForDb
private lateinit var sut: NSClientV3Plugin private lateinit var sut: NSClientV3Plugin
@ -77,8 +70,8 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
sut = sut =
NSClientV3Plugin( NSClientV3Plugin(
injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy,
sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, mockedProfileFunction, repository, sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelectorV3, mockedProfileFunction, repository,
nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource nsDeviceStatusHandler, nsClientSource, nsIncomingDataProcessor, storeDataForDb
) )
sut.nsAndroidClient = nsAndroidClient sut.nsAndroidClient = nsAndroidClient
`when`(mockedProfileFunction.getProfile(anyLong())).thenReturn(validProfile) `when`(mockedProfileFunction.getProfile(anyLong())).thenReturn(validProfile)
@ -87,7 +80,6 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddDeviceStatus() = runTest { fun nsAddDeviceStatus() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val deviceStatus = DeviceStatus( val deviceStatus = DeviceStatus(
timestamp = 10000, timestamp = 10000,
suggested = "{\"temp\":\"absolute\",\"bg\":133,\"tick\":-6,\"eventualBG\":67,\"targetBG\":99,\"insulinReq\":0,\"deliverAt\":\"2023-01-02T15:29:33.374Z\",\"sensitivityRatio\":1,\"variable_sens\":97.5,\"predBGs\":{\"IOB\":[133,127,121,116,111,106,101,97,93,89,85,81,78,75,72,69,67,65,62,60,58,57,55,54,52,51,50,49,48,47,46,45,45,44,43,43,42,42,41,41,41,41,40,40,40,40,39],\"ZT\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39,39,39,39,39,39,39],\"UAM\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39]},\"reason\":\"COB: 0, Dev: 0.1, BGI: -0.3, ISF: 5.4, CR: 13, Target: 5.5, minPredBG 2.2, minGuardBG 2.1, IOBpredBG 2.2, UAMpredBG 2.2; minGuardBG 2.1<4.0\",\"COB\":0,\"IOB\":0.692,\"duration\":90,\"rate\":0,\"timestamp\":\"2023-01-02T15:29:39.460Z\"}", suggested = "{\"temp\":\"absolute\",\"bg\":133,\"tick\":-6,\"eventualBG\":67,\"targetBG\":99,\"insulinReq\":0,\"deliverAt\":\"2023-01-02T15:29:33.374Z\",\"sensitivityRatio\":1,\"variable_sens\":97.5,\"predBGs\":{\"IOB\":[133,127,121,116,111,106,101,97,93,89,85,81,78,75,72,69,67,65,62,60,58,57,55,54,52,51,50,49,48,47,46,45,45,44,43,43,42,42,41,41,41,41,40,40,40,40,39],\"ZT\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39,39,39,39,39,39,39],\"UAM\":[133,127,121,115,110,105,101,96,92,88,84,81,77,74,71,69,66,64,62,59,58,56,54,53,51,50,49,48,47,46,45,44,44,43,42,42,41,41,40,40,40,39]},\"reason\":\"COB: 0, Dev: 0.1, BGI: -0.3, ISF: 5.4, CR: 13, Target: 5.5, minPredBG 2.2, minGuardBG 2.1, IOBpredBG 2.2, UAMpredBG 2.2; minGuardBG 2.1<4.0\",\"COB\":0,\"IOB\":0.692,\"duration\":90,\"rate\":0,\"timestamp\":\"2023-01-02T15:29:39.460Z\"}",
@ -103,23 +95,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairDeviceStatus(deviceStatus, 1000) val dataPair = DataSyncSelector.PairDeviceStatus(deviceStatus, 1000)
// create // create
`when`(nsAndroidClient.createDeviceStatus(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createDeviceStatus(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("devicestatus", dataPair, "1/3") sut.nsAdd("devicestatus", dataPair, "1/3")
// Assertions.assertEquals(1, storeDataForDb.nsIdDeviceStatuses.size) Assertions.assertEquals(1, storeDataForDb.nsIdDeviceStatuses.size)
verify(dataSyncSelector, Times(1)).confirmLastDeviceStatusIdIfGreater(1000)
verify(dataSyncSelector, Times(1)).processChangedDeviceStatuses()
// update // update
`when`(nsAndroidClient.createDeviceStatus(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.createDeviceStatus(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsAdd("devicestatus", dataPair, "1/3") sut.nsAdd("devicestatus", dataPair, "1/3")
// Assertions.assertEquals(1, storeDataForDb.nsIdDeviceStatuses.size) // still only 1 Assertions.assertEquals(2, storeDataForDb.nsIdDeviceStatuses.size) // still only 1
verify(dataSyncSelector, Times(2)).confirmLastDeviceStatusIdIfGreater(1000)
verify(dataSyncSelector, Times(2)).processChangedDeviceStatuses()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddEntries() = runTest { fun nsAddEntries() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val glucoseValue = GlucoseValue( val glucoseValue = GlucoseValue(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -134,21 +121,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairGlucoseValue(glucoseValue, 1000) val dataPair = DataSyncSelector.PairGlucoseValue(glucoseValue, 1000)
// create // create
`when`(nsAndroidClient.createSvg(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createSgv(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("entries", dataPair, "1/3") sut.nsAdd("entries", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastGlucoseValueIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdGlucoseValues.size)
verify(dataSyncSelector, Times(1)).processChangedGlucoseValues()
// update // update
`when`(nsAndroidClient.updateSvg(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateSvg(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("entries", dataPair, "1/3") sut.nsUpdate("entries", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastGlucoseValueIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdGlucoseValues.size)
verify(dataSyncSelector, Times(2)).processChangedGlucoseValues()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddFood() = runTest { fun nsAddFood() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val food = Food( val food = Food(
isValid = true, isValid = true,
name = "name", name = "name",
@ -167,21 +151,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairFood(food, 1000) val dataPair = DataSyncSelector.PairFood(food, 1000)
// create // create
`when`(nsAndroidClient.createFood(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createFood(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("food", dataPair, "1/3") sut.nsAdd("food", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastFoodIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdFoods.size)
verify(dataSyncSelector, Times(1)).processChangedFoods()
// update // update
`when`(nsAndroidClient.updateFood(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateFood(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("food", dataPair, "1/3") sut.nsUpdate("food", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastFoodIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdFoods.size)
verify(dataSyncSelector, Times(2)).processChangedFoods()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddBolus() = runTest { fun nsAddBolus() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val bolus = Bolus( val bolus = Bolus(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -198,21 +179,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairBolus(bolus, 1000) val dataPair = DataSyncSelector.PairBolus(bolus, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastBolusIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdBoluses.size)
verify(dataSyncSelector, Times(1)).processChangedBoluses()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastBolusIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdBoluses.size)
verify(dataSyncSelector, Times(2)).processChangedBoluses()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddCarbs() = runTest { fun nsAddCarbs() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val carbs = Carbs( val carbs = Carbs(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -228,21 +206,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairCarbs(carbs, 1000) val dataPair = DataSyncSelector.PairCarbs(carbs, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastCarbsIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdCarbs.size)
verify(dataSyncSelector, Times(1)).processChangedCarbs()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastCarbsIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdCarbs.size)
verify(dataSyncSelector, Times(2)).processChangedCarbs()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddBolusCalculatorResult() = runTest { fun nsAddBolusCalculatorResult() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val bolus = BolusCalculatorResult( val bolus = BolusCalculatorResult(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -284,21 +259,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairBolusCalculatorResult(bolus, 1000) val dataPair = DataSyncSelector.PairBolusCalculatorResult(bolus, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastBolusCalculatorResultsIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdBolusCalculatorResults.size)
verify(dataSyncSelector, Times(1)).processChangedBolusCalculatorResults()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastBolusCalculatorResultsIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdBolusCalculatorResults.size)
verify(dataSyncSelector, Times(2)).processChangedBolusCalculatorResults()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddEffectiveProfileSwitch() = runTest { fun nsAddEffectiveProfileSwitch() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val profileSwitch = EffectiveProfileSwitch( val profileSwitch = EffectiveProfileSwitch(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -325,21 +297,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairEffectiveProfileSwitch(profileSwitch, 1000) val dataPair = DataSyncSelector.PairEffectiveProfileSwitch(profileSwitch, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastEffectiveProfileSwitchIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdEffectiveProfileSwitches.size)
verify(dataSyncSelector, Times(1)).processChangedEffectiveProfileSwitches()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastEffectiveProfileSwitchIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdEffectiveProfileSwitches.size)
verify(dataSyncSelector, Times(2)).processChangedEffectiveProfileSwitches()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddProfileSwitch() = runTest { fun nsAddProfileSwitch() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val profileSwitch = ProfileSwitch( val profileSwitch = ProfileSwitch(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -364,21 +333,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairProfileSwitch(profileSwitch, 1000) val dataPair = DataSyncSelector.PairProfileSwitch(profileSwitch, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastProfileSwitchIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdProfileSwitches.size)
verify(dataSyncSelector, Times(1)).processChangedProfileSwitches()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastProfileSwitchIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdProfileSwitches.size)
verify(dataSyncSelector, Times(2)).processChangedProfileSwitches()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddExtendedBolus() = runTest { fun nsAddExtendedBolus() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val extendedBolus = ExtendedBolus( val extendedBolus = ExtendedBolus(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -394,21 +360,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairExtendedBolus(extendedBolus, 1000) val dataPair = DataSyncSelector.PairExtendedBolus(extendedBolus, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastExtendedBolusIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdExtendedBoluses.size)
verify(dataSyncSelector, Times(1)).processChangedExtendedBoluses()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastExtendedBolusIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdExtendedBoluses.size)
verify(dataSyncSelector, Times(2)).processChangedExtendedBoluses()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddOffilineEvent() = runTest { fun nsAddOffilineEvent() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val offlineEvent = OfflineEvent( val offlineEvent = OfflineEvent(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -423,21 +386,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairOfflineEvent(offlineEvent, 1000) val dataPair = DataSyncSelector.PairOfflineEvent(offlineEvent, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastOfflineEventIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdOfflineEvents.size)
verify(dataSyncSelector, Times(1)).processChangedOfflineEvents()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastOfflineEventIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdOfflineEvents.size)
verify(dataSyncSelector, Times(2)).processChangedOfflineEvents()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddTemporaryBasal() = runTest { fun nsAddTemporaryBasal() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val temporaryBasal = TemporaryBasal( val temporaryBasal = TemporaryBasal(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -454,21 +414,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairTemporaryBasal(temporaryBasal, 1000) val dataPair = DataSyncSelector.PairTemporaryBasal(temporaryBasal, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastTemporaryBasalIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdTemporaryBasals.size)
verify(dataSyncSelector, Times(1)).processChangedTemporaryBasals()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastTemporaryBasalIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdTemporaryBasals.size)
verify(dataSyncSelector, Times(2)).processChangedTemporaryBasals()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddTemporaryTarget() = runTest { fun nsAddTemporaryTarget() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val temporaryTarget = TemporaryTarget( val temporaryTarget = TemporaryTarget(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -485,21 +442,18 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairTemporaryTarget(temporaryTarget, 1000) val dataPair = DataSyncSelector.PairTemporaryTarget(temporaryTarget, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastTempTargetsIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdTemporaryTargets.size)
verify(dataSyncSelector, Times(1)).processChangedTempTargets()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastTempTargetsIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdTemporaryTargets.size)
verify(dataSyncSelector, Times(2)).processChangedTempTargets()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddTherapyEvent() = runTest { fun nsAddTherapyEvent() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val therapyEvent = TherapyEvent( val therapyEvent = TherapyEvent(
timestamp = 10000, timestamp = 10000,
isValid = true, isValid = true,
@ -519,32 +473,29 @@ internal class NSClientV3PluginTest : TestBaseWithProfile() {
) )
val dataPair = DataSyncSelector.PairTherapyEvent(therapyEvent, 1000) val dataPair = DataSyncSelector.PairTherapyEvent(therapyEvent, 1000)
// create // create
`when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createTreatment(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("treatments", dataPair, "1/3") sut.nsAdd("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastTherapyEventIdIfGreater(1000) Assertions.assertEquals(1, storeDataForDb.nsIdTherapyEvents.size)
verify(dataSyncSelector, Times(1)).processChangedTherapyEvents()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("treatments", dataPair, "1/3") sut.nsUpdate("treatments", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastTherapyEventIdIfGreater(1000) Assertions.assertEquals(2, storeDataForDb.nsIdTherapyEvents.size)
verify(dataSyncSelector, Times(2)).processChangedTherapyEvents()
} }
@Test @Test
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
fun nsAddProfile() = runTest { fun nsAddProfile() = runTest {
sut.scope = CoroutineScope(UnconfinedTestDispatcher(testScheduler))
val dataPair = DataSyncSelector.PairProfileStore(getValidProfileStore().data, 1000) val dataPair = DataSyncSelector.PairProfileStore(getValidProfileStore().data, 1000)
// create // create
`when`(nsAndroidClient.createProfileStore(anyObject())).thenReturn(CreateUpdateResponse(201, null)) `when`(nsAndroidClient.createProfileStore(anyObject())).thenReturn(CreateUpdateResponse(201, "aaa"))
sut.nsAdd("profile", dataPair, "1/3") sut.nsAdd("profile", dataPair, "1/3")
verify(dataSyncSelector, Times(1)).confirmLastProfileStore(1000) // verify(dataSyncSelectorV3, Times(1)).confirmLastProfileStore(1000)
verify(dataSyncSelector, Times(1)).processChangedProfileStore() // verify(dataSyncSelectorV3, Times(1)).processChangedProfileStore()
// update // update
`when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, null)) `when`(nsAndroidClient.updateTreatment(anyObject())).thenReturn(CreateUpdateResponse(200, "aaa"))
sut.nsUpdate("profile", dataPair, "1/3") sut.nsUpdate("profile", dataPair, "1/3")
verify(dataSyncSelector, Times(2)).confirmLastProfileStore(1000) // verify(dataSyncSelectorV3, Times(2)).confirmLastProfileStore(1000)
verify(dataSyncSelector, Times(2)).processChangedProfileStore() // verify(dataSyncSelectorV3, Times(2)).processChangedProfileStore()
} }
} }

View file

@ -7,8 +7,8 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.interfaces.plugin.ActivePlugin import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.sync.DataSyncSelector
import info.nightscout.interfaces.sync.NsClient import info.nightscout.interfaces.sync.NsClient
import info.nightscout.plugins.sync.nsclientV3.DataSyncSelectorV3Impl
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 kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -24,7 +24,7 @@ import org.mockito.Mockito.`when`
internal class DataSyncWorkerTest : TestBase() { internal class DataSyncWorkerTest : TestBase() {
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var dataSyncSelector: DataSyncSelector @Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3Impl
@Mock lateinit var activePlugin: ActivePlugin @Mock lateinit var activePlugin: ActivePlugin
@Mock lateinit var nsClient: NsClient @Mock lateinit var nsClient: NsClient
@Mock lateinit var rxBus: RxBus @Mock lateinit var rxBus: RxBus
@ -37,7 +37,7 @@ internal class DataSyncWorkerTest : TestBase() {
if (it is DataSyncWorker) { if (it is DataSyncWorker) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.fabricPrivacy = fabricPrivacy it.fabricPrivacy = fabricPrivacy
it.dataSyncSelector = dataSyncSelector it.dataSyncSelectorV3 = dataSyncSelectorV3
it.activePlugin = activePlugin it.activePlugin = activePlugin
it.rxBus = rxBus it.rxBus = rxBus
it.nsClientV3Plugin = nsClientV3Plugin it.nsClientV3Plugin = nsClientV3Plugin
@ -57,11 +57,11 @@ internal class DataSyncWorkerTest : TestBase() {
sut = TestListenableWorkerBuilder<DataSyncWorker>(context).build() sut = TestListenableWorkerBuilder<DataSyncWorker>(context).build()
`when`(nsClient.hasWritePermission).thenReturn(false) `when`(nsClient.hasWritePermission).thenReturn(false)
sut.doWorkAndLog() sut.doWorkAndLog()
Mockito.verify(dataSyncSelector, Mockito.times(0)).doUpload() Mockito.verify(dataSyncSelectorV3, Mockito.times(0)).doUpload()
`when`(nsClient.hasWritePermission).thenReturn(true) `when`(nsClient.hasWritePermission).thenReturn(true)
val result = sut.doWorkAndLog() val result = sut.doWorkAndLog()
Mockito.verify(dataSyncSelector, Mockito.times(1)).doUpload() Mockito.verify(dataSyncSelectorV3, Mockito.times(1)).doUpload()
Assertions.assertTrue(result is Success) Assertions.assertTrue(result is Success)
} }
} }

View file

@ -1,6 +1,5 @@
package info.nightscout.plugins.sync.nsclientV3.workers package info.nightscout.plugins.sync.nsclientV3.workers
import androidx.work.ExistingWorkPolicy
import androidx.work.ListenableWorker import androidx.work.ListenableWorker
import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequest
import androidx.work.WorkContinuation import androidx.work.WorkContinuation
@ -11,17 +10,17 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBase import info.nightscout.androidaps.TestBase
import info.nightscout.core.utils.fabric.FabricPrivacy import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.database.entities.GlucoseValue import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.embedments.InterfaceIDs import info.nightscout.database.entities.embedments.InterfaceIDs
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.nsclient.StoreDataForDb
import info.nightscout.interfaces.profile.ProfileFunction import info.nightscout.interfaces.profile.ProfileFunction
import info.nightscout.interfaces.receivers.ReceiverStatusStore import info.nightscout.interfaces.receivers.ReceiverStatusStore
import info.nightscout.interfaces.source.NSClientSource import info.nightscout.interfaces.source.NSClientSource
import info.nightscout.interfaces.sync.DataSyncSelector import info.nightscout.interfaces.sync.DataSyncSelectorV3
import info.nightscout.interfaces.ui.UiInteraction import info.nightscout.interfaces.ui.UiInteraction
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.plugins.sync.nsShared.NsIncomingDataProcessor
import info.nightscout.plugins.sync.nsclient.ReceiverDelegate import info.nightscout.plugins.sync.nsclient.ReceiverDelegate
import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler import info.nightscout.plugins.sync.nsclient.data.NSDeviceStatusHandler
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
@ -41,14 +40,12 @@ import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong import org.mockito.ArgumentMatchers.anyLong
import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.anyString
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
internal class LoadBgWorkerTest : TestBase() { internal class LoadBgWorkerTest : TestBase() {
@Mock lateinit var workerClasses: WorkerClasses
@Mock lateinit var sp: SP @Mock lateinit var sp: SP
@Mock lateinit var fabricPrivacy: FabricPrivacy @Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var dateUtil: DateUtil @Mock lateinit var dateUtil: DateUtil
@ -57,13 +54,15 @@ internal class LoadBgWorkerTest : TestBase() {
@Mock lateinit var profileFunction: ProfileFunction @Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var config: Config @Mock lateinit var config: Config
@Mock lateinit var uiInteraction: UiInteraction @Mock lateinit var uiInteraction: UiInteraction
@Mock lateinit var dataSyncSelector: DataSyncSelector @Mock lateinit var dataSyncSelectorV3: DataSyncSelectorV3
@Mock lateinit var repository: AppRepository @Mock lateinit var repository: AppRepository
@Mock lateinit var receiverStatusStore: ReceiverStatusStore @Mock lateinit var receiverStatusStore: ReceiverStatusStore
@Mock lateinit var nsClientSource: NSClientSource @Mock lateinit var nsClientSource: NSClientSource
@Mock lateinit var workManager: WorkManager @Mock lateinit var workManager: WorkManager
@Mock lateinit var workContinuation: WorkContinuation @Mock lateinit var workContinuation: WorkContinuation
@Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler @Mock lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
@Mock lateinit var storeDataForDb: StoreDataForDb
@Mock lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger) private val rxBus: RxBus = RxBus(aapsSchedulers, aapsLogger)
private lateinit var nsClientV3Plugin: NSClientV3Plugin private lateinit var nsClientV3Plugin: NSClientV3Plugin
@ -78,15 +77,13 @@ internal class LoadBgWorkerTest : TestBase() {
if (it is LoadBgWorker) { if (it is LoadBgWorker) {
it.aapsLogger = aapsLogger it.aapsLogger = aapsLogger
it.fabricPrivacy = fabricPrivacy it.fabricPrivacy = fabricPrivacy
it.dataWorkerStorage = dataWorkerStorage
it.sp = sp it.sp = sp
it.rxBus = rxBus it.rxBus = rxBus
it.context = context it.context = context
it.dateUtil = dateUtil it.dateUtil = dateUtil
it.nsClientV3Plugin = nsClientV3Plugin it.nsClientV3Plugin = nsClientV3Plugin
it.workerClasses = workerClasses
it.nsClientSource = nsClientSource it.nsClientSource = nsClientSource
it.workManager = workManager it.storeDataForDb = storeDataForDb
} }
} }
} }
@ -101,8 +98,8 @@ internal class LoadBgWorkerTest : TestBase() {
receiverDelegate = ReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy) receiverDelegate = ReceiverDelegate(rxBus, rh, sp, receiverStatusStore, aapsSchedulers, fabricPrivacy)
nsClientV3Plugin = NSClientV3Plugin( nsClientV3Plugin = NSClientV3Plugin(
injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy, injector, aapsLogger, aapsSchedulers, rxBus, rh, context, fabricPrivacy,
sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelector, profileFunction, repository, sp, receiverDelegate, config, dateUtil, uiInteraction, dataSyncSelectorV3, profileFunction, repository,
nsDeviceStatusHandler, workManager, workerClasses, dataWorkerStorage, nsClientSource nsDeviceStatusHandler, nsClientSource, nsIncomingDataProcessor, storeDataForDb
) )
nsClientV3Plugin.newestDataOnServer = LastModified(LastModified.Collections()) nsClientV3Plugin.newestDataOnServer = LastModified(LastModified.Collections())
} }
@ -124,11 +121,6 @@ internal class LoadBgWorkerTest : TestBase() {
val result = sut.doWorkAndLog() val result = sut.doWorkAndLog()
Assertions.assertTrue(result is ListenableWorker.Result.Success) Assertions.assertTrue(result is ListenableWorker.Result.Success)
Assertions.assertTrue(result.outputData.getString("Result") == "Load not enabled") Assertions.assertTrue(result.outputData.getString("Result") == "Load not enabled")
Mockito.verify(workManager, Mockito.times(1)).enqueueUniqueWork(
eq(nsClientV3Plugin.JOB_NAME),
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
any<OneTimeWorkRequest>()
)
} }
@Test @Test
@ -144,13 +136,6 @@ internal class LoadBgWorkerTest : TestBase() {
val result = sut.doWorkAndLog() val result = sut.doWorkAndLog()
Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries) Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries)
Assertions.assertTrue(result is ListenableWorker.Result.Success) Assertions.assertTrue(result is ListenableWorker.Result.Success)
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
eq(nsClientV3Plugin.JOB_NAME),
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
any<OneTimeWorkRequest>()
)
Mockito.verify(workContinuation, Mockito.times(1)).then(any<OneTimeWorkRequest>())
Mockito.verify(workContinuation, Mockito.times(1)).enqueue()
} }
@Test @Test
@ -171,7 +156,6 @@ internal class LoadBgWorkerTest : TestBase() {
Mockito.`when`(workManager.beginUniqueWork(anyString(), any(), any<OneTimeWorkRequest>())).thenReturn(workContinuation) Mockito.`when`(workManager.beginUniqueWork(anyString(), any(), any<OneTimeWorkRequest>())).thenReturn(workContinuation)
Mockito.`when`(workContinuation.then(any<OneTimeWorkRequest>())).thenReturn(workContinuation) Mockito.`when`(workContinuation.then(any<OneTimeWorkRequest>())).thenReturn(workContinuation)
Mockito.`when`(workerClasses.nsClientSourceWorker).thenReturn(LoggingWorker::class.java)
nsClientV3Plugin.nsAndroidClient = nsAndroidClient nsClientV3Plugin.nsAndroidClient = nsAndroidClient
nsClientV3Plugin.lastLoadedSrvModified.collections.entries = 0L // first load nsClientV3Plugin.lastLoadedSrvModified.collections.entries = 0L // first load
nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries = now - 1000 nsClientV3Plugin.firstLoadContinueTimestamp.collections.entries = now - 1000
@ -180,13 +164,6 @@ internal class LoadBgWorkerTest : TestBase() {
val result = sut.doWorkAndLog() val result = sut.doWorkAndLog()
Assertions.assertTrue(result is ListenableWorker.Result.Success) Assertions.assertTrue(result is ListenableWorker.Result.Success)
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
eq(nsClientV3Plugin.JOB_NAME),
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
any<OneTimeWorkRequest>()
)
Mockito.verify(workContinuation, Mockito.times(1)).then(any<OneTimeWorkRequest>())
Mockito.verify(workContinuation, Mockito.times(1)).enqueue()
} }
@ -203,12 +180,5 @@ internal class LoadBgWorkerTest : TestBase() {
val result = sut.doWorkAndLog() val result = sut.doWorkAndLog()
Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries) Assertions.assertEquals(now - 1000, nsClientV3Plugin.lastLoadedSrvModified.collections.entries)
Assertions.assertTrue(result is ListenableWorker.Result.Success) Assertions.assertTrue(result is ListenableWorker.Result.Success)
Mockito.verify(workManager, Mockito.times(1)).beginUniqueWork(
eq(nsClientV3Plugin.JOB_NAME),
eq(ExistingWorkPolicy.APPEND_OR_REPLACE),
any<OneTimeWorkRequest>()
)
Mockito.verify(workContinuation, Mockito.times(1)).then(any<OneTimeWorkRequest>())
Mockito.verify(workContinuation, Mockito.times(1)).enqueue()
} }
} }