mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
feat: 缓慢查询
This commit is contained in:
parent
3f91b7fcb6
commit
3034c6aed9
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
146
app/src/main/kotlin/li/songe/gkd/ui/SlowGroupPage.kt
Normal file
146
app/src/main/kotlin/li/songe/gkd/ui/SlowGroupPage.kt
Normal 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user