TP-66620 | Alfred resource manager (#179)

Co-authored-by: Varun Jain <varun.jain@navi.com>
This commit is contained in:
Sayed Owais Ali
2024-05-29 20:48:34 +05:30
committed by GitHub
parent 737cef6222
commit 2253fd9226
18 changed files with 574 additions and 337 deletions

View File

@@ -46,7 +46,7 @@ import com.navi.alfred.utils.buildNegativeCaseEvent
import com.navi.alfred.utils.captureBottomSheet
import com.navi.alfred.utils.captureScreen
import com.navi.alfred.utils.captureScreenshotOfCustomView
import com.navi.alfred.utils.checkDbBeforeStartRecording
import com.navi.alfred.utils.checkDbAndDeleteCorruptScreenshots
import com.navi.alfred.utils.createBitmapForView
import com.navi.alfred.utils.getCruiseConfig
import com.navi.alfred.utils.getTouchEvent
@@ -65,6 +65,7 @@ import java.lang.ref.WeakReference
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import okhttp3.Request
@@ -94,7 +95,6 @@ object AlfredManager {
internal var sessionStartRecordingTimeForCrash: Long? = null
internal var eventStartRecordingTimeForCrash: Long? = null
internal var timer: Timer? = null
internal var zipUploadRetryCount: Int = 0
internal var currentActivity: WeakReference<Activity>? = null
internal lateinit var alfredDataBase: AlfredDatabase
internal lateinit var screenShotDao: ScreenShotDao
@@ -103,16 +103,27 @@ object AlfredManager {
internal lateinit var analyticsDao: AnalyticsDAO
internal lateinit var negativeCaseDao: NegativeCaseDao
internal lateinit var failureEventDao: FailureEventDao
internal lateinit var zipFileDetails: List<ZipDetailsHelper>
internal lateinit var zipFileDetailsList: List<ZipDetailsHelper>
internal lateinit var applicationContext: Context
internal const val imageThreshHoldValue: Int = 60
internal const val imageSecondThreshHoldValue: Int = 100
var dialog: Dialog? = null
lateinit var sensitiveComposeRepository: ComposeMaskingRepoImpl
internal var isCriticalUserJourneyActive: AtomicBoolean = AtomicBoolean(false)
internal var hasCheckedDb: Boolean = true
internal var criticalJourneyResponseCode: Int = 0
internal var criticalJourneyResponseMessage: String = ""
fun init(config: AlfredConfig, context: Context) {
fun init(
config: AlfredConfig,
context: Context,
criticalJourneyResponseCode: Int,
criticalJourneyResponseMessage: String
) {
this.config = config
this.applicationContext = context
this.criticalJourneyResponseCode = criticalJourneyResponseCode
this.criticalJourneyResponseMessage = criticalJourneyResponseMessage
AlfredRetrofitProvider.init(applicationContext)
AlfredFailureRetrofitProvider.init(applicationContext)
config.setCruiseAttributes()
@@ -135,7 +146,7 @@ object AlfredManager {
screenShotTimer?.cancel()
screenShotTimer = Timer()
if (!hasRecordingStarted) {
checkDbBeforeStartRecording()
checkDbAndDeleteCorruptScreenshots()
config.setAlfredSessionId()
config.setAlfredEventId()
config.setSessionStartRecordingTime()
@@ -148,6 +159,7 @@ object AlfredManager {
moduleName = moduleName
)
AlfredDispatcher.addTaskToQueue(AddEventTask(startRecordingEvent, context))
hasCheckedDb = false
}
currentActivity = WeakReference(activity)
setCurrentScreenName(screenName)
@@ -249,6 +261,7 @@ object AlfredManager {
isAppInBackground = true
hasRecordingStarted = false
screenShotTimer?.cancel()
isCriticalUserJourneyActive.set(false)
val appBackgroundView =
LayoutInflater.from(applicationContext)
.inflate(R.layout.app_background_screen, null)
@@ -488,4 +501,8 @@ object AlfredManager {
fun isSensitiveComposeRepositoryInitialized(): Boolean {
return this::sensitiveComposeRepository.isInitialized
}
fun updateCriticalUserJourneyStatus(status: Boolean) {
isCriticalUserJourneyActive.set(status)
}
}

View File

@@ -9,6 +9,8 @@ package com.navi.alfred.db
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.navi.alfred.db.dao.AnalyticsDAO
import com.navi.alfred.db.dao.ApiMetricDao
import com.navi.alfred.db.dao.FailureEventDao
@@ -21,6 +23,8 @@ import com.navi.alfred.db.model.FailureEvent
import com.navi.alfred.db.model.NegativeCase
import com.navi.alfred.db.model.ScreenShotPathHelper
import com.navi.alfred.db.model.ZipDetailsHelper
import com.navi.alfred.utils.AlfredConstants.DB_VERSION_V5
import com.navi.alfred.utils.AlfredConstants.DB_VERSION_V6
@Database(
entities =
@@ -32,7 +36,7 @@ import com.navi.alfred.db.model.ZipDetailsHelper
NegativeCase::class,
FailureEvent::class
],
version = 5,
version = 6,
exportSchema = true
)
abstract class AlfredDatabase : RoomDatabase() {
@@ -48,3 +52,15 @@ abstract class AlfredDatabase : RoomDatabase() {
abstract fun failureEventDao(): FailureEventDao
}
val ALFRED_DATABASE_MIGRATION_5_6 =
object : Migration(DB_VERSION_V5, DB_VERSION_V6) {
override fun migrate(database: SupportSQLiteDatabase) {
// this migration changes schema of ZipDetailsHelper table by adding a new column
// zipUploadStatus and removing a redundant column zipFileName
database.execSQL("ALTER TABLE ZipDetailsHelper DROP COLUMN zipFileName")
database.execSQL(
"ALTER TABLE ZipDetailsHelper ADD COLUMN zipUploadStatus INTEGER NOT NULL DEFAULT 0"
)
}
}

View File

@@ -22,6 +22,7 @@ object AlfredDatabaseHelper {
}
val instance =
Room.databaseBuilder(context, AlfredDatabase::class.java, EVENT_DB_NAME)
.addMigrations(ALFRED_DATABASE_MIGRATION_5_6)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance

View File

@@ -43,6 +43,11 @@ interface ScreenShotDao {
@Query("SELECT * FROM ScreenShotPathHelper")
fun fetchAllScreenShotsPath(): List<ScreenShotPathHelper>
@Query("SELECT id FROM ScreenShotPathHelper") fun fetchAllScreenShotIds(): List<Int>
@Query("SELECT * FROM ScreenShotPathHelper WHERE id IN (:idList)")
fun fetchAllScreenShotsPathFromIds(idList: List<Int>): List<ScreenShotPathHelper>
@Query("DELETE FROM ScreenShotPathHelper WHERE id IN (:idList)")
fun deleteScreenShot(idList: List<Int>)
@@ -62,6 +67,20 @@ interface ZipDetailsDao {
fun fetchAllZipFilesDetails(): List<ZipDetailsHelper>
@Query("DELETE FROM ZipDetailsHelper WHERE id = :id") fun deleteZipFileDetail(id: Int)
@Query("SELECT count(*) FROM ZipDetailsHelper WHERE alfredEventId = :zipFileName")
fun zipDetailExists(zipFileName: String): Boolean
@Query("SELECT ZipDetailsHelper.* FROM ZipDetailsHelper WHERE alfredEventId = :zipFileName")
fun getZipFileDetail(zipFileName: String): ZipDetailsHelper?
@Query("DELETE FROM ZipDetailsHelper WHERE alfredEventId = :zipFileName")
fun deleteZipFileDetail(zipFileName: String)
@Query(
"UPDATE ZipDetailsHelper SET zipUploadStatus = :status WHERE alfredEventId = :zipFileName"
)
fun updateZipUploadStatus(zipFileName: String, status: Boolean)
}
@Dao

View File

@@ -33,9 +33,9 @@ data class ZipDetailsHelper(
@ColumnInfo(name = "alfredSessionId") val alfredSessionId: String,
@ColumnInfo(name = "sessionStartRecordingTime") val sessionStartRecordingTime: Long,
@ColumnInfo(name = "eventStartRecordingTime") val eventStartRecordingTime: Long,
@ColumnInfo(name = "zipFileName") val zipFileName: String,
@ColumnInfo(name = "alfredEventId") val alfredEventId: String,
@ColumnInfo(name = "latestScreenshotTimestamp") val latestScreenshotTimestamp: Long
@ColumnInfo(name = "latestScreenshotTimestamp") val latestScreenshotTimestamp: Long,
@ColumnInfo(name = "zipUploadStatus") val zipUploadStatus: Boolean
) {
@PrimaryKey(autoGenerate = true) var id: Int = 0
}

View File

@@ -8,7 +8,6 @@
package com.navi.alfred.model
import android.os.Parcelable
import com.navi.alfred.db.model.ScreenShotPathHelper
import java.util.*
import kotlinx.parcelize.Parcelize
@@ -19,9 +18,8 @@ data class WorkManagerFailureInputData(
var alfredSessionId: String? = "",
var sessionStartRecordingTime: Long = 0L,
var eventStartRecordingTime: Long = 0L,
var screenShots: List<ScreenShotPathHelper> = emptyList(),
val id: UUID,
val zipFileName: String,
val alfredEventId: String,
val latestScreenshotTimestamp: Long = 0L
val latestScreenshotTimestamp: Long = 0L,
var retryCount: Int = 0
)

View File

@@ -57,15 +57,12 @@ object AlfredFailureRetrofitProvider {
.build()
}
} else {
val errorMessage = ErrorMessage()
errorMessage.statusCode = ApiConstants.NO_INTERNET
errorMessage.message = AlfredConstants.NO_INTERNET_MESSAGE
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_2)
.code(errorMessage.statusCode.orZero())
.code(ApiConstants.NO_INTERNET.orZero())
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
.message(errorMessage.message.orEmpty())
.message(AlfredConstants.NO_INTERNET_MESSAGE.orEmpty())
.build()
}
AlfredApiLogsManager.getAlfredApiLogsProvider()
@@ -74,6 +71,7 @@ object AlfredFailureRetrofitProvider {
}
fun init(context: Context) {
val alfredResourceManagerInterceptor = AlfredResourceManagerInterceptor()
okHttpClient =
OkHttpClient.Builder()
.apply {
@@ -90,6 +88,9 @@ object AlfredFailureRetrofitProvider {
)
}
addInterceptor(networkInterceptor)
addInterceptor(
alfredResourceManagerInterceptor.resourceManagerNetworkInterceptor
)
connectionPool(ConnectionPool(0, 5, TimeUnit.MINUTES))
.protocols(listOf(Protocol.HTTP_1_1))
}

View File

@@ -0,0 +1,80 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.alfred.network
import android.content.Intent
import android.util.Log
import com.navi.alfred.AlfredManager
import com.navi.alfred.model.ErrorMessage
import com.navi.alfred.network.model.RequestInfo
import com.navi.alfred.utils.AlfredConstants.BROADCAST_ACTION_TYPE
import com.navi.alfred.utils.AlfredConstants.BROADCAST_ERROR_MESSAGE
import com.navi.alfred.utils.AlfredConstants.BROADCAST_EXCEPTION
import com.navi.alfred.utils.AlfredConstants.BROADCAST_REQUEST
import com.navi.alfred.utils.AlfredConstants.HEADER_APP_REQUEST_ID
import com.navi.alfred.utils.AlfredConstants.HEADER_X_TARGET
import com.navi.alfred.utils.handleException
import com.navi.alfred.utils.orZero
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
internal class AlfredResourceManagerInterceptor {
val resourceManagerNetworkInterceptor: Interceptor
get() = Interceptor { chain ->
val request = chain.request()
val response =
if (!AlfredManager.isCriticalUserJourneyActive.get()) {
try {
chain.proceed(request).newBuilder().build()
} catch (e: Exception) {
val errorMessage = handleException(e)
// send failure broadcast if the request is critical
setNetworkFailureBroadcast(e, errorMessage, request)
// A mocked response in case of n/w exception
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_2)
.code(errorMessage.statusCode.orZero())
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
.message(errorMessage.message.orEmpty())
.build()
}
} else {
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_2)
.code(AlfredManager.criticalJourneyResponseCode.orZero())
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
.message(AlfredManager.criticalJourneyResponseMessage.orEmpty())
.build()
}
AlfredApiLogsManager.getAlfredApiLogsProvider()
?.sendApiLog(request = request, response = response)
response
}
private fun setNetworkFailureBroadcast(
e: Exception,
errorMessage: ErrorMessage,
request: Request
) {
Log.d("Alfred", "AlfredResourceManagerInterceptor: setNetworkFailureBroadcast")
val intent = Intent(BROADCAST_ACTION_TYPE)
val requestInfo =
RequestInfo(
request.url.toString(),
request.headers[HEADER_X_TARGET],
request.headers[HEADER_APP_REQUEST_ID]
)
intent.putExtra(BROADCAST_EXCEPTION, e)
intent.putExtra(BROADCAST_ERROR_MESSAGE, errorMessage)
intent.putExtra(BROADCAST_REQUEST, requestInfo)
AlfredManager.applicationContext.sendBroadcast(intent)
}
}

View File

@@ -67,15 +67,12 @@ object AlfredRetrofitProvider {
.build()
}
} else {
val errorMessage = ErrorMessage()
errorMessage.statusCode = ApiConstants.NO_INTERNET
errorMessage.message = AlfredConstants.NO_INTERNET_MESSAGE
Response.Builder()
.request(request)
.protocol(Protocol.HTTP_2)
.code(errorMessage.statusCode.orZero())
.code(ApiConstants.NO_INTERNET.orZero())
.body(ResponseBody.create("application/json".toMediaTypeOrNull(), "{}"))
.message(errorMessage.message.orEmpty())
.message(AlfredConstants.NO_INTERNET_MESSAGE.orEmpty())
.build()
}
AlfredApiLogsManager.getAlfredApiLogsProvider()
@@ -84,6 +81,7 @@ object AlfredRetrofitProvider {
}
fun init(context: Context) {
val alfredResourceManagerInterceptor = AlfredResourceManagerInterceptor()
okHttpClient =
OkHttpClient.Builder()
.apply {
@@ -100,6 +98,9 @@ object AlfredRetrofitProvider {
)
}
addInterceptor(networkInterceptor)
addInterceptor(
alfredResourceManagerInterceptor.resourceManagerNetworkInterceptor
)
connectionPool(ConnectionPool(0, 5, TimeUnit.MINUTES))
.protocols(listOf(Protocol.HTTP_1_1))
}

View File

@@ -111,4 +111,13 @@ object AlfredConstants {
const val LATEST_SCREENSHOT_TIMESTAMP = "LATEST_SCREENSHOT_TIMESTAMP"
const val SNAPSHOT_PER_SECOND = "SNAPSHOT_PER_SECOND"
const val NO_INTERNET_MESSAGE = "No internet"
const val IS_ZIP_FILE_PREPARED = "IS_ZIP_FILE_PREPARED"
const val ZIP_UPLOAD_WORK = "ZIP_UPLOAD_WORK"
const val EVENTS_UPLOAD_WORK = "EVENTS_UPLOAD_WORK"
const val ZIP_UPLOAD_RETRY_WORK = "ZIP_UPLOAD_RETRY_WORK"
const val ZIP_FILE_DETAIL_LIST = "zipFileDetailList"
const val CRITICAL_SECTION_MESSAGE = "CRITICAL_SECTION_ENTERED"
const val SCREENSHOT_ID_LIST = "SCREENSHOT_ID_LIST"
const val DB_VERSION_V5 = 5
const val DB_VERSION_V6 = 6
}

View File

@@ -17,4 +17,5 @@ object ApiConstants {
const val API_CODE_UNKNOWN_HOST = 21
const val API_CODE_CONNECT_EXCEPTION = 22
const val API_CODE_SOCKET = 26
const val CRITICAL_SECTION = 27
}

View File

@@ -15,6 +15,7 @@ import com.navi.alfred.db.model.AnalyticsEvent
import com.navi.alfred.db.model.ApiMetricHelper
import com.navi.alfred.db.model.FailureEvent
import com.navi.alfred.db.model.NegativeCase
import com.navi.alfred.db.model.ZipDetailsHelper
import com.navi.alfred.dispatcher.AlfredDispatcher
import com.navi.alfred.model.AnalyticsRequest
import com.navi.alfred.model.BaseAttribute
@@ -94,7 +95,10 @@ internal suspend fun sendEventsToServer(
)
true
} else {
if (!isNoInternetResponse(response.code())) {
if (
!isNoInternetResponse(response.code()) &&
!isCriticalJourneyResponse(response.code())
) {
val zipNamesList: MutableList<String> = mutableListOf()
val eventIdList: MutableList<String> = mutableListOf()
events.forEach { event ->
@@ -197,7 +201,10 @@ internal suspend fun sendNegativeCaseToServer(
)
true
} else {
if (!isNoInternetResponse(response.code())) {
if (
!isNoInternetResponse(response.code()) &&
!isCriticalJourneyResponse(response.code())
) {
val failureEvent =
buildFailureEvent(
errorType = API_ERROR,
@@ -280,9 +287,8 @@ internal suspend fun sendFailureEventsToServer(workManagerFlow: Boolean? = false
)
return if (
(response.isSuccessful &&
response.code() == AlfredConstants.CODE_API_SUCCESS) or
(response.code() == AlfredConstants.CODE_API_BAD_REQUEST) or
(isNoInternetResponse(response.code()))
response.code() == AlfredConstants.CODE_API_SUCCESS) ||
(response.code() == AlfredConstants.CODE_API_BAD_REQUEST)
) {
AlfredManager.failureEventDao.deleteFailureEvents(
failureEvents.map { it.eventId }
@@ -310,76 +316,37 @@ internal suspend fun sendFailureEventsToServer(workManagerFlow: Boolean? = false
return false
}
internal fun sendAlfredSessionEvent(
dumpFlow: Boolean = false,
index: Int? = null,
currentZipName: String? = null,
latestScreenshotTimestamp: Long? = null
) {
var request: SessionRequest? = null
if (dumpFlow) {
var clientTs: Long? = null
var sessionTimeStamp: Long? = null
var sessionId: String? = null
if (index != null) {
val zipFileDetail = AlfredManager.zipFileDetails[index]
clientTs = zipFileDetail.eventStartRecordingTime
sessionTimeStamp = zipFileDetail.sessionStartRecordingTime
sessionId = zipFileDetail.alfredSessionId
} else {
clientTs = AlfredManager.eventStartRecordingTimeForCrash
sessionTimeStamp = AlfredManager.sessionStartRecordingTimeForCrash
sessionId = AlfredManager.sessionIdForCrash
}
internal fun sendAlfredSessionEvent(zipFileDetails: ZipDetailsHelper, dumpFlow: Boolean = false) {
val request =
SessionRequest(
base_attribute =
BaseAttribute(
sessionId = zipFileDetails.alfredSessionId,
eventTimeStamp = AlfredManager.config.getEventTimeStamp(),
clientTs = zipFileDetails.eventStartRecordingTime,
latestScreenshotTimestamp = zipFileDetails.latestScreenshotTimestamp,
sessionTimeStamp = zipFileDetails.sessionStartRecordingTime
),
session_upload_event_attributes =
SessionEventAttribute(
eventId = zipFileDetails.alfredEventId,
beginningDeviceAttributes =
DeviceAttributes(
battery = AlfredManager.config.batteryPercentageBeforeEventStart,
cpu = AlfredManager.config.cpuUsageBeforeEventStart,
memory = AlfredManager.config.memoryUsageBeforeEventStart,
storage = AlfredManager.config.storageUsageBeforeEventStart
),
endDeviceAttributes =
DeviceAttributes(
battery = AlfredManager.config.getBatteryPercentage(),
cpu = AlfredManager.config.getCpuUsage(),
memory = AlfredManager.config.getMemoryUsagePercentage(),
storage = AlfredManager.config.getStorageUsage()
)
)
)
request =
SessionRequest(
base_attribute =
BaseAttribute(
sessionId = sessionId,
eventTimeStamp = AlfredManager.config.getEventTimeStamp(),
clientTs = clientTs,
sessionTimeStamp = sessionTimeStamp,
latestScreenshotTimestamp = latestScreenshotTimestamp
),
session_upload_event_attributes =
SessionEventAttribute(
eventId = currentZipName,
beginningDeviceAttributes = DeviceAttributes(),
endDeviceAttributes = DeviceAttributes()
)
)
} else {
request =
SessionRequest(
base_attribute =
BaseAttribute(
sessionId = AlfredManager.config.getAlfredSessionId(),
eventTimeStamp = AlfredManager.config.getEventTimeStamp(),
clientTs = AlfredManager.config.getEventStartRecordingTime(),
latestScreenshotTimestamp = latestScreenshotTimestamp,
sessionTimeStamp = AlfredManager.config.getSessionStartRecordingTime()
),
session_upload_event_attributes =
SessionEventAttribute(
eventId = currentZipName,
beginningDeviceAttributes =
DeviceAttributes(
battery = AlfredManager.config.batteryPercentageBeforeEventStart,
cpu = AlfredManager.config.cpuUsageBeforeEventStart,
memory = AlfredManager.config.memoryUsageBeforeEventStart,
storage = AlfredManager.config.storageUsageBeforeEventStart
),
endDeviceAttributes =
DeviceAttributes(
battery = AlfredManager.config.getBatteryPercentage(),
cpu = AlfredManager.config.getCpuUsage(),
memory = AlfredManager.config.getMemoryUsagePercentage(),
storage = AlfredManager.config.getStorageUsage()
)
)
)
}
AlfredManager.coroutineScope.launch {
val response =
AlfredManager.networkRepository.sendSession(
@@ -388,21 +355,24 @@ internal fun sendAlfredSessionEvent(
request
)
if (response.isSuccessful && response.code() == AlfredConstants.CODE_API_SUCCESS) {
AlfredManager.zipDetailsDao.deleteZipFileDetail(zipFileDetails.alfredEventId)
if (!dumpFlow) {
AlfredManager.config.setEventStartRecordingTime(true)
handleDeviceAttributes()
} else {
index?.let { index ->
AlfredManager.zipDetailsDao.deleteZipFileDetail(
AlfredManager.zipFileDetails[index].id
)
}
if (AlfredManager.workFailureData.size > 0) {
AlfredManager.workFailureData.removeAt(0)
}
}
if (!AlfredManager.hasCheckedDb) {
checkDbToUploadFailedZips()
AlfredManager.hasCheckedDb = true
}
} else {
if (!isNoInternetResponse(response.code())) {
if (
!isNoInternetResponse(response.code()) &&
!isCriticalJourneyResponse(response.code())
) {
val failureEvent =
buildFailureEvent(
errorType = API_ERROR,
@@ -474,7 +444,10 @@ internal suspend fun sendIngestMetric(
)
true
} else {
if (!isNoInternetResponse(response.code())) {
if (
!isNoInternetResponse(response.code()) &&
!isCriticalJourneyResponse(response.code())
) {
val failureEvent =
buildFailureEvent(
errorType = API_ERROR,

View File

@@ -55,3 +55,7 @@ internal fun isNetworkAvailable(): Boolean {
internal fun isNoInternetResponse(responseCode: Int): Boolean {
return responseCode == ApiConstants.NO_INTERNET
}
internal fun isCriticalJourneyResponse(responseCode: Int): Boolean {
return responseCode == AlfredManager.criticalJourneyResponseCode
}

View File

@@ -243,40 +243,38 @@ internal suspend fun captureBottomSheet(
if (AlfredManager.config.getDisableDialogScreenShot()) {
return
}
if (bottomSheetView != null) {
val bottomSheetCanvasForBitmap = createBitmapForView(bottomSheetView)
val bottomSheetScreenShot =
captureScreen(
bottomSheetView,
context,
true,
screenName,
AlfredManager.coroutineScope,
bottomSheetCanvasForBitmap?.first,
bottomSheetCanvasForBitmap?.second,
moduleName = moduleName
)
val backgroundScreenShot =
captureScreen(
view,
context,
true,
screenName,
AlfredManager.coroutineScope,
rootCanvas,
rootBmp,
moduleName = moduleName
)
if (bottomSheetScreenShot != null && backgroundScreenShot != null) {
combineScreenshots(
backgroundScreenShot,
bottomSheetScreenShot,
context,
screenName,
moduleName = moduleName,
scope = AlfredManager.coroutineScope
)
}
val bottomSheetCanvasForBitmap = createBitmapForView(bottomSheetView)
val bottomSheetScreenShot =
captureScreen(
bottomSheetView,
context,
true,
screenName,
AlfredManager.coroutineScope,
bottomSheetCanvasForBitmap?.first,
bottomSheetCanvasForBitmap?.second,
moduleName = moduleName
)
val backgroundScreenShot =
captureScreen(
view,
context,
true,
screenName,
AlfredManager.coroutineScope,
rootCanvas,
rootBmp,
moduleName = moduleName
)
if (bottomSheetScreenShot != null && backgroundScreenShot != null) {
combineScreenshots(
backgroundScreenShot,
bottomSheetScreenShot,
context,
screenName,
moduleName = moduleName,
scope = AlfredManager.coroutineScope
)
}
}

View File

@@ -13,8 +13,8 @@ import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import com.google.gson.Gson
import com.navi.alfred.AlfredManager
import com.navi.alfred.db.model.ZipDetailsHelper
import com.navi.alfred.dispatcher.AlfredDispatcher
import com.navi.alfred.utils.AlfredConstants.API_ERROR
import com.navi.alfred.utils.AlfredConstants.DEFAULT_GET_PRE_SIGNED_URL_URL
@@ -26,89 +26,73 @@ import com.navi.alfred.utils.AlfredConstants.ZIP_ERROR
import com.navi.alfred.worker.AddFailureTask
import com.navi.alfred.worker.UploadEventsWorker
import com.navi.alfred.worker.UploadFileWorker
import com.navi.alfred.worker.ZipUploadRetryWorker
import java.io.File
import java.util.UUID
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.asRequestBody
import retrofit2.Response
internal suspend fun getPreSignedUrl(
zipFileName: String,
zipFileDetail: ZipDetailsHelper,
dumpFlow: Boolean = false,
index: Int? = null,
workManagerFlow: Boolean? = false,
alfredEventIdForDumpFlow: String? = null,
latestScreenshotTimestamp: Long? = null
workManagerFlow: Boolean? = false
) {
val currentZipName: String
val latestScreenshotName: Long
if (dumpFlow) {
currentZipName =
alfredEventIdForDumpFlow
?: UUID.randomUUID().toString().plus(AlfredConstants.ALFRED_EVENT_ID)
latestScreenshotName = latestScreenshotTimestamp ?: 0L
} else {
currentZipName = AlfredManager.config.getAlfredEventId()
latestScreenshotName = AlfredManager.config.getLatestScreenshotTimestamp()
AlfredManager.config.setAlfredEventId()
}
val currentZipName = zipFileDetail.alfredEventId
val bucketKey = currentZipName.plus(AlfredConstants.ZIP_FILE_EXTENSION)
val zipUploadStatus = zipFileDetail.zipUploadStatus
val response =
AlfredManager.networkRepository.getPreSignedUrl(bucketKey, AlfredManager.config.getApiKey())
if (!zipUploadStatus) {
AlfredManager.networkRepository.getPreSignedUrl(
bucketKey,
AlfredManager.config.getApiKey()
)
} else {
Response.error(AlfredConstants.CODE_API_BAD_REQUEST, null)
}
if (response.isSuccessful && response.code() == AlfredConstants.CODE_API_SUCCESS) {
checkFileExists(zipFileName, AlfredManager.applicationContext)?.let { file ->
checkFileExists(currentZipName, AlfredManager.applicationContext)?.let { file ->
response.body()?.data?.let {
uploadFile(
file,
it,
dumpFlow,
index,
zipFileName,
workManagerFlow = workManagerFlow,
currentZipName = currentZipName,
latestScreenshotTimestamp = latestScreenshotName
zipFileDetails = zipFileDetail,
uploadFile = file,
url = it,
dumpFlow = dumpFlow,
workManagerFlow = workManagerFlow
)
}
}
} else {
val failureEvent =
buildFailureEvent(
errorType = API_ERROR,
requestUrl = DEFAULT_GET_PRE_SIGNED_URL_URL.plus(bucketKey),
requestMethod = GET_METHOD,
zipName = listOf(currentZipName),
errorStatusCode = response.code().toLong(),
errorMessage = response.message(),
errorName = GET_PRE_SIGNED_URL_FAILURE
if (!isCriticalJourneyResponse(response.code())) {
val failureEvent =
buildFailureEvent(
errorType = API_ERROR,
requestUrl = DEFAULT_GET_PRE_SIGNED_URL_URL.plus(bucketKey),
requestMethod = GET_METHOD,
zipName = listOf(currentZipName),
errorStatusCode = response.code().toLong(),
errorMessage = response.message(),
errorName = GET_PRE_SIGNED_URL_FAILURE
)
AlfredDispatcher.addTaskToQueue(
AddFailureTask(failureEvent, context = AlfredManager.applicationContext)
)
AlfredDispatcher.addTaskToQueue(
AddFailureTask(failureEvent, context = AlfredManager.applicationContext)
)
}
if (!dumpFlow) {
AlfredManager.hasUploadFlowStarted = false
AlfredManager.config.getEventStartRecordingTime()?.let { eventStartRecordingTime ->
insertZipDetailsToDbForDumpingLater(
AlfredManager.config.getAlfredSessionId(),
AlfredManager.config.getSessionStartRecordingTime(),
eventStartRecordingTime,
zipFileName,
currentZipName,
latestScreenshotName
)
}
AlfredManager.config.setEventStartRecordingTime(true)
}
if (workManagerFlow == true) {
val latestScreenshotName = zipFileDetail.latestScreenshotTimestamp
uploadWorkManagerFailedZip(currentZipName, latestScreenshotName)
}
}
}
internal fun checkAndInitiateFileUploadWorkManager() {
val screenShotList = AlfredManager.screenShotDao.fetchAllScreenShotsPath()
AlfredManager.screenShotDao.deleteAllScreenShot()
ScreenShotStorageHelper.clearAll()
val screenShotIds = AlfredManager.screenShotDao.fetchAllScreenShotIds()
AlfredManager.isAppInBackground = false
AlfredManager.hasRecordingStarted = false
AlfredManager.config.clearZipFileName()
@@ -125,7 +109,7 @@ internal fun checkAndInitiateFileUploadWorkManager() {
.putString(AlfredConstants.ALFRED_SESSION_ID, alfredSessionId)
.putLong(AlfredConstants.SESSION_START_RECORDING_TIME, sessionTimestamp)
.putLong(AlfredConstants.EVENT_START_RECORDING_TIME, clientTs ?: 0L)
.putString(AlfredConstants.SCREENSHOT_LIST, Gson().toJson(screenShotList))
.putIntArray(AlfredConstants.SCREENSHOT_ID_LIST, screenShotIds.toIntArray())
.putString(AlfredConstants.ALFRED_EVENT_ID, alfredEventId)
.putLong(AlfredConstants.LATEST_SCREENSHOT_TIMESTAMP, latestScreenshotTimestamp)
.build()
@@ -145,7 +129,7 @@ internal fun buildWorkManagerForZip(requestData: Data) {
.setRequiresBatteryNotLow(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uniqueWorkName = "SESSION_UPLOAD_WORK"
val uniqueWorkName = AlfredConstants.ZIP_UPLOAD_WORK
val uniqueWorkStatus =
WorkManager.getInstance(AlfredManager.applicationContext)
.getWorkInfosForUniqueWork(uniqueWorkName)
@@ -175,7 +159,7 @@ internal fun buildWorkManagerForEvents(requestData: Data) {
.setRequiresBatteryNotLow(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uniqueWorkName = "EVENTS_UPLOAD_WORK"
val uniqueWorkName = AlfredConstants.EVENTS_UPLOAD_WORK
val uniqueWorkStatus =
WorkManager.getInstance(AlfredManager.applicationContext)
.getWorkInfosForUniqueWork(uniqueWorkName)
@@ -200,53 +184,74 @@ internal fun buildWorkManagerForEvents(requestData: Data) {
}
internal suspend fun uploadFile(
zipFileDetails: ZipDetailsHelper,
uploadFile: File,
url: String,
dumpFlow: Boolean = false,
index: Int? = null,
zipFileName: String,
workManagerFlow: Boolean? = false,
currentZipName: String? = "",
latestScreenshotTimestamp: Long? = 0L
) {
val currentZipName = zipFileDetails.alfredEventId
val requestBody = uploadFile.asRequestBody("application/zip".toMediaTypeOrNull())
val uploadResponse = AlfredManager.networkRepository.uploadZipToS3(url, requestBody)
if (uploadResponse.isSuccessful && uploadResponse.code() == AlfredConstants.CODE_API_SUCCESS) {
uploadFile.delete()
sendAlfredSessionEvent(dumpFlow, index, currentZipName, latestScreenshotTimestamp)
AlfredManager.zipDetailsDao.updateZipUploadStatus(currentZipName, true)
sendAlfredSessionEvent(zipFileDetails, dumpFlow)
} else {
val failureEvent =
buildFailureEvent(
errorType = ZIP_ERROR,
requestUrl = url,
requestMethod = POST_METHOD,
zipName = listOf(currentZipName ?: ""),
errorStatusCode = uploadResponse.code().toLong(),
errorMessage = uploadResponse.message(),
errorName = UPLOAD_TO_S3_FAILURE
)
AlfredDispatcher.addTaskToQueue(
AddFailureTask(failureEvent, context = AlfredManager.applicationContext)
)
if (!dumpFlow) {
AlfredManager.config.getEventStartRecordingTime()?.let { eventStartRecordingTime ->
insertZipDetailsToDbForDumpingLater(
AlfredManager.config.getAlfredSessionId(),
AlfredManager.config.getSessionStartRecordingTime(),
eventStartRecordingTime,
zipFileName,
currentZipName ?: "",
latestScreenshotTimestamp ?: 0L
if (!isCriticalJourneyResponse(uploadResponse.code())) {
val failureEvent =
buildFailureEvent(
errorType = ZIP_ERROR,
requestUrl = url,
requestMethod = POST_METHOD,
zipName = listOf(currentZipName),
errorStatusCode = uploadResponse.code().toLong(),
errorMessage = uploadResponse.message(),
errorName = UPLOAD_TO_S3_FAILURE
)
}
AlfredManager.config.setEventStartRecordingTime(true)
AlfredDispatcher.addTaskToQueue(
AddFailureTask(failureEvent, context = AlfredManager.applicationContext)
)
}
if (workManagerFlow == true) {
val latestScreenshotTimestamp = zipFileDetails.latestScreenshotTimestamp
uploadWorkManagerFailedZip(currentZipName, latestScreenshotTimestamp)
}
}
if (!dumpFlow) {
AlfredManager.config.setEventStartRecordingTime(true)
AlfredManager.hasUploadFlowStarted = false
}
}
internal fun buildWorkManagerForZipUploadRetry(requestData: Data) {
val constraints =
Constraints.Builder()
.setRequiresBatteryNotLow(false)
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
val uniqueWorkName = AlfredConstants.ZIP_UPLOAD_RETRY_WORK
val uniqueWorkStatus =
WorkManager.getInstance(AlfredManager.applicationContext)
.getWorkInfosForUniqueWork(uniqueWorkName)
.get()
if (uniqueWorkStatus.isNullOrEmpty()) {
val uniqueWorkRequest =
OneTimeWorkRequestBuilder<ZipUploadRetryWorker>()
.setConstraints(constraints)
.setInputData(requestData)
.build()
WorkManager.getInstance(AlfredManager.applicationContext)
.beginUniqueWork(uniqueWorkName, ExistingWorkPolicy.KEEP, uniqueWorkRequest)
.enqueue()
} else {
val workRequest =
OneTimeWorkRequestBuilder<ZipUploadRetryWorker>()
.setConstraints(constraints)
.setInputData(requestData)
.build()
WorkManager.getInstance(AlfredManager.applicationContext).enqueue(workRequest)
}
}

View File

@@ -21,7 +21,6 @@ import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.UUID
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlinx.coroutines.Dispatchers
@@ -29,7 +28,8 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.launch
internal fun toZip(imagePathList: List<ScreenShotPathHelper>) {
val zipFileName = AlfredManager.config.getAlfredSessionId() + UUID.randomUUID().toString()
val zipFileName = AlfredManager.config.getAlfredEventId()
val latestScreenshotTimestamp = AlfredManager.config.getLatestScreenshotTimestamp()
AlfredManager.config.setZipFileName(zipFileName)
val zipFilePath: String = AlfredManager.applicationContext.filesDir.path + "/" + zipFileName
val fileList = ArrayList<String>()
@@ -42,7 +42,15 @@ internal fun toZip(imagePathList: List<ScreenShotPathHelper>) {
}
if (zip(fileList, zipFilePath) == true) {
deleteScreenShot()
insertZipDetailsToDbForUpload(
alfredSessionId = AlfredManager.config.getAlfredSessionId(),
sessionStartRecordingTime = AlfredManager.config.getSessionStartRecordingTime(),
latestScreenshotTimestamp = latestScreenshotTimestamp,
eventStartRecordingTime = AlfredManager.config.getEventStartRecordingTime() ?: 0L,
alfredEventId = AlfredManager.config.getAlfredEventId()
)
AlfredManager.config.setNextEventStartRecordingTime()
AlfredManager.config.setAlfredEventId()
}
}
@@ -86,30 +94,32 @@ internal fun zip(_files: java.util.ArrayList<String>, zipFilePath: String?): Boo
return null
}
internal fun checkDbBeforeStartRecording() {
internal fun checkDbAndDeleteCorruptScreenshots() {
AlfredManager.coroutineScope.launch(Dispatchers.IO) {
if (AlfredManager.screenShotDao.getScreenShotCount() > 0) {
AlfredManager.screenShotDao.deleteAllScreenShot()
}
}
}
internal fun checkDbToUploadFailedZips() {
AlfredManager.coroutineScope.launch(Dispatchers.IO) {
if (AlfredManager.zipDetailsDao.getZipFilesDetailsCount() > 0) {
AlfredManager.zipFileDetails = AlfredManager.zipDetailsDao.fetchAllZipFilesDetails()
AlfredManager.zipFileDetails.forEachIndexed { index, DumpZipDetailsHelper ->
if (
checkFileExists(
fileName = DumpZipDetailsHelper.zipFileName,
AlfredManager.applicationContext
) != null
) {
getPreSignedUrl(
zipFileName = DumpZipDetailsHelper.zipFileName,
dumpFlow = true,
index = index,
alfredEventIdForDumpFlow = DumpZipDetailsHelper.alfredEventId,
latestScreenshotTimestamp = DumpZipDetailsHelper.latestScreenshotTimestamp
)
AlfredManager.zipFileDetailsList = AlfredManager.zipDetailsDao.fetchAllZipFilesDetails()
AlfredManager.zipFileDetailsList.forEachIndexed { _, dumpZipDetailsHelper ->
if (dumpZipDetailsHelper.zipUploadStatus) {
sendAlfredSessionEvent(dumpZipDetailsHelper, dumpFlow = true)
} else {
AlfredManager.zipDetailsDao.deleteZipFileDetail(DumpZipDetailsHelper.id)
if (
checkFileExists(
fileName = dumpZipDetailsHelper.alfredEventId,
AlfredManager.applicationContext
) != null
) {
getPreSignedUrl(zipFileDetail = dumpZipDetailsHelper, dumpFlow = true)
} else {
AlfredManager.zipDetailsDao.deleteZipFileDetail(dumpZipDetailsHelper.id)
}
}
}
}
@@ -118,23 +128,25 @@ internal fun checkDbBeforeStartRecording() {
internal suspend fun checkToStartZipUpload() {
val zipFileName = AlfredManager.config.getZipFileName().toString()
if (zipFileName.isNotEmpty()) {
if (checkFileExists(zipFileName, AlfredManager.applicationContext) != null) {
if (!AlfredManager.hasUploadFlowStarted) {
AlfredManager.hasUploadFlowStarted = true
getPreSignedUrl(zipFileName)
}
if (
zipFileName.isNotEmpty() &&
checkFileExists(zipFileName, AlfredManager.applicationContext) != null &&
!AlfredManager.hasUploadFlowStarted &&
AlfredManager.zipDetailsDao.zipDetailExists(zipFileName)
) {
AlfredManager.hasUploadFlowStarted = true
val zipFileDetail = AlfredManager.zipDetailsDao.getZipFileDetail(zipFileName)
if (zipFileDetail != null && !zipFileDetail.zipUploadStatus) {
getPreSignedUrl(zipFileDetail = zipFileDetail)
}
}
}
internal suspend fun toZipForWorkManager(
imagePathList: List<ScreenShotPathHelper>,
zipFileName: String,
sessionStartRecordingTime: Long? = null,
alfredSessionId: String? = null,
eventStartRecordingTime: Long? = null,
index: Int? = null,
sessionStartRecordingTime: Long,
alfredSessionId: String,
eventStartRecordingTime: Long,
alfredEventId: String,
latestScreenshotTimestamp: Long
) {
@@ -149,39 +161,46 @@ internal suspend fun toZipForWorkManager(
}
}
}
val zipFilePath = AlfredManager.applicationContext.filesDir.path + "/" + zipFileName
val zipFilePath = AlfredManager.applicationContext.filesDir.path + "/" + alfredEventId
if (zip(fileList, zipFilePath) == true) {
clearScreenShot(imagePathList)
getPreSignedUrl(
zipFileName,
index = index,
workManagerFlow = true,
dumpFlow = true,
alfredEventIdForDumpFlow = alfredEventId,
latestScreenshotTimestamp = latestScreenshotTimestamp
insertZipDetailsToDbForUpload(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime = sessionStartRecordingTime,
latestScreenshotTimestamp = latestScreenshotTimestamp,
eventStartRecordingTime = eventStartRecordingTime,
alfredEventId = alfredEventId
)
AlfredManager.screenShotDao.deleteAllScreenShot()
ScreenShotStorageHelper.clearAll()
clearScreenShot(imagePathList)
val zipFileDetail = AlfredManager.zipDetailsDao.getZipFileDetail(alfredEventId)
if (zipFileDetail != null && !zipFileDetail.zipUploadStatus) {
getPreSignedUrl(zipFileDetail = zipFileDetail, workManagerFlow = true, dumpFlow = true)
}
}
}
internal fun insertZipDetailsToDbForDumpingLater(
internal fun insertZipDetailsToDbForUpload(
alfredSessionId: String,
sessionStartRecordingTime: Long,
eventStartRecordingTime: Long,
zipFileName: String,
alfredEventId: String,
latestScreenshotTimestamp: Long
latestScreenshotTimestamp: Long,
zipUploadStatus: Boolean = false
) {
AlfredManager.zipDetailsDao.insert(
data =
ZipDetailsHelper(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime = sessionStartRecordingTime,
eventStartRecordingTime = eventStartRecordingTime,
zipFileName = zipFileName,
alfredEventId = alfredEventId,
latestScreenshotTimestamp = latestScreenshotTimestamp
)
)
if (!AlfredManager.zipDetailsDao.zipDetailExists(alfredEventId)) {
AlfredManager.zipDetailsDao.insert(
data =
ZipDetailsHelper(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime = sessionStartRecordingTime,
eventStartRecordingTime = eventStartRecordingTime,
alfredEventId = alfredEventId,
latestScreenshotTimestamp = latestScreenshotTimestamp,
zipUploadStatus = zipUploadStatus
)
)
}
}
internal fun startAnrCrashZipUpload(view: View) {
@@ -197,47 +216,53 @@ internal fun startAnrCrashZipUpload(view: View) {
checkAndInitiateFileUploadWorkManager()
}
}
AlfredManager.coroutineScope.launch(Dispatchers.IO) {
if (AlfredManager.zipDetailsDao.getZipFilesDetailsCount() > 0) {
val zipFileDetailList = AlfredManager.zipDetailsDao.fetchAllZipFilesDetails()
val requestData =
Data.Builder()
.putString(
AlfredConstants.ZIP_FILE_DETAIL_LIST,
Gson().toJson(zipFileDetailList)
)
.build()
buildWorkManagerForZipUploadRetry(requestData)
}
}
}
internal fun uploadWorkManagerFailedZip(
alfredEventId: String? = null,
latestScreenshotTimestamp: Long? = null
) {
if (AlfredManager.workFailureData.size > 0) {
val inputData = AlfredManager.workFailureData[0]
if (AlfredManager.zipUploadRetryCount < 3) {
WorkManager.getInstance(AlfredManager.applicationContext).cancelWorkById(inputData.id)
val failedZipDetails = AlfredManager.workFailureData.find { it.alfredEventId == alfredEventId }
if (failedZipDetails != null) {
if (failedZipDetails.retryCount < 3) {
WorkManager.getInstance(AlfredManager.applicationContext)
.cancelWorkById(failedZipDetails.id)
val requestData =
Data.Builder()
.putString(AlfredConstants.ALFRED_SESSION_ID, inputData.alfredSessionId)
.putString(AlfredConstants.ALFRED_SESSION_ID, failedZipDetails.alfredSessionId)
.putLong(
AlfredConstants.SESSION_START_RECORDING_TIME,
inputData.sessionStartRecordingTime
failedZipDetails.sessionStartRecordingTime
)
.putLong(
AlfredConstants.EVENT_START_RECORDING_TIME,
inputData.eventStartRecordingTime
failedZipDetails.eventStartRecordingTime
)
.putString(
AlfredConstants.SCREENSHOT_LIST,
Gson().toJson(inputData.screenShots)
.putString(AlfredConstants.ALFRED_EVENT_ID, failedZipDetails.alfredEventId)
.putLong(
AlfredConstants.LATEST_SCREENSHOT_TIMESTAMP,
latestScreenshotTimestamp ?: 0L
)
.build()
buildWorkManagerForZip(requestData)
AlfredManager.zipUploadRetryCount += 1
AlfredManager.workFailureData.removeAt(0)
failedZipDetails.retryCount += 1
} else {
AlfredManager.zipUploadRetryCount = 0
WorkManager.getInstance(AlfredManager.applicationContext).cancelWorkById(inputData.id)
WorkManager.getInstance(AlfredManager.applicationContext)
.cancelWorkById(failedZipDetails.id)
AlfredManager.workFailureData.removeAt(0)
insertZipDetailsToDbForDumpingLater(
alfredSessionId = inputData.alfredSessionId.toString(),
eventStartRecordingTime = inputData.eventStartRecordingTime,
sessionStartRecordingTime = inputData.sessionStartRecordingTime,
zipFileName = inputData.zipFileName,
alfredEventId = alfredEventId.toString(),
latestScreenshotTimestamp = latestScreenshotTimestamp ?: 0L
)
}
}
}

View File

@@ -10,15 +10,15 @@ package com.navi.alfred.worker
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navi.alfred.AlfredManager
import com.navi.alfred.AlfredManager.workFailureData
import com.navi.alfred.db.AlfredDatabaseHelper
import com.navi.alfred.db.model.ScreenShotPathHelper
import com.navi.alfred.model.WorkManagerFailureInputData
import com.navi.alfred.utils.AlfredConstants
import com.navi.alfred.utils.getPreSignedUrl
import com.navi.alfred.utils.sendAlfredSessionEvent
import com.navi.alfred.utils.toZipForWorkManager
import java.lang.reflect.Type
import java.util.UUID
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -27,53 +27,73 @@ class UploadFileWorker(context: Context, workerParams: WorkerParameters) :
override suspend fun doWork(): Result =
withContext(Dispatchers.IO) {
AlfredManager.alfredDataBase =
AlfredDatabaseHelper.getAnalyticsDatabase(AlfredManager.applicationContext)
AlfredManager.zipDetailsDao = AlfredManager.alfredDataBase.zipDetailsDao()
AlfredManager.screenShotDao = AlfredManager.alfredDataBase.screenShotDao()
val alfredSessionId = inputData.getString(AlfredConstants.ALFRED_SESSION_ID)
val sessionStartRecordingTime =
inputData.getLong(AlfredConstants.SESSION_START_RECORDING_TIME, 0L)
val eventStartRecordingTime =
inputData.getLong(AlfredConstants.EVENT_START_RECORDING_TIME, 0L)
val screenShotList = inputData.getString(AlfredConstants.SCREENSHOT_LIST)
val listType: Type = object : TypeToken<List<ScreenShotPathHelper?>?>() {}.type
val screenShots: List<ScreenShotPathHelper> =
Gson().fromJson(screenShotList.toString(), listType)
val zipFileName =
alfredSessionId +
sessionStartRecordingTime +
AlfredConstants.WORKER_ZIP_FILENAME_ENDPOINT
val alfredEventId =
inputData.getString(AlfredConstants.ALFRED_EVENT_ID)
?: UUID.randomUUID().toString().plus(AlfredConstants.ALFRED_EVENT_ID)
val screenshotIdArray = inputData.getIntArray(AlfredConstants.SCREENSHOT_ID_LIST)
val screenshotIdList = screenshotIdArray?.toList()
var screenShots = emptyList<ScreenShotPathHelper>()
if (screenshotIdList?.isNotEmpty() == true) {
screenShots =
AlfredManager.screenShotDao.fetchAllScreenShotsPathFromIds(screenshotIdList)
}
val alfredEventId = inputData.getString(AlfredConstants.ALFRED_EVENT_ID)
val latestScreenshotTimestamp =
inputData.getLong(AlfredConstants.LATEST_SCREENSHOT_TIMESTAMP, 0L)
workFailureData.add(
WorkManagerFailureInputData(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime,
eventStartRecordingTime,
screenShots,
id,
zipFileName,
alfredEventId,
latestScreenshotTimestamp
)
)
try {
if (
alfredSessionId == null ||
sessionStartRecordingTime == 0L ||
eventStartRecordingTime == 0L
eventStartRecordingTime == 0L ||
alfredEventId == null
) {
Result.failure()
} else {
toZipForWorkManager(
imagePathList = screenShots,
zipFileName = zipFileName,
sessionStartRecordingTime = sessionStartRecordingTime,
alfredSessionId = alfredSessionId,
eventStartRecordingTime = eventStartRecordingTime,
alfredEventId = alfredEventId,
latestScreenshotTimestamp = latestScreenshotTimestamp
)
if (workFailureData.find { it.alfredEventId == alfredEventId } == null) {
workFailureData.add(
WorkManagerFailureInputData(
alfredSessionId = alfredSessionId,
sessionStartRecordingTime,
eventStartRecordingTime,
id,
alfredEventId,
latestScreenshotTimestamp
)
)
}
if (screenShots.isNotEmpty()) {
toZipForWorkManager(
imagePathList = screenShots,
sessionStartRecordingTime = sessionStartRecordingTime,
alfredSessionId = alfredSessionId,
eventStartRecordingTime = eventStartRecordingTime,
alfredEventId = alfredEventId,
latestScreenshotTimestamp = latestScreenshotTimestamp
)
} else {
val zipFileDetail =
AlfredManager.zipDetailsDao.getZipFileDetail(alfredEventId)
if (zipFileDetail != null) {
if (zipFileDetail.zipUploadStatus) {
sendAlfredSessionEvent(zipFileDetail, dumpFlow = true)
} else {
getPreSignedUrl(
zipFileDetail = zipFileDetail,
workManagerFlow = true,
dumpFlow = true
)
}
}
}
Result.success()
}
} catch (e: Exception) {

View File

@@ -0,0 +1,69 @@
/*
*
* * Copyright © 2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.alfred.worker
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.navi.alfred.db.model.ZipDetailsHelper
import com.navi.alfred.utils.AlfredConstants
import com.navi.alfred.utils.buildWorkManagerForZip
import com.navi.alfred.utils.sendAlfredSessionEvent
import java.lang.reflect.Type
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class ZipUploadRetryWorker(context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result =
withContext(Dispatchers.IO) {
try {
val zipDetailList = inputData.getString(AlfredConstants.ZIP_FILE_DETAIL_LIST)
val listType: Type = object : TypeToken<List<ZipDetailsHelper?>?>() {}.type
val zipFileDetailList: List<ZipDetailsHelper> =
if (zipDetailList != null) {
Gson().fromJson(zipDetailList, listType)
} else {
emptyList()
}
zipFileDetailList.forEach {
if (it.zipUploadStatus) {
sendAlfredSessionEvent(it, true)
} else {
val requestDataForZip =
Data.Builder()
.putString(AlfredConstants.ALFRED_SESSION_ID, it.alfredSessionId)
.putLong(
AlfredConstants.SESSION_START_RECORDING_TIME,
it.sessionStartRecordingTime
)
.putLong(
AlfredConstants.EVENT_START_RECORDING_TIME,
it.sessionStartRecordingTime
)
.putString(AlfredConstants.ALFRED_EVENT_ID, it.alfredEventId)
.putLong(
AlfredConstants.LATEST_SCREENSHOT_TIMESTAMP,
it.latestScreenshotTimestamp
)
.build()
buildWorkManagerForZip(requestDataForZip)
}
}
Result.success()
} catch (e: Exception) {
e.printStackTrace()
Result.retry()
}
}
}