NSCv3: improve comm

This commit is contained in:
Milos Kozak 2023-01-02 22:38:17 +01:00
parent ddba45622c
commit 7ad13882ef
5 changed files with 79 additions and 53 deletions

View file

@ -105,7 +105,6 @@ class NSAndroidClientImpl(
} }
} }
// TODO: parameters like count?
override suspend fun getSgvs(): List<NSSgvV3> = callWrapper(dispatcher) { override suspend fun getSgvs(): List<NSSgvV3> = callWrapper(dispatcher) {
val response = api.getSgvs() val response = api.getSgvs()
@ -143,27 +142,36 @@ class NSAndroidClientImpl(
val remoteEntry = nsSgvV3.toRemoteEntry() val remoteEntry = nsSgvV3.toRemoteEntry()
remoteEntry.app = "AAPS" remoteEntry.app = "AAPS"
val response = api.createEntry(remoteEntry) val response = api.createEntry(remoteEntry)
if (response.isSuccessful) { val errorResponse = response.errorBody()?.string()
if (response.code() == 200) { if (response.code() == 200) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = null,
isDeduplication = true, isDeduplication = true
deduplicatedIdentifier = null, )
lastModified = null } else if (response.code() == 201) {
) return@callWrapper CreateUpdateResponse(
} else if (response.code() == 201) { response = response.code(),
return@callWrapper CreateUpdateResponse( identifier = response.body()?.result?.identifier
response = response.code(), ?: throw UnknownResponseNightscoutException(),
identifier = response.body()?.result?.identifier ?: throw UnknownResponseNightscoutException(), isDeduplication = response.body()?.result?.isDeduplication ?: false,
isDeduplication = response.body()?.result?.isDeduplication ?: false, deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier, lastModified = response.body()?.result?.lastModified
lastModified = response.body()?.result?.lastModified )
) } else if (response.code() == 400 && errorResponse?.contains("Bad or missing utcOffset field") == true && nsSgvV3.utcOffset != 0L) {
} else throw UnsuccessfullNightscoutException() // Record can be originally uploaded without utcOffset
} else { // because utcOffset is mandatory and cannot be change, try 0
throw UnsuccessfullNightscoutException() nsSgvV3.utcOffset = 0
} return@callWrapper createSvg(nsSgvV3)
} else if (response.code() == 400 && errorResponse?.contains("Field utcOffset cannot be modified by the client") == true) {
// there is different utcOffset than in AAPS and zero
// not possible to upload
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
errorResponse = errorResponse
)
} else throw UnknownResponseNightscoutException()
} }
override suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) { override suspend fun updateSvg(nsSgvV3: NSSgvV3): CreateUpdateResponse = callWrapper(dispatcher) {
@ -225,28 +233,36 @@ class NSAndroidClientImpl(
val remoteTreatment = nsTreatment.toRemoteTreatment() ?: throw InvalidFormatNightscoutException() val remoteTreatment = nsTreatment.toRemoteTreatment() ?: throw InvalidFormatNightscoutException()
remoteTreatment.app = "AAPS" remoteTreatment.app = "AAPS"
val response = api.createTreatment(remoteTreatment) val response = api.createTreatment(remoteTreatment)
if (response.isSuccessful) { val errorResponse = response.errorBody()?.string()
if (response.code() == 200) { if (response.code() == 200) {
return@callWrapper CreateUpdateResponse( return@callWrapper CreateUpdateResponse(
response = response.code(), response = response.code(),
identifier = null, identifier = null,
isDeduplication = true, isDeduplication = true
deduplicatedIdentifier = null, )
lastModified = null } else if (response.code() == 201) {
) return@callWrapper CreateUpdateResponse(
} else if (response.code() == 201) { response = response.code(),
return@callWrapper CreateUpdateResponse( identifier = response.body()?.result?.identifier
response = response.code(), ?: throw UnknownResponseNightscoutException(),
identifier = response.body()?.result?.identifier isDeduplication = response.body()?.result?.isDeduplication ?: false,
?: throw UnknownResponseNightscoutException(), deduplicatedIdentifier = response.body()?.result?.deduplicatedIdentifier,
isDeduplication = response.body()?.result?.isDeduplication ?: false, lastModified = response.body()?.result?.lastModified
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) {
) // Record can be originally uploaded without utcOffset
} else throw UnknownResponseNightscoutException() // because utcOffset is mandatory and cannot be change, try 0
} else { nsTreatment.utcOffset = 0
throw UnsuccessfullNightscoutException() return@callWrapper createTreatment(nsTreatment)
} } else if (response.code() == 400 && errorResponse?.contains("Field utcOffset cannot be modified by the client") == true) {
// there is different utcOffset than in AAPS and zero
// not possible to upload
return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
errorResponse = errorResponse
)
} else throw UnknownResponseNightscoutException()
} }
override suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) { override suspend fun updateTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) {

View file

@ -5,5 +5,6 @@ class CreateUpdateResponse(
val identifier: String?, val identifier: String?,
val isDeduplication: Boolean? = false, val isDeduplication: Boolean? = false,
val deduplicatedIdentifier: String? = null, val deduplicatedIdentifier: String? = null,
val lastModified: Long? = null val lastModified: Long? = null,
val errorResponse: String? = null
) )

View file

@ -153,6 +153,7 @@ class NSClientPlugin @Inject constructor(
if (activePlugin.activeBgSource is DoingOwnUploadSource) { if (activePlugin.activeBgSource is DoingOwnUploadSource) {
preferenceFragment.findPreference<SwitchPreference>(rh.gs(info.nightscout.core.utils.R.string.key_do_ns_upload))?.isVisible = false preferenceFragment.findPreference<SwitchPreference>(rh.gs(info.nightscout.core.utils.R.string.key_do_ns_upload))?.isVisible = false
} }
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_client_token))?.isVisible = false
} }
override val hasWritePermission: Boolean get() = nsClientService?.hasWriteAuth ?: false override val hasWritePermission: Boolean get() = nsClientService?.hasWriteAuth ?: false

View file

@ -70,6 +70,10 @@ import info.nightscout.shared.utils.DateUtil
import info.nightscout.shared.utils.T import info.nightscout.shared.utils.T
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 kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -115,6 +119,7 @@ class NSClientV3Plugin @Inject constructor(
} }
private val disposable = CompositeDisposable() private val disposable = CompositeDisposable()
private val 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() private val listLog: MutableList<EventNSClientNewLog> = ArrayList()
@ -141,7 +146,6 @@ class NSClientV3Plugin @Inject constructor(
internal var firstLoadContinueTimestamp = LastModified(LastModified.Collections()) // timestamp of last fetched data for every collection during initial load internal var firstLoadContinueTimestamp = LastModified(LastModified.Collections()) // timestamp of last fetched data for every collection during initial load
override fun onStart() { override fun onStart() {
// context.bindService(Intent(context, NSClientService::class.java), mConnection, Context.BIND_AUTO_CREATE)
super.onStart() super.onStart()
lastLoadedSrvModified = Json.decodeFromString( lastLoadedSrvModified = Json.decodeFromString(
@ -221,6 +225,7 @@ class NSClientV3Plugin @Inject constructor(
preferenceFragment.findPreference<SwitchPreference>(rh.gs(info.nightscout.core.utils.R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false preferenceFragment.findPreference<SwitchPreference>(rh.gs(info.nightscout.core.utils.R.string.key_ns_create_announcements_from_carbs_req))?.isVisible = false
} }
preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_tbr_eb))?.isVisible = config.isEngineeringMode() preferenceFragment.findPreference<SwitchPreference>(rh.gs(R.string.key_ns_receive_tbr_eb))?.isVisible = config.isEngineeringMode()
preferenceFragment.findPreference<SwitchPreference>(rh.gs(info.nightscout.core.utils.R.string.key_nsclientinternal_api_secret))?.isVisible = false
} }
override val hasWritePermission: Boolean get() = nsAndroidClient?.lastStatus?.apiPermissions?.isFull() ?: false override val hasWritePermission: Boolean get() = nsAndroidClient?.lastStatus?.apiPermissions?.isFull() ?: false
@ -335,7 +340,7 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairGlucoseValue -> dataPair.value.toNSSvgV3() is DataSyncSelector.PairGlucoseValue -> dataPair.value.toNSSvgV3()
else -> null else -> null
}?.let { data -> }?.let { data ->
runBlocking { 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(
@ -354,10 +359,11 @@ class NSClientV3Plugin @Inject constructor(
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}"))
400 -> rxBus.send(EventNSClientNewLog("FAIL", "${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@runBlocking return@launch
} }
} }
when (dataPair) { when (dataPair) {
@ -387,7 +393,7 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairFood -> dataPair.value.toNSFood() is DataSyncSelector.PairFood -> dataPair.value.toNSFood()
else -> null else -> null
}?.let { data -> }?.let { data ->
runBlocking { 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(
@ -406,10 +412,11 @@ class NSClientV3Plugin @Inject constructor(
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}"))
400 -> rxBus.send(EventNSClientNewLog("FAIL", "${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@runBlocking return@launch
} }
} }
when (dataPair) { when (dataPair) {
@ -465,7 +472,7 @@ class NSClientV3Plugin @Inject constructor(
is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent() is DataSyncSelector.PairOfflineEvent -> dataPair.value.toNSOfflineEvent()
else -> null else -> null
}?.let { data -> }?.let { data ->
runBlocking { 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(
@ -484,10 +491,11 @@ class NSClientV3Plugin @Inject constructor(
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}"))
400 -> rxBus.send(EventNSClientNewLog("FAIL", "${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@runBlocking return@launch
} }
} }
when (dataPair) { when (dataPair) {

View file

@ -18,7 +18,7 @@ abstract class DiaconnHistoryDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION = 1 const val VERSION = 2
fun build(context: Context) = fun build(context: Context) =
Room.databaseBuilder( Room.databaseBuilder(