mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-24 10:55:33 +00:00
android, desktop: debug subscribed SMP queues (#4262)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
committed by
GitHub
parent
b165603136
commit
c251f5e2bd
+72
@@ -931,6 +931,20 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiContactQueueInfo(rh: Long?, contactId: Long): Pair<RcvMsgInfo?, QueueInfo>? {
|
||||
val r = sendCmd(rh, CC.APIContactQueueInfo(contactId))
|
||||
if (r is CR.QueueInfoR) return Pair(r.rcvMsgInfo, r.queueInfo)
|
||||
apiErrorAlert("apiContactQueueInfo", generalGetString(MR.strings.error), r)
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiGroupMemberQueueInfo(rh: Long?, groupId: Long, groupMemberId: Long): Pair<RcvMsgInfo?, QueueInfo>? {
|
||||
val r = sendCmd(rh, CC.APIGroupMemberQueueInfo(groupId, groupMemberId))
|
||||
if (r is CR.QueueInfoR) return Pair(r.rcvMsgInfo, r.queueInfo)
|
||||
apiErrorAlert("apiGroupMemberQueueInfo", generalGetString(MR.strings.error), r)
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiSwitchContact(rh: Long?, contactId: Long): ConnectionStats? {
|
||||
val r = sendCmd(rh, CC.APISwitchContact(contactId))
|
||||
if (r is CR.ContactSwitchStarted) return r.connectionStats
|
||||
@@ -2507,6 +2521,8 @@ sealed class CC {
|
||||
class ApiSetMemberSettings(val groupId: Long, val groupMemberId: Long, val memberSettings: GroupMemberSettings): CC()
|
||||
class APIContactInfo(val contactId: Long): CC()
|
||||
class APIGroupMemberInfo(val groupId: Long, val groupMemberId: Long): CC()
|
||||
class APIContactQueueInfo(val contactId: Long): CC()
|
||||
class APIGroupMemberQueueInfo(val groupId: Long, val groupMemberId: Long): CC()
|
||||
class APISwitchContact(val contactId: Long): CC()
|
||||
class APISwitchGroupMember(val groupId: Long, val groupMemberId: Long): CC()
|
||||
class APIAbortSwitchContact(val contactId: Long): CC()
|
||||
@@ -2652,6 +2668,8 @@ sealed class CC {
|
||||
is ApiSetMemberSettings -> "/_member settings #$groupId $groupMemberId ${json.encodeToString(memberSettings)}"
|
||||
is APIContactInfo -> "/_info @$contactId"
|
||||
is APIGroupMemberInfo -> "/_info #$groupId $groupMemberId"
|
||||
is APIContactQueueInfo -> "/_queue info @$contactId"
|
||||
is APIGroupMemberQueueInfo -> "/_queue info #$groupId $groupMemberId"
|
||||
is APISwitchContact -> "/_switch @$contactId"
|
||||
is APISwitchGroupMember -> "/_switch #$groupId $groupMemberId"
|
||||
is APIAbortSwitchContact -> "/_abort switch @$contactId"
|
||||
@@ -2790,6 +2808,8 @@ sealed class CC {
|
||||
is ApiSetMemberSettings -> "apiSetMemberSettings"
|
||||
is APIContactInfo -> "apiContactInfo"
|
||||
is APIGroupMemberInfo -> "apiGroupMemberInfo"
|
||||
is APIContactQueueInfo -> "apiContactQueueInfo"
|
||||
is APIGroupMemberQueueInfo -> "apiGroupMemberQueueInfo"
|
||||
is APISwitchContact -> "apiSwitchContact"
|
||||
is APISwitchGroupMember -> "apiSwitchGroupMember"
|
||||
is APIAbortSwitchContact -> "apiAbortSwitchContact"
|
||||
@@ -4197,6 +4217,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("networkConfig") class NetworkConfig(val networkConfig: NetCfg): CR()
|
||||
@Serializable @SerialName("contactInfo") class ContactInfo(val user: UserRef, val contact: Contact, val connectionStats_: ConnectionStats? = null, val customUserProfile: Profile? = null): CR()
|
||||
@Serializable @SerialName("groupMemberInfo") class GroupMemberInfo(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val connectionStats_: ConnectionStats? = null): CR()
|
||||
@Serializable @SerialName("queueInfo") class QueueInfoR(val user: UserRef, val rcvMsgInfo: RcvMsgInfo?, val queueInfo: QueueInfo): CR()
|
||||
@Serializable @SerialName("contactSwitchStarted") class ContactSwitchStarted(val user: UserRef, val contact: Contact, val connectionStats: ConnectionStats): CR()
|
||||
@Serializable @SerialName("groupMemberSwitchStarted") class GroupMemberSwitchStarted(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val connectionStats: ConnectionStats): CR()
|
||||
@Serializable @SerialName("contactSwitchAborted") class ContactSwitchAborted(val user: UserRef, val contact: Contact, val connectionStats: ConnectionStats): CR()
|
||||
@@ -4368,6 +4389,7 @@ sealed class CR {
|
||||
is NetworkConfig -> "networkConfig"
|
||||
is ContactInfo -> "contactInfo"
|
||||
is GroupMemberInfo -> "groupMemberInfo"
|
||||
is QueueInfoR -> "queueInfo"
|
||||
is ContactSwitchStarted -> "contactSwitchStarted"
|
||||
is GroupMemberSwitchStarted -> "groupMemberSwitchStarted"
|
||||
is ContactSwitchAborted -> "contactSwitchAborted"
|
||||
@@ -4529,6 +4551,7 @@ sealed class CR {
|
||||
is NetworkConfig -> json.encodeToString(networkConfig)
|
||||
is ContactInfo -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats_)}")
|
||||
is GroupMemberInfo -> withUser(user, "group: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionStats: ${json.encodeToString(connectionStats_)}")
|
||||
is QueueInfoR -> withUser(user, "rcvMsgInfo: ${json.encodeToString(rcvMsgInfo)}\nqueueInfo: ${json.encodeToString(queueInfo)}\n")
|
||||
is ContactSwitchStarted -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
|
||||
is GroupMemberSwitchStarted -> withUser(user, "group: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
|
||||
is ContactSwitchAborted -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
|
||||
@@ -5786,3 +5809,52 @@ enum class UserNetworkType {
|
||||
OTHER -> generalGetString(MR.strings.network_type_other)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class RcvMsgInfo (
|
||||
val msgId: Long,
|
||||
val msgDeliveryId: Long,
|
||||
val msgDeliveryStatus: String,
|
||||
val agentMsgId: Long,
|
||||
val agentMsgMeta: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class QueueInfo (
|
||||
val qiSnd: Boolean,
|
||||
val qiNtf: Boolean,
|
||||
val qiSub: QSub? = null,
|
||||
val qiSize: Int,
|
||||
val qiMsg: MsgInfo? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class QSub (
|
||||
val qSubThread: QSubThread,
|
||||
val qDelivered: String? = null
|
||||
)
|
||||
|
||||
enum class QSubThread {
|
||||
@SerialName("noSub")
|
||||
NO_SUB,
|
||||
@SerialName("subPending")
|
||||
SUB_PENDING,
|
||||
@SerialName("subThread")
|
||||
SUB_THREAD,
|
||||
@SerialName("prohibitSub")
|
||||
PROHIBIT_SUB
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class MsgInfo (
|
||||
val msgId: String,
|
||||
val msgTs: Instant,
|
||||
val msgType: MsgType,
|
||||
)
|
||||
|
||||
enum class MsgType {
|
||||
@SerialName("message")
|
||||
MESSAGE,
|
||||
@SerialName("quota")
|
||||
QUOTA
|
||||
}
|
||||
|
||||
+20
@@ -42,6 +42,7 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.serialization.encodeToString
|
||||
import java.io.File
|
||||
|
||||
@Composable
|
||||
@@ -418,6 +419,19 @@ fun ChatInfoLayout(
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
|
||||
InfoRow(stringResource(MR.strings.info_row_local_name), chat.chatInfo.localDisplayName)
|
||||
InfoRow(stringResource(MR.strings.info_row_database_id), chat.chatInfo.apiId.toString())
|
||||
SectionItemView({
|
||||
withBGApi {
|
||||
val info = controller.apiContactQueueInfo(chat.remoteHostId, chat.chatInfo.apiId)
|
||||
if (info != null) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.message_queue_info),
|
||||
text = queueInfoText(info)
|
||||
)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(MR.strings.info_row_debug_delivery))
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
@@ -798,6 +812,12 @@ fun showSyncConnectionForceAlert(syncConnectionForce: () -> Unit) {
|
||||
)
|
||||
}
|
||||
|
||||
fun queueInfoText(info: Pair<RcvMsgInfo?, QueueInfo>): String {
|
||||
val (rcvMsgInfo, qInfo) = info
|
||||
val msgInfo: String = if (rcvMsgInfo != null) json.encodeToString(rcvMsgInfo) else generalGetString(MR.strings.message_queue_info_none)
|
||||
return generalGetString(MR.strings.message_queue_info_server_info).format(json.encodeToString(qInfo), msgInfo)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewChatInfoLayout() {
|
||||
|
||||
+18
@@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.group
|
||||
import InfoRow
|
||||
import SectionBottomSpacer
|
||||
import SectionDividerSpaced
|
||||
import SectionItemView
|
||||
import SectionSpacer
|
||||
import SectionTextFooter
|
||||
import SectionView
|
||||
@@ -27,6 +28,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.chat.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
@@ -58,6 +60,7 @@ fun GroupMemberInfoView(
|
||||
if (chat != null) {
|
||||
val newRole = remember { mutableStateOf(member.memberRole) }
|
||||
GroupMemberInfoLayout(
|
||||
rhId = rhId,
|
||||
groupInfo,
|
||||
member,
|
||||
connStats,
|
||||
@@ -219,6 +222,7 @@ fun removeMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, c
|
||||
|
||||
@Composable
|
||||
fun GroupMemberInfoLayout(
|
||||
rhId: Long?,
|
||||
groupInfo: GroupInfo,
|
||||
member: GroupMember,
|
||||
connStats: MutableState<ConnectionStats?>,
|
||||
@@ -397,6 +401,19 @@ fun GroupMemberInfoLayout(
|
||||
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
|
||||
InfoRow(stringResource(MR.strings.info_row_local_name), member.localDisplayName)
|
||||
InfoRow(stringResource(MR.strings.info_row_database_id), member.groupMemberId.toString())
|
||||
SectionItemView({
|
||||
withBGApi {
|
||||
val info = controller.apiGroupMemberQueueInfo(rhId, groupInfo.apiId, member.groupMemberId)
|
||||
if (info != null) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.message_queue_info),
|
||||
text = queueInfoText(info)
|
||||
)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(MR.strings.info_row_debug_delivery))
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
@@ -644,6 +661,7 @@ fun blockMemberForAll(rhId: Long?, gInfo: GroupInfo, member: GroupMember, blocke
|
||||
fun PreviewGroupMemberInfoLayout() {
|
||||
SimpleXTheme {
|
||||
GroupMemberInfoLayout(
|
||||
rhId = null,
|
||||
groupInfo = GroupInfo.sampleData,
|
||||
member = GroupMember.sampleData,
|
||||
connStats = remember { mutableStateOf(null) },
|
||||
|
||||
@@ -1401,6 +1401,7 @@
|
||||
<string name="section_title_for_console">FOR CONSOLE</string>
|
||||
<string name="info_row_local_name">Local name</string>
|
||||
<string name="info_row_database_id">Database ID</string>
|
||||
<string name="info_row_debug_delivery">Debug delivery</string>
|
||||
<string name="info_row_updated_at">Record updated at</string>
|
||||
<string name="info_row_sent_at">Sent at</string>
|
||||
<string name="info_row_created_at">Created at</string>
|
||||
@@ -1462,6 +1463,9 @@
|
||||
<string name="info_row_connection">Connection</string>
|
||||
<string name="conn_level_desc_direct">direct</string>
|
||||
<string name="conn_level_desc_indirect">indirect (%1$s)</string>
|
||||
<string name="message_queue_info">Message queue info</string>
|
||||
<string name="message_queue_info_none">none</string>
|
||||
<string name="message_queue_info_server_info">server queue info: %1$s\n\nlast received msg: %2$s</string>
|
||||
|
||||
<!-- GroupWelcomeView.kt -->
|
||||
<string name="group_welcome_title">Welcome message</string>
|
||||
|
||||
Reference in New Issue
Block a user