All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.com.wisetrack.sdk.PackageHandler.kt Maven / Gradle / Ivy

There is a newer version: 1.5.8-alpha
Show newest version
package com.wisetrack.sdk

import android.content.Context
import com.wisetrack.sdk.network.IActivityPackageSender
import com.wisetrack.sdk.scheduler.SingleThreadCachedScheduler
import com.wisetrack.sdk.scheduler.ThreadScheduler
import org.json.JSONObject
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicBoolean

/**
@author hamed (@hamed-hsb)
 * @since 12th October 2021
 */

class PackageHandler(
    activityHandler: IActivityHandler?,
    context: Context?,
    startsSending: Boolean,
    packageHandlerActivityPackageSender: IActivityPackageSender?,
    val wiseTrackConfig: WiseTrackConfig
) : IPackageHandler, IActivityPackageSender.ResponseDataCallbackSubscriber,IActivityPackageSender.ResponseConfigDataCallbackSubscriber {

    companion object {
        private const val PACKAGE_QUEUE_FILENAME = "WiseTrackIoPackageQueue"
        private const val PACKAGE_QUEUE_NAME = "Package queue"

        fun deleteState(context: Context) {
            deletePackageQueue(context)
        }

        private fun deletePackageQueue(context: Context): Boolean {
            return context.deleteFile(PACKAGE_QUEUE_FILENAME)
        }
    }

    private var scheduler: ThreadScheduler? = null
    private var activityPackageSender: IActivityPackageSender? = null
    private var activityHandlerWeakRef: WeakReference? = null
    private var packageQueue: ArrayList? = null
    private var isSending: AtomicBoolean? = null
    private var paused = false

    private var isSDKSecure = false
    private var isFirstConfigPackage = true

    private var context: Context? = null
    private var logger: ILogger? = null
    private var backoffStrategy: BackoffStrategy?
    private var backoffStrategyForInstallSession: BackoffStrategy

    init {
        scheduler = SingleThreadCachedScheduler("PackageHandler")
        logger = WiseTrackFactory.getLogger()
        backoffStrategy = WiseTrackFactory.packageHandlerBackoffStrategy
        backoffStrategyForInstallSession = WiseTrackFactory.installSessionBackoffStrategy!!
        init(activityHandler, context, startsSending, packageHandlerActivityPackageSender)
        scheduler!!.submit { initI() }
    }

    override fun init(
        activityHandler: IActivityHandler?,
        context: Context?,
        startsSending: Boolean,
        packageHandlerActivityPackageSender: IActivityPackageSender?
    ) {
        activityHandlerWeakRef = WeakReference(activityHandler)
        this.context = context
        paused = !startsSending
        activityPackageSender = packageHandlerActivityPackageSender

    }



    // add a package to the queue
    override fun addPackage(activityPackage: ActivityPackage) {
        scheduler!!.submit { addI(activityPackage) }
    }

    // try to send the oldest package
    override fun sendFirstPackage() {
        scheduler!!.submit { sendFirstI() }
    }

    override fun onResponseDataCallback(responseData: ResponseData) {
        logger!!.debug("Got response in PackageHandler")
        val activityHandler = activityHandlerWeakRef!!.get()
        if (activityHandler != null &&
            responseData.trackingState === TrackingState.OPTED_OUT
        ) {
            activityHandler.gotOptOutResponse()
        }
        if (!responseData.willRetry) {
            scheduler!!.submit { sendNextI() }
            activityHandler?.finishedTrackingActivity(responseData)
            return
        }
        activityHandler?.finishedTrackingActivity(responseData)
        val runnable = Runnable {
            logger!!.verbose("Package handler can send")
            isSending!!.set(false)

            // Try to send the same package after sleeping
            sendFirstPackage()
        }
        if (responseData.activityPackage == null) {
            runnable.run()
            return
        }
        val retries = responseData.activityPackage!!.increaseRetries()
        val waitTimeMilliSeconds: Long

        val sharedPreferencesManager = SharedPreferencesManager.getDefaultInstance(context!!)

        waitTimeMilliSeconds = if (responseData.activityPackage!!.activityKind ===
            ActivityKind.SESSION && !sharedPreferencesManager!!.getInstallTracked()
        ) {
            Util.getWaitingTime(retries, backoffStrategyForInstallSession)
        } else {
            Util.getWaitingTime(retries, backoffStrategy!!)
        }
        val waitTimeSeconds = waitTimeMilliSeconds / 1000.0
        val secondsString = Util.SecondsDisplayFormat.format(waitTimeSeconds)
        logger!!.verbose("Waiting for $secondsString seconds before retrying the $retries time")
        scheduler!!.schedule(runnable, waitTimeMilliSeconds)
    }

    override fun onResponseConfigDataCallback(response: String) {

    }

    // interrupt the sending loop after the current request has finished
    override fun pauseSending() {
        paused = true
    }

    // allow sending requests again
    override fun resumeSending() {
        paused = false
    }

    override fun updatePackages(sessionParameters: SessionParameters?) {
        val sessionParametersCopy: SessionParameters? = sessionParameters?.deepCopy()
        scheduler!!.submit { updatePackagesI(sessionParametersCopy) }
    }

    override fun flush() {
        scheduler!!.submit { flushI() }
    }


    override fun teardown() {
        logger!!.verbose("PackageHandler teardown")
        if (scheduler != null) {
            scheduler!!.teardown()
        }
        activityHandlerWeakRef?.clear()
        packageQueue?.clear()
        scheduler = null
        activityHandlerWeakRef = null
        packageQueue = null
        isSending = null
        context = null
        logger = null
        backoffStrategy = null
    }

    // internal methods run in dedicated queue thread
    private fun initI() {
        isSending = AtomicBoolean()
        readPackageQueueI()
    }

    private fun addI(newPackage: ActivityPackage) {
        packageQueue!!.add(newPackage)
        logger!!.debug("Added package ${packageQueue!!.size} ($newPackage)")
        logger!!.verbose(newPackage.getExtendedString())
        writePackageQueueI()
    }

    private fun sendFirstI() {
        if (packageQueue!!.isEmpty()) {
            return
        }
        if (paused) {
            logger!!.debug("Package handler is paused")
            return
        }
        if (isSending!!.getAndSet(true)) {
            logger!!.verbose("Package handler is already sending")
            return
        }
        val sendingParameters = generateSendingParametersI()
        val firstPackage = packageQueue!![0]

        if (!isFirstConfigPackage && isSDKSecure) {

        }

        activityPackageSender!!.sendActivityPackage(
            firstPackage,
            sendingParameters,
            this
        )
    }

    private fun generateSendingParametersI(): HashMap {
        val sendingParameters = HashMap()
        val now = System.currentTimeMillis()
        val dateString = Util.dateFormatter.format(now)
        PackageBuilder.addString(sendingParameters, "sent_at", dateString)
        val queueSize = packageQueue!!.size - 1
        if (queueSize > 0) {
            PackageBuilder.addLong(sendingParameters, "queue_size", queueSize.toLong())
        }
        return sendingParameters
    }

    private fun sendNextI() {
        if (packageQueue!!.isEmpty()) {
            return
        }
        packageQueue!!.removeAt(0)
        writePackageQueueI()
        isSending!!.set(false)
        logger!!.verbose("Package handler can send")
        sendFirstI()
    }

    fun updatePackagesI(sessionParameters: SessionParameters?) {
        if (sessionParameters == null) {
            return
        }
        logger!!.debug("Updating package handler queue")
        sessionParameters.callbackParameters?.let {
            logger!!.verbose("Session callback parameters: %s",
                it.toString())
        }
        sessionParameters.partnerParameters?.let {
            logger!!.verbose("Session partner parameters: %s",
                it
            )
        }
        for (activityPackage in packageQueue!!) {
            val parameters = activityPackage.parameters
            // callback parameters
            val mergedCallbackParameters: HashMap? = Util.mergeParameters(
                sessionParameters.callbackParameters,
                activityPackage.callbackParameters,
                "Callback"
            )
            PackageBuilder.addMapJson(
                parameters!!,
                Constants.CALLBACK_PARAMETERS,
                mergedCallbackParameters
            )
            // partner parameters
            val mergedPartnerParameters: HashMap? = Util.mergeParameters(
                sessionParameters.partnerParameters,
                activityPackage.partnerParameters,
                "Partner"
            )
            PackageBuilder.addMapJson(
                parameters,
                Constants.PARTNER_PARAMETERS,
                mergedPartnerParameters
            )
        }
        writePackageQueueI()
    }

    private fun flushI() {
        packageQueue!!.clear()
        writePackageQueueI()
    }

    private fun readPackageQueueI() {
        packageQueue = try {
            Util.readObject(
                context!!,
                PACKAGE_QUEUE_FILENAME,
                PACKAGE_QUEUE_NAME,
                ArrayList::class.java as Class?>
            )
        } catch (e: Exception) {
            logger!!.error("Failed to read $PACKAGE_QUEUE_NAME file (${e.message!!})")
            logger!!.report("Failed to read $PACKAGE_QUEUE_NAME file (${e.message!!})")
            null
        }
        if (packageQueue != null) {
            logger!!.debug("Package handler read ${packageQueue!!.size} packages")
        } else {
            packageQueue = java.util.ArrayList()
        }
    }

    private fun writePackageQueueI() {
        Util.writeObject(
            packageQueue,
            context!!, PACKAGE_QUEUE_FILENAME, PACKAGE_QUEUE_NAME
        )
        logger!!.debug("Package handler wrote ${packageQueue!!.size} packages")
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy