feat: 缓慢查询

This commit is contained in:
lisonge 2024-02-06 20:33:15 +08:00
parent 3f91b7fcb6
commit 3034c6aed9
6 changed files with 201 additions and 5 deletions

View File

@ -173,7 +173,7 @@ data class RawSubscription(
} }
val allSelectorStrings by lazy { val allSelectorStrings by lazy {
rules.map { r -> r.matches + (r.excludeMatches ?: emptyList()) }.flatten().distinct() rules.map { r -> r.matches + (r.excludeMatches ?: emptyList()) }.flatten()
} }
val allSelector by lazy { val allSelector by lazy {
@ -257,7 +257,7 @@ data class RawSubscription(
) : RawGroupProps, RawAppRuleProps { ) : RawGroupProps, RawAppRuleProps {
val allSelectorStrings by lazy { val allSelectorStrings by lazy {
rules.map { r -> r.matches + (r.excludeMatches ?: emptyList()) }.flatten().distinct() rules.map { r -> r.matches + (r.excludeMatches ?: emptyList()) }.flatten()
} }
val allSelector by lazy { val allSelector by lazy {

View File

@ -16,7 +16,8 @@ sealed class ResolvedRule(
) { ) {
val key = rule.key val key = rule.key
val index = group.rules.indexOf(rule) val index = group.rules.indexOf(rule)
val preKeys = (rule.preKeys ?: emptyList()).toSet() val othersKeys = group.rules.filter { r -> r.key != rule.key }.mapNotNull { r -> r.key }.toSet()
val preKeys = (rule.preKeys ?: emptyList()).filter { r -> othersKeys.contains(r) }.toSet()
val resetMatch = rule.resetMatch ?: group.resetMatch val resetMatch = rule.resetMatch ?: group.resetMatch
val matches = rule.matches.map { s -> Selector.parse(s) } val matches = rule.matches.map { s -> Selector.parse(s) }
val excludeMatches = (rule.excludeMatches ?: emptyList()).map { s -> Selector.parse(s) } val excludeMatches = (rule.excludeMatches ?: emptyList()).map { s -> Selector.parse(s) }
@ -41,6 +42,16 @@ sealed class ResolvedRule(
val order = rule.order ?: group.order ?: 0 val order = rule.order ?: group.order ?: 0
val slowSelectors by lazy {
(matches + excludeMatches).filterNot { s ->
((quickFind && s.canQf) || s.isMatchRoot) && !s.connectKeys.contains(
"<<"
)
}
}
val isSlow by lazy { preKeys.isEmpty() && slowSelectors.isNotEmpty() && (matchTime == null || matchTime > 30_000L) }
var groupToRules: Map<out RawSubscription.RawGroupProps, List<ResolvedRule>> = emptyMap() var groupToRules: Map<out RawSubscription.RawGroupProps, List<ResolvedRule>> = emptyMap()
set(value) { set(value) {
field = value field = value

View File

@ -0,0 +1,146 @@
package li.songe.gkd.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph
import li.songe.gkd.ui.destinations.AppItemPageDestination
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.ProfileTransitions
import li.songe.gkd.util.appInfoCacheFlow
import li.songe.gkd.util.navigate
import li.songe.gkd.util.ruleSummaryFlow
@RootNavGraph
@Destination(style = ProfileTransitions::class)
@Composable
fun SlowGroupPage() {
val navController = LocalNavController.current
val ruleSummary by ruleSummaryFlow.collectAsState()
val appInfoCache by appInfoCacheFlow.collectAsState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
scrollBehavior = scrollBehavior,
navigationIcon = {
IconButton(onClick = {
navController.popBackStack()
}) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = null,
)
}
},
title = { Text(text = if (ruleSummary.slowGroupCount > 0) "缓慢查询-${ruleSummary.slowGroupCount}" else "缓慢查询") },
actions = {}
)
}
) { padding ->
LazyColumn(modifier = Modifier.padding(padding)) {
items(ruleSummary.slowGlobalGroups) { (group, rule) ->
SlowGroupCard(
modifier = Modifier
.clickable {
navController.navigate(
GlobalRulePageDestination(
rule.subsItem.id,
group.key
)
)
}
.padding(10.dp, 5.dp),
title = group.name,
desc = "${rule.rawSubs.name}-全局规则"
)
}
items(ruleSummary.slowAppGroups) { (group, rule) ->
SlowGroupCard(
modifier = Modifier
.clickable {
navController.navigate(
AppItemPageDestination(
rule.subsItem.id,
rule.app.id,
group.key
)
)
}
.padding(10.dp, 5.dp),
title = group.name,
desc = "${rule.rawSubs.name}-应用规则-${appInfoCache[rule.app.id]?.name ?: rule.app.name ?: rule.app.id}"
)
}
item {
Spacer(modifier = Modifier.height(40.dp))
if (ruleSummary.slowGroupCount == 0) {
Text(
text = "暂无规则",
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center
)
}
}
}
}
}
@Composable
fun SlowGroupCard(title: String, desc: String, modifier: Modifier = Modifier) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = modifier,
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = title, fontSize = 18.sp,
maxLines = 1,
softWrap = false,
overflow = TextOverflow.Ellipsis,
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = desc, fontSize = 14.sp,
maxLines = 1,
softWrap = false,
overflow = TextOverflow.Ellipsis,
)
}
Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = null
)
}
}

View File

@ -39,11 +39,13 @@ import li.songe.gkd.service.ManageService
import li.songe.gkd.ui.component.AuthCard import li.songe.gkd.ui.component.AuthCard
import li.songe.gkd.ui.component.TextSwitch import li.songe.gkd.ui.component.TextSwitch
import li.songe.gkd.ui.destinations.ClickLogPageDestination import li.songe.gkd.ui.destinations.ClickLogPageDestination
import li.songe.gkd.ui.destinations.SlowGroupPageDestination
import li.songe.gkd.util.HOME_PAGE_URL import li.songe.gkd.util.HOME_PAGE_URL
import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.checkOrRequestNotifPermission import li.songe.gkd.util.checkOrRequestNotifPermission
import li.songe.gkd.util.launchTry import li.songe.gkd.util.launchTry
import li.songe.gkd.util.navigate import li.songe.gkd.util.navigate
import li.songe.gkd.util.ruleSummaryFlow
import li.songe.gkd.util.storeFlow import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.updateStorage import li.songe.gkd.util.updateStorage
import li.songe.gkd.util.usePollState import li.songe.gkd.util.usePollState
@ -58,6 +60,7 @@ fun useControlPage(): ScaffoldExt {
val latestRecordDesc by vm.latestRecordDescFlow.collectAsState() val latestRecordDesc by vm.latestRecordDescFlow.collectAsState()
val subsStatus by vm.subsStatusFlow.collectAsState() val subsStatus by vm.subsStatusFlow.collectAsState()
val store by storeFlow.collectAsState() val store by storeFlow.collectAsState()
val ruleSummary by ruleSummaryFlow.collectAsState()
val gkdAccessRunning by GkdAbService.isRunning.collectAsState() val gkdAccessRunning by GkdAbService.isRunning.collectAsState()
val manageRunning by ManageService.isRunning.collectAsState() val manageRunning by ManageService.isRunning.collectAsState()
@ -216,6 +219,34 @@ fun useControlPage(): ScaffoldExt {
} }
HorizontalDivider() HorizontalDivider()
if (ruleSummary.slowGroupCount > 0) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clickable {
navController.navigate(SlowGroupPageDestination)
}
.padding(10.dp, 5.dp),
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = "耗时查询", fontSize = 18.sp
)
Spacer(modifier = Modifier.height(2.dp))
Text(
text = "存在${ruleSummary.slowGroupCount}规则组,可能导致触发缓慢或更多耗电",
fontSize = 14.sp
)
}
Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = null
)
}
HorizontalDivider()
}
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()

View File

@ -102,6 +102,13 @@ data class RuleSummary(
} else { } else {
"暂无规则" "暂无规则"
} }
val slowGlobalGroups =
globalRules.filter { r -> r.isSlow }.distinctBy { r -> r.group }.map { r -> r.group to r }
val slowAppGroups =
appIdToRules.values.flatten().filter { r -> r.isSlow }.distinctBy { r -> r.group }
.map { r -> r.group to r }
val slowGroupCount = slowGlobalGroups.size + slowAppGroups.size
} }
val ruleSummaryFlow by lazy { val ruleSummaryFlow by lazy {

View File

@ -27,8 +27,9 @@ class Selector internal constructor(private val propertyWrapper: PropertyWrapper
var c = propertyWrapper.to var c = propertyWrapper.to
val keys = mutableListOf<String>() val keys = mutableListOf<String>()
while (c != null) { while (c != null) {
c!!.connectSegment.connectExpression c?.apply {
keys.add(c!!.connectSegment.operator.key) keys.add(connectSegment.operator.key)
}
c = c?.to?.to c = c?.to?.to
} }
keys.toTypedArray() keys.toTypedArray()