mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 20:45:49 +00:00
core: faster tracking of active subscriptions; ui: only track in foreground (#4446)
* core: faster tracking of active subscriptions * combine db transaction * optimizations of queries from UI * ios: track when active * ios: disable log --------- Co-authored-by: Avently <7953703+avently@users.noreply.github.com> Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
23f24b1677
commit
3e873fcb32
@@ -266,23 +266,19 @@ struct ChatListView: View {
|
||||
}
|
||||
|
||||
struct SubsStatusIndicator: View {
|
||||
@State private var subs: SMPServerSubs = SMPServerSubs.newSMPServerSubs
|
||||
@State private var sess: ServerSessions = ServerSessions.newServerSessions
|
||||
@State private var serversSummary: PresentedServersSummary?
|
||||
@State private var timer: Timer? = nil
|
||||
@State private var timerCounter = 0
|
||||
@State private var showServersSummary = false
|
||||
|
||||
@AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false
|
||||
|
||||
// Constants for the intervals
|
||||
let initialInterval: TimeInterval = 1.0
|
||||
let regularInterval: TimeInterval = 3.0
|
||||
let initialPhaseDuration: TimeInterval = 10.0 // Duration for initial phase in seconds
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
showServersSummary = true
|
||||
} label: {
|
||||
let subs = serversSummary?.allUsersSMP.smpTotals.subs ?? SMPServerSubs.newSMPServerSubs
|
||||
let sess = serversSummary?.allUsersSMP.smpTotals.sessions ?? ServerSessions.newServerSessions
|
||||
HStack(spacing: 4) {
|
||||
SubscriptionStatusIndicatorView(subs: subs, sess: sess)
|
||||
if showSubscriptionPercentage {
|
||||
@@ -291,34 +287,24 @@ struct SubsStatusIndicator: View {
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
startInitialTimer()
|
||||
startTimer()
|
||||
}
|
||||
.onDisappear {
|
||||
stopTimer()
|
||||
}
|
||||
.sheet(isPresented: $showServersSummary) {
|
||||
ServersSummaryView()
|
||||
ServersSummaryView(serversSummary: $serversSummary)
|
||||
}
|
||||
}
|
||||
|
||||
private func startInitialTimer() {
|
||||
timer = Timer.scheduledTimer(withTimeInterval: initialInterval, repeats: true) { _ in
|
||||
getServersSummary()
|
||||
timerCounter += 1
|
||||
// Switch to the regular timer after the initial phase
|
||||
if timerCounter * Int(initialInterval) >= Int(initialPhaseDuration) {
|
||||
switchToRegularTimer()
|
||||
private func startTimer() {
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
|
||||
if AppChatState.shared.value == .active {
|
||||
getServersSummary()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func switchToRegularTimer() {
|
||||
timer?.invalidate()
|
||||
timer = Timer.scheduledTimer(withTimeInterval: regularInterval, repeats: true) { _ in
|
||||
getServersSummary()
|
||||
}
|
||||
}
|
||||
|
||||
func stopTimer() {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
@@ -326,8 +312,7 @@ struct SubsStatusIndicator: View {
|
||||
|
||||
private func getServersSummary() {
|
||||
do {
|
||||
let summ = try getAgentServersSummary()
|
||||
(subs, sess) = (summ.allUsersSMP.smpTotals.subs, summ.allUsersSMP.smpTotals.sessions)
|
||||
serversSummary = try getAgentServersSummary()
|
||||
} catch let error {
|
||||
logger.error("getAgentServersSummary error: \(responseError(error))")
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ import SimpleXChat
|
||||
|
||||
struct ServersSummaryView: View {
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@State private var serversSummary: PresentedServersSummary? = nil
|
||||
@EnvironmentObject var theme: AppTheme
|
||||
@Binding var serversSummary: PresentedServersSummary?
|
||||
@State private var selectedUserCategory: PresentedUserCategory = .allUsers
|
||||
@State private var selectedServerType: PresentedServerType = .smp
|
||||
@State private var selectedSMPServer: String? = nil
|
||||
@State private var selectedXFTPServer: String? = nil
|
||||
@State private var timer: Timer? = nil
|
||||
@State private var alert: SomeAlert?
|
||||
|
||||
@AppStorage(DEFAULT_SHOW_SUBSCRIPTION_PERCENTAGE) private var showSubscriptionPercentage = false
|
||||
@@ -47,26 +47,10 @@ struct ServersSummaryView: View {
|
||||
if m.users.filter({ u in u.user.activeUser || !u.user.hidden }).count == 1 {
|
||||
selectedUserCategory = .currentUser
|
||||
}
|
||||
getServersSummary()
|
||||
startTimer()
|
||||
}
|
||||
.onDisappear {
|
||||
stopTimer()
|
||||
}
|
||||
.alert(item: $alert) { $0.alert }
|
||||
}
|
||||
|
||||
private func startTimer() {
|
||||
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
|
||||
getServersSummary()
|
||||
}
|
||||
}
|
||||
|
||||
func stopTimer() {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
|
||||
private func shareButton() -> some View {
|
||||
Button {
|
||||
if let serversSummary = serversSummary {
|
||||
@@ -183,6 +167,8 @@ struct ServersSummaryView: View {
|
||||
}
|
||||
} else {
|
||||
Text("No info, try to reload")
|
||||
.foregroundColor(theme.colors.secondary)
|
||||
.background(theme.colors.background)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +355,6 @@ struct ServersSummaryView: View {
|
||||
Task {
|
||||
do {
|
||||
try await resetAgentServersStats()
|
||||
getServersSummary()
|
||||
} catch let error {
|
||||
alert = SomeAlert(
|
||||
alert: mkAlert(
|
||||
@@ -389,14 +374,6 @@ struct ServersSummaryView: View {
|
||||
Text("Reset all statistics")
|
||||
}
|
||||
}
|
||||
|
||||
private func getServersSummary() {
|
||||
do {
|
||||
serversSummary = try getAgentServersSummary()
|
||||
} catch let error {
|
||||
logger.error("getAgentServersSummary error: \(responseError(error))")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SubscriptionStatusIndicatorView: View {
|
||||
@@ -734,5 +711,7 @@ struct DetailedXFTPStatsView: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ServersSummaryView()
|
||||
ServersSummaryView(
|
||||
serversSummary: Binding.constant(nil)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import android.net.LocalServerSocket
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import chat.simplex.common.*
|
||||
import chat.simplex.common.platform.*
|
||||
import java.io.*
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
@@ -24,6 +22,8 @@ var isAppOnForeground: Boolean = false
|
||||
@Suppress("ConstantLocale")
|
||||
val defaultLocale: Locale = Locale.getDefault()
|
||||
|
||||
actual fun isAppVisibleAndFocused(): Boolean = isAppOnForeground
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
lateinit var androidAppContext: Context
|
||||
var mainActivity: WeakReference<FragmentActivity> = WeakReference(null)
|
||||
|
||||
@@ -3,7 +3,6 @@ package chat.simplex.common.platform
|
||||
import chat.simplex.common.BuildConfigCommon
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.ui.theme.DefaultTheme
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
enum class AppPlatform {
|
||||
@@ -20,6 +19,8 @@ expect val appPlatform: AppPlatform
|
||||
|
||||
expect val deviceName: String
|
||||
|
||||
expect fun isAppVisibleAndFocused(): Boolean
|
||||
|
||||
val appVersionInfo: Pair<String, Int?> = if (appPlatform == AppPlatform.ANDROID)
|
||||
BuildConfigCommon.ANDROID_VERSION_NAME to BuildConfigCommon.ANDROID_VERSION_CODE
|
||||
else
|
||||
|
||||
@@ -266,44 +266,29 @@ private fun ChatListToolbar(drawerState: DrawerState, userPickerState: MutableSt
|
||||
fun SubscriptionStatusIndicator(serversSummary: MutableState<PresentedServersSummary?>, click: (() -> Unit)) {
|
||||
var subs by remember { mutableStateOf(SMPServerSubs.newSMPServerSubs) }
|
||||
var sess by remember { mutableStateOf(ServerSessions.newServerSessions) }
|
||||
var timer: Job? by remember { mutableStateOf(null) }
|
||||
|
||||
val fetchInterval: Duration = 1.seconds
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
fun setServersSummary() {
|
||||
withBGApi {
|
||||
serversSummary.value = chatModel.controller.getAgentServersSummary(chatModel.remoteHostId())
|
||||
suspend fun setServersSummary() {
|
||||
serversSummary.value = chatModel.controller.getAgentServersSummary(chatModel.remoteHostId())
|
||||
|
||||
serversSummary.value?.let {
|
||||
subs = it.allUsersSMP.smpTotals.subs
|
||||
sess = it.allUsersSMP.smpTotals.sessions
|
||||
}
|
||||
serversSummary.value?.let {
|
||||
subs = it.allUsersSMP.smpTotals.subs
|
||||
sess = it.allUsersSMP.smpTotals.sessions
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
setServersSummary()
|
||||
timer = timer ?: scope.launch {
|
||||
while (true) {
|
||||
delay(fetchInterval.inWholeMilliseconds)
|
||||
setServersSummary()
|
||||
scope.launch {
|
||||
while (isActive) {
|
||||
delay(1.seconds)
|
||||
if ((appPlatform.isDesktop || chatModel.chatId.value == null) && !ModalManager.start.hasModalsOpen() && !ModalManager.fullscreen.hasModalsOpen() && isAppVisibleAndFocused()) {
|
||||
setServersSummary()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopTimer() {
|
||||
timer?.cancel()
|
||||
timer = null
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
stopTimer()
|
||||
}
|
||||
}
|
||||
|
||||
SimpleButtonFrame(click = click) {
|
||||
SubscriptionStatusIndicatorView(subs = subs, sess = sess)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package chat.simplex.common.platform
|
||||
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.simplexWindowState
|
||||
import chat.simplex.common.views.call.RcvCallInvitation
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import java.util.*
|
||||
@@ -10,6 +11,8 @@ actual val appPlatform = AppPlatform.DESKTOP
|
||||
|
||||
actual val deviceName = generalGetString(MR.strings.desktop_device)
|
||||
|
||||
actual fun isAppVisibleAndFocused() = simplexWindowState.windowFocused.value
|
||||
|
||||
@Suppress("ConstantLocale")
|
||||
val defaultLocale: Locale = Locale.getDefault()
|
||||
|
||||
|
||||
@@ -2260,11 +2260,14 @@ processChatCommand' vr = \case
|
||||
DebugEvent event -> toView event >> ok_
|
||||
GetAgentServersSummary userId -> withUserId userId $ \user -> do
|
||||
agentServersSummary <- lift $ withAgent' getAgentServersSummary
|
||||
users <- withStore' getUsers
|
||||
smpServers <- getUserProtocolServers user SPSMP
|
||||
xftpServers <- getUserProtocolServers user SPXFTP
|
||||
cfg <- asks config
|
||||
(users, smpServers, xftpServers) <-
|
||||
withStore' $ \db -> (,,) <$> getUsers db <*> getServers db cfg user SPSMP <*> getServers db cfg user SPXFTP
|
||||
let presentedServersSummary = toPresentedServersSummary agentServersSummary users user smpServers xftpServers
|
||||
pure $ CRAgentServersSummary user presentedServersSummary
|
||||
where
|
||||
getServers :: (ProtocolTypeI p, UserProtocol p) => DB.Connection -> ChatConfig -> User -> SProtocolType p -> IO (NonEmpty (ProtocolServer p))
|
||||
getServers db cfg user p = L.map (\ServerCfg {server} -> protoServer server) . useServers cfg p <$> getProtocolServers db user
|
||||
ResetAgentServersStats -> withAgent resetAgentServersStats >> ok_
|
||||
GetAgentWorkers -> lift $ CRAgentWorkersSummary <$> withAgent' getAgentWorkersSummary
|
||||
GetAgentWorkersDetails -> lift $ CRAgentWorkersDetails <$> withAgent' getAgentWorkersDetails
|
||||
@@ -3223,7 +3226,8 @@ receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete}
|
||||
S.toList $ S.fromList $ concatMap (\FD.FileChunk {replicas} -> map (\FD.FileChunkReplica {server} -> server) replicas) chunks
|
||||
getUnknownSrvs :: [XFTPServer] -> CM [XFTPServer]
|
||||
getUnknownSrvs srvs = do
|
||||
knownSrvs <- getUserProtocolServers user SPXFTP
|
||||
cfg <- asks config
|
||||
knownSrvs <- L.map (\ServerCfg {server} -> protoServer server) . useServers cfg SPXFTP <$> withStore' (`getProtocolServers` user)
|
||||
pure $ filter (`notElem` knownSrvs) srvs
|
||||
ipProtectedForSrvs :: [XFTPServer] -> CM Bool
|
||||
ipProtectedForSrvs srvs = do
|
||||
@@ -3235,11 +3239,6 @@ receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete}
|
||||
forM_ aci_ $ \aci -> toView $ CRChatItemUpdated user aci
|
||||
throwChatError $ CEFileNotApproved fileId unknownSrvs
|
||||
|
||||
getUserProtocolServers :: (ProtocolTypeI p, UserProtocol p) => User -> SProtocolType p -> CM (NonEmpty (ProtocolServer p))
|
||||
getUserProtocolServers user p = do
|
||||
cfg <- asks config
|
||||
L.map (\ServerCfg {server} -> protoServer server) . useServers cfg p <$> withStore' (`getProtocolServers` user)
|
||||
|
||||
getNetworkConfig :: CM' NetworkConfig
|
||||
getNetworkConfig = withAgent' $ liftIO . getNetworkConfig'
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv
|
||||
AgentServersSummary {statsStartedAt, smpServersSessions, smpServersSubs, smpServersStats, xftpServersSessions, xftpServersStats, xftpRcvInProgress, xftpSndInProgress, xftpDelInProgress} = agentSummary
|
||||
countUserInAll auId = countUserInAllStats (AgentUserId auId) currentUser users
|
||||
accSMPTotals :: Map SMPServer SMPServerSummary -> SMPTotals
|
||||
accSMPTotals = M.foldr addTotals initialTotals
|
||||
accSMPTotals = M.foldr' addTotals initialTotals
|
||||
where
|
||||
initialTotals = SMPTotals {sessions = ServerSessions 0 0 0, subs = SMPServerSubs 0 0, stats = newAgentSMPServerStatsData}
|
||||
addTotals SMPServerSummary {sessions, subs, stats} SMPTotals {sessions = accSess, subs = accSubs, stats = accStats} =
|
||||
@@ -160,7 +160,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv
|
||||
stats = maybe accStats (accStats `addSMPStatsData`) stats
|
||||
}
|
||||
accXFTPTotals :: Map XFTPServer XFTPServerSummary -> XFTPTotals
|
||||
accXFTPTotals = M.foldr addTotals initialTotals
|
||||
accXFTPTotals = M.foldr' addTotals initialTotals
|
||||
where
|
||||
initialTotals = XFTPTotals {sessions = ServerSessions 0 0 0, stats = newAgentXFTPServerStatsData}
|
||||
addTotals XFTPServerSummary {sessions, stats} XFTPTotals {sessions = accSess, stats = accStats} =
|
||||
@@ -169,7 +169,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv
|
||||
stats = maybe accStats (accStats `addXFTPStatsData`) stats
|
||||
}
|
||||
smpSummsIntoCategories :: Map SMPServer SMPServerSummary -> ([SMPServerSummary], [SMPServerSummary], [SMPServerSummary])
|
||||
smpSummsIntoCategories = foldr partitionSummary ([], [], [])
|
||||
smpSummsIntoCategories = M.foldr' partitionSummary ([], [], [])
|
||||
where
|
||||
partitionSummary srvSumm (curr, prev, prox)
|
||||
| isCurrentlyUsed srvSumm = (srvSumm : curr, prev, prox)
|
||||
@@ -183,7 +183,7 @@ toPresentedServersSummary agentSummary users currentUser userSMPSrvs userXFTPSrv
|
||||
Just AgentSMPServerStatsData {_sentDirect, _sentProxied, _sentDirectAttempts, _sentProxiedAttempts, _recvMsgs, _connCreated, _connSecured, _connSubscribed, _connSubAttempts} ->
|
||||
_sentDirect > 0 || _sentProxied > 0 || _sentDirectAttempts > 0 || _sentProxiedAttempts > 0 || _recvMsgs > 0 || _connCreated > 0 || _connSecured > 0 || _connSubscribed > 0 || _connSubAttempts > 0
|
||||
xftpSummsIntoCategories :: Map XFTPServer XFTPServerSummary -> ([XFTPServerSummary], [XFTPServerSummary])
|
||||
xftpSummsIntoCategories = foldr partitionSummary ([], [])
|
||||
xftpSummsIntoCategories = M.foldr' partitionSummary ([], [])
|
||||
where
|
||||
partitionSummary srvSumm (curr, prev)
|
||||
| isCurrentlyUsed srvSumm = (srvSumm : curr, prev)
|
||||
|
||||
Reference in New Issue
Block a user