diff --git a/lib/src/main/java/com/example/http/Request.kt b/lib/src/main/java/com/example/http/Request.kt index 807b20a..eae44e0 100644 --- a/lib/src/main/java/com/example/http/Request.kt +++ b/lib/src/main/java/com/example/http/Request.kt @@ -5,7 +5,7 @@ import com.example.action.NoString data class Request( var url:String, - var method: HttpMethod? = HttpMethod.Get, + var method: HttpMethod = HttpMethod.Get, var headers:Map = emptyMap(), var body: ByteArray = byteArrayOf() ): NoString() { diff --git a/lib/src/main/java/com/example/service/PinServer.kt b/lib/src/main/java/com/example/service/PinServer.kt new file mode 100644 index 0000000..4b39c45 --- /dev/null +++ b/lib/src/main/java/com/example/service/PinServer.kt @@ -0,0 +1,163 @@ +package com.example.service + +import android.util.Log +import com.example.action.BaseAction +import com.example.action.Next +import com.example.logger.LogUtils +import com.example.pin.NotificationMessage +import com.example.report.ActionExec +import com.example.task.TaskConfig +import com.example.utils.toJsonString +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeoutOrNull +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +class PinService( + private val action: BaseAction.PinAction, + override val taskConfig: TaskConfig +) : BaseService(taskConfig) { + + override suspend fun execute(onFinish: (List) -> Unit) { + withContext(Dispatchers.IO) { + val actionExecList: MutableList = mutableListOf() + var currentStep = taskConfig.currentStep + kotlin.runCatching { + val start = System.currentTimeMillis() + var respCode = 200 + var cost = 0L + val messageLog: MutableList = mutableListOf() + val nextList = action.next + LogUtils.info("next list: ${nextList.map { it.regexp + ", " + it.contain }}") + withTimeoutOrNull(action.delay.toDuration(DurationUnit.SECONDS)) { + while (isActive) { + val notificationCache = taskConfig.notificationCache + if (nextList.isNotEmpty() && notificationCache.isNotEmpty()) { + val notificationMessages = + haveNextCatchTargetMessage(notificationCache, nextList) + if (notificationMessages.isNotEmpty()) { + LogUtils.info("catch target message...") + messageLog.addAll(notificationMessages) + break + } + } + cost = System.currentTimeMillis() - start + LogUtils.info("waiting for target message... ${action.delay}, escape: ${cost / 1000f}") + delay(1000) + } + } + cost = System.currentTimeMillis() - start + LogUtils.info("waiting for target message... finish ${cost/1000f}") + if (messageLog.isNotEmpty()) { + val nextStep = + nextList.getNextStepIndex( + messageLog.toJsonString(), + currentStep + ) + taskConfig.currentStep = nextStep + } else { + if (nextList.isNotEmpty()) { + taskConfig.currentStep = Int.MAX_VALUE + respCode = ERROR_CODE_PIN_ACTION_TIMEOUT + if(taskConfig.notificationCache.isNotEmpty()) { + messageLog += taskConfig.notificationCache.last() + } + } else { + taskConfig.currentStep = ++currentStep + messageLog += taskConfig.notificationCache + } + } + if (taskConfig.currentStep != Int.MAX_VALUE && messageLog.isNotEmpty()) { + val responseBody = messageLog.toJsonString() + extractBodyVariableToCache(action, responseBody, responseBody.toByteArray()) + } + + val actionExec = genActionExec(messageLog, currentStep, respCode, cost) + actionExecList += actionExec + }.onFailure { + LogUtils.error(it) + val actionExec = genExceptionActionExec( + action, + ERROR_CODE_PIN_ACTION_EXEC_FAILED, + Log.getStackTraceString(it) + ) + actionExecList += actionExec + if (action.skipError) { + taskConfig.currentStep = ++currentStep + } else { + taskConfig.currentStep = Int.MAX_VALUE + } + } + onFinish(actionExecList) + } + } + + private fun genActionExec( + messageLog: MutableList, + currentStep: Int, + respCode: Int, + cost: Long + ): ActionExec { + val actionExec = ActionExec().apply { + this.step = currentStep + this.index = 1 + this.respCode = respCode + this.cost = cost + this.time = System.currentTimeMillis() + if (messageLog.isNotEmpty()) { + this.url = messageLog.first().app + this.respData = messageLog.toJsonString() + } + } + return actionExec + } + + private fun haveNextCatchTargetMessage( + notificationCache: List, + nextList: List + ): List { + var result: List = mutableListOf() + var targetMessage: NotificationMessage? = null + LogUtils.info("message size: ${notificationCache.size}") + for (notify in notificationCache) { + LogUtils.info("notify: ${notify.content}") + for (next in nextList) { + if (next.step <= 0) continue + LogUtils.info("next:$next") + val contain = next.contain + if (contain.isNotBlank() && (notify.from.contains(contain) || + notify.content.contains(contain)) + ) { + targetMessage = notify + break + } + + if (next.regexp.isNotBlank()) { + val pattern = next.regexp.toRegex() + var matcher = pattern.matches(notify.from) + if (matcher) { + targetMessage = notify + break + } + + matcher = pattern.matches(notify.content) + if (matcher) { + targetMessage = notify + break + } + } + } + if (targetMessage != null) { + break + } + } + if (targetMessage != null) { + result = notificationCache.filter { targetMessage.from == it.from }.toList() + } + + return result + } +} \ No newline at end of file