From beb4e004bf6382c4755b859da9d5cd61cf1718b0 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Sun, 14 Jul 2019 15:01:12 +0100 Subject: [PATCH] better null checks --- .../general/tidepool/TidepoolPlugin.kt | 13 ++- .../general/tidepool/comm/InfoInterceptor.kt | 8 +- .../plugins/general/tidepool/comm/Session.kt | 11 +- .../general/tidepool/comm/TidepoolUploader.kt | 106 ++++++++++-------- .../general/tidepool/comm/UploadChunk.kt | 3 +- .../tidepool/elements/ProfileElement.kt | 22 +++- .../general/tidepool/utils/RateLimit.kt | 10 +- .../androidaps/utils/BolusWizard.kt | 4 +- 8 files changed, 103 insertions(+), 74 deletions(-) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt index 18b3ed5ad5..90f60d0542 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/TidepoolPlugin.kt @@ -5,6 +5,7 @@ import android.text.Spanned import info.nightscout.androidaps.Constants import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R +import info.nightscout.androidaps.db.BgReading import info.nightscout.androidaps.events.EventNetworkChange import info.nightscout.androidaps.events.EventNewBG import info.nightscout.androidaps.events.EventPreferenceChange @@ -30,7 +31,6 @@ import io.reactivex.schedulers.Schedulers import org.slf4j.LoggerFactory import java.util.* - object TidepoolPlugin : PluginBase(PluginDescription() .mainType(PluginType.GENERAL) .pluginName(R.string.tidepool) @@ -39,6 +39,7 @@ object TidepoolPlugin : PluginBase(PluginDescription() .preferencesId(R.xml.pref_tidepool) .description(R.string.description_tidepool) ) { + private val log = LoggerFactory.getLogger(L.TIDEPOOL) private var disposable: CompositeDisposable = CompositeDisposable() @@ -75,15 +76,17 @@ object TidepoolPlugin : PluginBase(PluginDescription() disposable += RxBus .toObservable(EventNewBG::class.java) .observeOn(Schedulers.io()) - .subscribe({ event -> - if (event.bgReading!!.date < TidepoolUploader.getLastEnd()) - TidepoolUploader.setLastEnd(event.bgReading.date) + .filter { it.bgReading != null } // better would be optional in API level >24 + .map { it.bgReading } + .subscribe { bgReading -> + if (bgReading!!.date < TidepoolUploader.getLastEnd()) + TidepoolUploader.setLastEnd(bgReading.date) if (isEnabled(PluginType.GENERAL) && (!SP.getBoolean(R.string.key_tidepool_only_while_charging, false) || ChargingStateReceiver.isCharging()) && (!SP.getBoolean(R.string.key_tidepool_only_while_unmetered, false) || NetworkChangeReceiver.isWifiConnected()) && RateLimit.rateLimit("tidepool-new-data-upload", T.mins(4).secs().toInt())) doUpload() - }, {}) + } disposable += RxBus .toObservable(EventPreferenceChange::class.java) .observeOn(Schedulers.io()) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/InfoInterceptor.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/InfoInterceptor.kt index b5ea25a151..ca3c3e0483 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/InfoInterceptor.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/InfoInterceptor.kt @@ -19,14 +19,14 @@ class InfoInterceptor(tag: String) : Interceptor { @Throws(IOException::class) override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() - if (request?.body() != null) { + request?.body()?.let { if (L.isEnabled(L.TIDEPOOL)) { - log.debug("Interceptor Body size: " + request.body()!!.contentLength()) + log.debug("Interceptor Body size: " + it.contentLength()) val requestBuffer = Buffer() - request.body()!!.writeTo(requestBuffer) + it.writeTo(requestBuffer) log.debug("Interceptor Body: " + requestBuffer.readUtf8()) } } - return chain.proceed(request!!) + return chain.proceed(request) } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/Session.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/Session.kt index 8d81399ee9..684f66f543 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/Session.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/Session.kt @@ -4,7 +4,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.messages.AuthReplyMes import info.nightscout.androidaps.plugins.general.tidepool.messages.DatasetReplyMessage import okhttp3.Headers -class Session (var authHeader: String?, private var sessionTokenHeader: String) { +class Session(var authHeader: String?, private var sessionTokenHeader: String) { val service = TidepoolUploader.getRetrofitInstance()?.create(TidepoolApiService::class.java) @@ -28,9 +28,12 @@ class Session (var authHeader: String?, private var sessionTokenHeader: String) if (obj is AuthReplyMessage) { authReply = obj } else if (obj is List<*>) { - val list = obj as List<*>? - if (list!!.isNotEmpty() && list[0] is DatasetReplyMessage) { - datasetReply = list[0] as DatasetReplyMessage + val list = obj as? List<*>? + + list?.getOrNull(0)?.let { + if (it is DatasetReplyMessage) { + datasetReply = it + } } } else if (obj is DatasetReplyMessage) { datasetReply = obj diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt index 7271eee199..32f2f1e00b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/TidepoolUploader.kt @@ -6,8 +6,8 @@ import android.os.SystemClock import info.nightscout.androidaps.BuildConfig import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R -import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.logging.L +import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.general.tidepool.events.EventTidepoolStatus import info.nightscout.androidaps.plugins.general.tidepool.messages.* import info.nightscout.androidaps.utils.DateUtil @@ -28,7 +28,6 @@ object TidepoolUploader { private var wl: PowerManager.WakeLock? = null - private const val INTEGRATION_BASE_URL = "https://int-api.tidepool.org" private const val PRODUCTION_BASE_URL = "https://api.tidepool.org" @@ -82,10 +81,11 @@ object TidepoolUploader { // TODO failure backoff extendWakeLock(30000) session = Session(AuthRequestMessage.getAuthRequestHeader(), SESSION_TOKEN_HEADER) - if (session?.authHeader != null) { + val authHeader = session?.authHeader + if (authHeader != null) { connectionStatus = TidepoolUploader.ConnectionStatus.CONNECTING RxBus.send(EventTidepoolStatus(("Connecting"))) - val call = session!!.service?.getLogin(session?.authHeader!!) + val call = session?.service?.getLogin(authHeader) call?.enqueue(TidepoolCallback(session!!, "Login", { startSession(session!!, doUpload) @@ -105,22 +105,20 @@ object TidepoolUploader { fun testLogin(rootContext: Context) { val session = Session(AuthRequestMessage.getAuthRequestHeader(), SESSION_TOKEN_HEADER) - if (session.authHeader != null) { - val call = session.service!!.getLogin(session.authHeader!!) + session.authHeader?.let { + val call = session.service?.getLogin(it) - call.enqueue(TidepoolCallback(session, "Login", { + call?.enqueue(TidepoolCallback(session, "Login", { OKDialog.show(rootContext, MainApp.gs(R.string.tidepool), "Successfully logged into Tidepool.", null) }, { OKDialog.show(rootContext, MainApp.gs(R.string.tidepool), "Failed to log into Tidepool.\nCheck that your user name and password are correct.", null) })) - } else { - OKDialog.show(rootContext, MainApp.gs(R.string.tidepool), "Cannot do login as user credentials have not been set correctly", null) } + ?: OKDialog.show(rootContext, MainApp.gs(R.string.tidepool), "Cannot do login as user credentials have not been set correctly", null) } - private fun loginFailed() { releaseWakeLock() } @@ -173,39 +171,43 @@ object TidepoolUploader { @Synchronized fun doUpload() { - if (session == null) { - log.error("Session is null, cannot proceed") - releaseWakeLock() - return - } - extendWakeLock(60000) - session!!.iterations++ - val chunk = UploadChunk.getNext(session) - when { - chunk == null -> { - log.error("Upload chunk is null, cannot proceed") + session.let { session -> + if (session == null) { + log.error("Session is null, cannot proceed") releaseWakeLock() + return } - chunk.length == 2 -> { - if (L.isEnabled(L.TIDEPOOL)) log.debug("Empty dataset - marking as succeeded") - RxBus.send(EventTidepoolStatus(("No data to upload"))) - releaseWakeLock() - unploadNext() - } - else -> { - val body = RequestBody.create(MediaType.parse("application/json"), chunk) + extendWakeLock(60000) + session.iterations++ + val chunk = UploadChunk.getNext(session) + when { + chunk == null -> { + log.error("Upload chunk is null, cannot proceed") + releaseWakeLock() + } - RxBus.send(EventTidepoolStatus(("Uploading"))) - val call = session!!.service!!.doUpload(session!!.token!!, session!!.datasetReply!!.getUploadId()!!, body) - call.enqueue(TidepoolCallback(session!!, "Data Upload", { - setLastEnd(session!!.end) - RxBus.send(EventTidepoolStatus(("Upload completed OK"))) + chunk.length == 2 -> { + if (L.isEnabled(L.TIDEPOOL)) log.debug("Empty dataset - marking as succeeded") + RxBus.send(EventTidepoolStatus(("No data to upload"))) releaseWakeLock() unploadNext() - }, { - RxBus.send(EventTidepoolStatus(("Upload FAILED"))) - releaseWakeLock() - })) + } + + else -> { + val body = RequestBody.create(MediaType.parse("application/json"), chunk) + + RxBus.send(EventTidepoolStatus(("Uploading"))) + val call = session.service!!.doUpload(session.token!!, session.datasetReply!!.getUploadId()!!, body) + call.enqueue(TidepoolCallback(session, "Data Upload", { + setLastEnd(session.end) + RxBus.send(EventTidepoolStatus(("Upload completed OK"))) + releaseWakeLock() + unploadNext() + }, { + RxBus.send(EventTidepoolStatus(("Upload FAILED"))) + releaseWakeLock() + })) + } } } } @@ -238,10 +240,16 @@ object TidepoolUploader { } fun deleteAllData() { - if (session!!.authReply!!.userid != null) { + val session = this.session + val token = session?.token + val userid = session?.authReply?.userid + try { + requireNotNull(session) + requireNotNull(token) + requireNotNull(userid) extendWakeLock(60000) - val call = session!!.service?.deleteAllData(session!!.token!!, session!!.authReply!!.userid!!) - call?.enqueue(TidepoolCallback(session!!, "Delete all data", { + val call = session.service?.deleteAllData(token, userid) + call?.enqueue(TidepoolCallback(session, "Delete all data", { connectionStatus = TidepoolUploader.ConnectionStatus.DISCONNECTED RxBus.send(EventTidepoolStatus(("All data removed OK"))) releaseWakeLock() @@ -250,7 +258,7 @@ object TidepoolUploader { RxBus.send(EventTidepoolStatus(("All data remove FAILED"))) releaseWakeLock() })) - } else { + } catch (e: IllegalArgumentException) { log.error("Got login response but cannot determine userId - cannot proceed") } } @@ -271,7 +279,6 @@ object TidepoolUploader { } } - @Synchronized private fun extendWakeLock(ms: Long) { if (wl == null) { @@ -286,12 +293,13 @@ object TidepoolUploader { @Synchronized private fun releaseWakeLock() { - if (wl == null) return - if (wl!!.isHeld) { - try { - wl!!.release() - } catch (e: Exception) { - log.error("Error releasing wakelock: $e") + wl?.let { + if (it.isHeld) { + try { + it.release() + } catch (e: Exception) { + log.error("Error releasing wakelock: $e") + } } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt index 81bd256d4b..40cab06f4c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/comm/UploadChunk.kt @@ -120,8 +120,7 @@ object UploadChunk { val pss = MainApp.getDbHelper().getProfileSwitchEventsFromTime(start, end, true) val selection = LinkedList() for (ps in pss) { - val pe = ProfileElement(ps) - selection.add(pe) + ProfileElement.newInstanceOrNull(ps)?.let { selection.add(it) } } if (selection.size > 0) RxBus.send(EventTidepoolStatus("${selection.size} ProfileSwitches selected for upload")) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt index 64cab1ab9b..93009ea7e1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/elements/ProfileElement.kt @@ -9,7 +9,7 @@ import info.nightscout.androidaps.utils.InstanceId import java.util.* import kotlin.collections.ArrayList -class ProfileElement(ps: ProfileSwitch) +class ProfileElement private constructor(ps: ProfileSwitch) : BaseElement(ps.date, UUID.nameUUIDFromBytes(("AAPS-profile" + ps.date).toByteArray()).toString()) { @Expose @@ -25,9 +25,11 @@ class ProfileElement(ps: ProfileSwitch) @Expose internal var insulinSensitivities: IsfProfile = IsfProfile() @Expose - internal var deviceId: String = TidepoolUploader.PUMPTYPE + ":" + (ConfigBuilderPlugin.getPlugin().activePump?.serialNumber() ?: InstanceId.instanceId()) + internal var deviceId: String = TidepoolUploader.PUMPTYPE + ":" + (ConfigBuilderPlugin.getPlugin().activePump?.serialNumber() + ?: InstanceId.instanceId()) @Expose - internal var deviceSerialNumber: String = ConfigBuilderPlugin.getPlugin().activePump?.serialNumber() ?: InstanceId.instanceId() + internal var deviceSerialNumber: String = ConfigBuilderPlugin.getPlugin().activePump?.serialNumber() + ?: InstanceId.instanceId() @Expose internal var clockDriftOffset: Long = 0 @Expose @@ -35,7 +37,8 @@ class ProfileElement(ps: ProfileSwitch) init { type = "pumpSettings" - val profile: Profile = ps.getProfileObject()!! + val profile: Profile? = ps.profileObject + checkNotNull(profile) for (br in profile.basalValues) basalSchedules.Normal.add(BasalRate(br.timeAsSeconds * 1000, br.value)) for (target in profile.singleTargets) @@ -94,4 +97,15 @@ class ProfileElement(ps: ProfileSwitch) internal var amount: Double ) + companion object { + @JvmStatic + fun newInstanceOrNull(ps: ProfileSwitch): ProfileElement? = try { + ProfileElement(ps) + } catch (e: Throwable) { + null + } + } + } + + diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt index b7bdd6194b..88f09abdc2 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/tidepool/utils/RateLimit.kt @@ -16,10 +16,12 @@ object RateLimit { @Synchronized fun rateLimit(name: String, seconds: Int): Boolean { // check if over limit - if (rateLimits.containsKey(name) && DateUtil.now() - rateLimits[name]!! < T.secs(seconds.toLong()).msecs()) { - if (L.isEnabled(L.TIDEPOOL)) - log.debug("$name rate limited: $seconds seconds") - return false + rateLimits[name]?.let { + if (DateUtil.now() - it < T.secs(seconds.toLong()).msecs()) { + if (L.isEnabled(L.TIDEPOOL)) + log.debug("$name rate limited: $seconds seconds") + return false + } } // not over limit rateLimits[name] = DateUtil.now() diff --git a/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt b/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt index 6f695fc401..e9a1b180c2 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/BolusWizard.kt @@ -188,7 +188,7 @@ class BolusWizard @JvmOverloads constructor(val profile: Profile, calculatedTotalInsulin = 0.0 } - val bolusStep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription!!.bolusStep + val bolusStep = ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.bolusStep ?: 0.1 calculatedTotalInsulin = Round.roundTo(calculatedTotalInsulin, bolusStep) insulinAfterConstraints = MainApp.getConstraintChecker().applyBolusConstraints(Constraint(calculatedTotalInsulin)).value() @@ -318,7 +318,7 @@ class BolusWizard @JvmOverloads constructor(val profile: Profile, detailedBolusInfo.boluscalc = nsJSON() detailedBolusInfo.source = Source.USER detailedBolusInfo.notes = notes - if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription!!.storesCarbInfo) { + if (detailedBolusInfo.insulin > 0 || ConfigBuilderPlugin.getPlugin().activePump?.pumpDescription?.storesCarbInfo == true) { ConfigBuilderPlugin.getPlugin().commandQueue.bolus(detailedBolusInfo, object : Callback() { override fun run() { if (!result.success) {