better null checks

This commit is contained in:
Milos Kozak 2019-07-14 15:01:12 +01:00
parent 6d2e159edb
commit beb4e004bf
8 changed files with 103 additions and 74 deletions

View file

@ -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())

View file

@ -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)
}
}

View file

@ -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

View file

@ -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<AuthReplyMessage>(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<AuthReplyMessage>(session, "Login", {
call?.enqueue(TidepoolCallback<AuthReplyMessage>(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,32 +171,35 @@ object TidepoolUploader {
@Synchronized
fun doUpload() {
session.let { session ->
if (session == null) {
log.error("Session is null, cannot proceed")
releaseWakeLock()
return
}
extendWakeLock(60000)
session!!.iterations++
session.iterations++
val chunk = UploadChunk.getNext(session)
when {
chunk == null -> {
log.error("Upload chunk is null, cannot proceed")
releaseWakeLock()
}
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)
RxBus.send(EventTidepoolStatus(("Uploading")))
val call = session!!.service!!.doUpload(session!!.token!!, session!!.datasetReply!!.getUploadId()!!, body)
call.enqueue(TidepoolCallback<UploadReplyMessage>(session!!, "Data Upload", {
setLastEnd(session!!.end)
val call = session.service!!.doUpload(session.token!!, session.datasetReply!!.getUploadId()!!, body)
call.enqueue(TidepoolCallback<UploadReplyMessage>(session, "Data Upload", {
setLastEnd(session.end)
RxBus.send(EventTidepoolStatus(("Upload completed OK")))
releaseWakeLock()
unploadNext()
@ -209,6 +210,7 @@ object TidepoolUploader {
}
}
}
}
private fun unploadNext() {
if (getLastEnd() < DateUtil.now() - T.mins(1).msecs()) {
@ -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,14 +293,15 @@ object TidepoolUploader {
@Synchronized
private fun releaseWakeLock() {
if (wl == null) return
if (wl!!.isHeld) {
wl?.let {
if (it.isHeld) {
try {
wl!!.release()
it.release()
} catch (e: Exception) {
log.error("Error releasing wakelock: $e")
}
}
}
}
}

View file

@ -120,8 +120,7 @@ object UploadChunk {
val pss = MainApp.getDbHelper().getProfileSwitchEventsFromTime(start, end, true)
val selection = LinkedList<ProfileElement>()
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"))

View file

@ -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
}
}
}

View file

@ -16,11 +16,13 @@ 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()) {
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()
return true

View file

@ -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) {