core, ui: better error on failed channel creation (#6825)

This commit is contained in:
spaced4ndy
2026-04-20 08:17:42 +00:00
committed by GitHub
parent a7c6f0af95
commit 2eb25d124f
19 changed files with 268 additions and 67 deletions
@@ -1564,6 +1564,23 @@ object ChatController {
}
}
fun connErrorText(e: ChatError): String = when {
e is ChatError.ChatErrorChat && e.errorType is ChatErrorType.InvalidConnReq ->
generalGetString(MR.strings.invalid_connection_link)
e is ChatError.ChatErrorChat && e.errorType is ChatErrorType.UnsupportedConnReq ->
generalGetString(MR.strings.unsupported_connection_link)
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.SMP && e.agentError.smpErr is SMPErrorType.AUTH ->
generalGetString(MR.strings.connection_error_auth)
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.SMP && e.agentError.smpErr is SMPErrorType.BLOCKED ->
"${generalGetString(MR.strings.connection_error_blocked)}: ${e.agentError.smpErr.blockInfo.reason.text}"
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.SMP && e.agentError.smpErr is SMPErrorType.QUOTA ->
generalGetString(MR.strings.connection_reached_limit_of_undelivered_messages)
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.BROKER ->
generalGetString(MR.strings.network_error)
else ->
"${generalGetString(MR.strings.error_prefix)}: ${e.string}"
}
suspend fun apiPrepareContact(rh: Long?, connLink: CreatedConnLink, contactShortLinkData: ContactShortLinkData): Chat? {
val userId = try { currentUserId("apiPrepareContact") } catch (e: Exception) { return null }
val r = sendCmd(rh, CC.APIPrepareContact(userId, connLink, contactShortLinkData))
@@ -2118,10 +2135,16 @@ object ChatController {
return null
}
suspend fun apiNewPublicGroup(rh: Long?, incognito: Boolean, relayIds: List<Long>, groupProfile: GroupProfile): Triple<GroupInfo, GroupLink, List<GroupRelay>>? {
sealed class PublicGroupCreationResult {
data class Created(val groupInfo: GroupInfo, val groupLink: GroupLink, val groupRelays: List<GroupRelay>): PublicGroupCreationResult()
data class CreationFailed(val addRelayResults: List<AddRelayResult>): PublicGroupCreationResult()
}
suspend fun apiNewPublicGroup(rh: Long?, incognito: Boolean, relayIds: List<Long>, groupProfile: GroupProfile): PublicGroupCreationResult? {
val userId = kotlin.runCatching { currentUserId("apiNewPublicGroup") }.getOrElse { return null }
val r = sendCmdWithRetry(rh, CC.ApiNewPublicGroup(userId, incognito, relayIds, groupProfile))
if (r is API.Result && r.res is CR.PublicGroupCreated) return Triple(r.res.groupInfo, r.res.groupLink, r.res.groupRelays)
if (r is API.Result && r.res is CR.PublicGroupCreated) return PublicGroupCreationResult.Created(r.res.groupInfo, r.res.groupLink, r.res.groupRelays)
if (r is API.Result && r.res is CR.PublicGroupCreationFailed) return PublicGroupCreationResult.CreationFailed(r.res.addRelayResults)
if (r != null) throw Exception("${r.responseType}: ${r.details}")
return null
}
@@ -4569,6 +4592,12 @@ data class RelayConnectionResult(
val relayError: ChatError? = null
)
@Serializable
data class AddRelayResult(
val relay: UserChatRelay,
val relayError: ChatError? = null
)
@Serializable
data class GroupShortLinkInfo(
val direct: Boolean,
@@ -6345,6 +6374,7 @@ sealed class CR {
// group events
@Serializable @SerialName("groupCreated") class GroupCreated(val user: UserRef, val groupInfo: GroupInfo): CR()
@Serializable @SerialName("publicGroupCreated") class PublicGroupCreated(val user: UserRef, val groupInfo: GroupInfo, val groupLink: GroupLink, val groupRelays: List<GroupRelay>): CR()
@Serializable @SerialName("publicGroupCreationFailed") class PublicGroupCreationFailed(val user: UserRef, val addRelayResults: List<AddRelayResult>): CR()
@Serializable @SerialName("groupRelays") class GroupRelays(val user: UserRef, val groupInfo: GroupInfo, val groupRelays: List<GroupRelay>): CR()
@Serializable @SerialName("sentGroupInvitation") class SentGroupInvitation(val user: UserRef, val groupInfo: GroupInfo, val contact: Contact, val member: GroupMember): CR()
@Serializable @SerialName("userAcceptedGroupSent") class UserAcceptedGroupSent (val user: UserRef, val groupInfo: GroupInfo, val hostContact: Contact? = null): CR()
@@ -6533,6 +6563,7 @@ sealed class CR {
is ForwardPlan -> "forwardPlan"
is GroupCreated -> "groupCreated"
is PublicGroupCreated -> "publicGroupCreated"
is PublicGroupCreationFailed -> "publicGroupCreationFailed"
is GroupRelays -> "groupRelays"
is SentGroupInvitation -> "sentGroupInvitation"
is UserAcceptedGroupSent -> "userAcceptedGroupSent"
@@ -6714,6 +6745,7 @@ sealed class CR {
is ForwardPlan -> withUser(user, "itemsCount: $itemsCount\nchatItemIds: ${json.encodeToString(chatItemIds)}\nforwardConfirmation: ${json.encodeToString(forwardConfirmation)}")
is GroupCreated -> withUser(user, json.encodeToString(groupInfo))
is PublicGroupCreated -> withUser(user, "groupInfo: $groupInfo\ngroupLink: $groupLink\ngroupRelays: $groupRelays")
is PublicGroupCreationFailed -> withUser(user, "addRelayResults: $addRelayResults")
is GroupRelays -> withUser(user, "groupInfo: $groupInfo\ngroupRelays: $groupRelays")
is SentGroupInvitation -> withUser(user, "groupInfo: $groupInfo\ncontact: $contact\nmember: $member")
is UserAcceptedGroupSent -> json.encodeToString(groupInfo)
@@ -130,19 +130,31 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
relayIds = relayIds,
groupProfile = profile
)
if (result != null) {
val (gI, gL, gR) = result
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId = null, gI)
chatModel.creatingChannelId.value = gI.id
groupInfo.value = gI
groupLink.value = gL
groupRelays.value = gR.sortedBy { relayDisplayName(it) }
ChannelRelaysModel.set(gI.groupId, gR)
creationInProgress.value = false
when (result) {
is ChatController.PublicGroupCreationResult.Created -> {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId = null, result.groupInfo)
chatModel.creatingChannelId.value = result.groupInfo.id
groupInfo.value = result.groupInfo
groupLink.value = result.groupLink
groupRelays.value = result.groupRelays.sortedBy { relayDisplayName(it) }
ChannelRelaysModel.set(result.groupInfo.groupId, result.groupRelays)
creationInProgress.value = false
}
}
is ChatController.PublicGroupCreationResult.CreationFailed -> {
withContext(Dispatchers.Main) {
creationInProgress.value = false
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.error_creating_channel),
text = generalGetString(MR.strings.relay_results) + "\n" +
result.addRelayResults.joinToString("\n") { "${chatRelayDisplayName(it.relay)}: ${it.relayError?.let { e -> ChatController.connErrorText(e) } ?: "ok"}" }
)
}
}
null -> {
withContext(Dispatchers.Main) { creationInProgress.value = false }
}
} else {
withContext(Dispatchers.Main) { creationInProgress.value = false }
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
@@ -545,6 +557,10 @@ fun relayDisplayName(relay: GroupRelay): String {
return "relay ${relay.groupRelayId}"
}
private fun chatRelayDisplayName(relay: UserChatRelay): String {
if (relay.displayName.isNotEmpty()) return relay.displayName
return relay.address
}
@Composable
fun RelayStatusIndicator(status: RelayStatus, connFailed: Boolean = false, memberStatus: GroupMemberStatus? = null) {
@@ -2943,6 +2943,10 @@
<string name="channel_display_name_field">Channel name</string>
<string name="creating_channel">Creating channel</string>
<string name="error_creating_channel">Error creating channel</string>
<string name="relay_results">Relay results:</string>
<string name="connection_reached_limit_of_undelivered_messages">The connection reached the limit of undelivered messages</string>
<string name="network_error">Network error</string>
<string name="error_prefix">Error</string>
<string name="cancel_creating_channel_question">Cancel creating channel?</string>
<string name="cancel_creating_channel_confirm">Cancel</string>
<string name="enable_at_least_one_chat_relay">Enable at least one chat relay to create a channel.</string>