desktop: fix remote desktop channel and connection issues (#7137)

This commit is contained in:
spaced4ndy
2026-06-26 15:42:47 +00:00
committed by GitHub
parent 1785132691
commit 3a38c39d35
7 changed files with 37 additions and 30 deletions
@@ -1607,7 +1607,7 @@ object ChatController {
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))
if (r is API.Result && r.res is CR.NewPreparedChat) return r.res.chat
if (r is API.Result && r.res is CR.NewPreparedChat) return if (rh == null) r.res.chat else r.res.chat.copy(remoteHostId = rh)
Log.e(TAG, "apiPrepareContact bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_preparing_contact), "${r.responseType}: ${r.details}")
return null
@@ -1616,7 +1616,7 @@ object ChatController {
suspend fun apiPrepareGroup(rh: Long?, connLink: CreatedConnLink, directLink: Boolean, groupShortLinkData: GroupShortLinkData): Chat? {
val userId = try { currentUserId("apiPrepareGroup") } catch (e: Exception) { return null }
val r = sendCmd(rh, CC.APIPrepareGroup(userId, connLink, directLink, groupShortLinkData))
if (r is API.Result && r.res is CR.NewPreparedChat) return r.res.chat
if (r is API.Result && r.res is CR.NewPreparedChat) return if (rh == null) r.res.chat else r.res.chat.copy(remoteHostId = rh)
Log.e(TAG, "apiPrepareGroup bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_preparing_group), "${r.responseType}: ${r.details}")
return null
@@ -2172,8 +2172,8 @@ object ChatController {
return null
}
suspend fun apiGetGroupRelays(groupId: Long): List<GroupRelay> {
val r = sendCmd(null, CC.ApiGetGroupRelays(groupId))
suspend fun apiGetGroupRelays(rh: Long?, groupId: Long): List<GroupRelay> {
val r = sendCmd(rh, CC.ApiGetGroupRelays(groupId))
if (r is API.Result && r.res is CR.GroupRelays) return r.res.groupRelays
return emptyList()
}
@@ -2183,8 +2183,8 @@ object ChatController {
data class AddFailed(val addRelayResults: List<AddRelayResult>): AddGroupRelaysResult()
}
suspend fun apiAddGroupRelays(groupId: Long, relayIds: List<Long>): AddGroupRelaysResult? {
val r = sendCmdWithRetry(null, CC.ApiAddGroupRelays(groupId, relayIds))
suspend fun apiAddGroupRelays(rh: Long?, groupId: Long, relayIds: List<Long>): AddGroupRelaysResult? {
val r = sendCmdWithRetry(rh, CC.ApiAddGroupRelays(groupId, relayIds))
if (r is API.Result && r.res is CR.GroupRelaysAdded) return AddGroupRelaysResult.Added(r.res.groupInfo, r.res.groupLink, r.res.groupRelays)
if (r is API.Result && r.res is CR.GroupRelaysAddFailed) return AddGroupRelaysResult.AddFailed(r.res.addRelayResults)
if (r != null) throw Exception("${r.responseType}: ${r.details}")
@@ -208,7 +208,7 @@ fun ChatView(
withBGApi {
setGroupMembers(chatRh, cInfo.groupInfo, chatModel)
if (cInfo.groupInfo.membership.memberRole == GroupMemberRole.Owner) {
val relays = chatModel.controller.apiGetGroupRelays(cInfo.groupInfo.groupId)
val relays = chatModel.controller.apiGetGroupRelays(chatRh, cInfo.groupInfo.groupId)
withContext(Dispatchers.Main) {
ChannelRelaysModel.set(cInfo.groupInfo.groupId, relays)
}
@@ -31,6 +31,7 @@ data class AvailableRelay(
@Composable
fun AddGroupRelayView(
rhId: Long?,
groupInfo: GroupInfo,
existingRelayIds: Set<Long>,
onRelayAdded: () -> Unit,
@@ -46,7 +47,7 @@ fun AddGroupRelayView(
LaunchedEffect(Unit) {
try {
val servers = ChatController.getUserServers(null)
val servers = ChatController.getUserServers(rhId)
if (servers != null) {
val relays = mutableListOf<AvailableRelay>()
for (op in servers) {
@@ -80,7 +81,7 @@ fun AddGroupRelayView(
if (relayIds.isEmpty()) return@AddGroupRelayLayout
isAdding = true
scope.launch {
addSelectedRelays(groupInfo, relayIds, selectedRelayIds, availableRelays, onRelayAdded, close) { newSelectedIds, newAvailableRelays ->
addSelectedRelays(rhId, groupInfo, relayIds, selectedRelayIds, availableRelays, onRelayAdded, close) { newSelectedIds, newAvailableRelays ->
selectedRelayIds = newSelectedIds
availableRelays = newAvailableRelays
isAdding = false
@@ -183,6 +184,7 @@ private fun AddRelaysButton(onClick: () -> Unit, disabled: Boolean) {
}
private suspend fun addSelectedRelays(
rhId: Long?,
groupInfo: GroupInfo,
relayIds: List<Long>,
selectedRelayIds: Set<Long>,
@@ -192,7 +194,7 @@ private suspend fun addSelectedRelays(
updateState: (Set<Long>, List<AvailableRelay>) -> Unit
) {
try {
val result = ChatController.apiAddGroupRelays(groupInfo.groupId, relayIds)
val result = ChatController.apiAddGroupRelays(rhId, groupInfo.groupId, relayIds)
if (result == null) {
updateState(selectedRelayIds, availableRelays)
return
@@ -37,7 +37,7 @@ fun ChannelRelaysView(
LaunchedEffect(Unit) {
setGroupMembers(rhId, groupInfo, chatModel)
if (groupInfo.isOwner) {
val relays = chatModel.controller.apiGetGroupRelays(groupInfo.groupId)
val relays = chatModel.controller.apiGetGroupRelays(rhId, groupInfo.groupId)
ChannelRelaysModel.set(groupId = groupInfo.groupId, groupRelays = relays)
}
}
@@ -114,6 +114,7 @@ private fun ChannelRelaysLayout(
val existingRelayIds = groupRelays.mapNotNull { it.userChatRelay.chatRelayId }.toSet()
ModalManager.end.showModalCloseable(showClose = true, cardScreen = true) { close ->
AddGroupRelayView(
rhId = rhId,
groupInfo = groupInfo,
existingRelayIds = existingRelayIds,
onRelayAdded = { withBGApi { setGroupMembers(rhId, groupInfo, chatModel) } },
@@ -81,7 +81,7 @@ fun ChannelWebPageView(
}
LaunchedEffect(Unit) {
val relays = chatModel.controller.apiGetGroupRelays(groupInfo.groupId)
val relays = chatModel.controller.apiGetGroupRelays(rhId, groupInfo.groupId)
groupRelays.clear()
groupRelays.addAll(relays)
}
@@ -38,7 +38,8 @@ import dev.icerock.moko.resources.compose.painterResource
import kotlinx.coroutines.*
@Composable
fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit) {
fun AddChannelView(chatModel: ChatModel, rh: RemoteHostInfo?, close: () -> Unit, closeAll: () -> Unit) {
val rhId = rh?.remoteHostId
val view = LocalMultiplatformView()
val bottomSheetModalState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()
@@ -56,7 +57,7 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
val gInfo = groupInfo.value
if (showLinkStep.value && gInfo != null) {
LinkStepView(chatModel, gInfo, groupLink, closeAll)
LinkStepView(chatModel, rhId, gInfo, groupLink, closeAll)
} else if (gInfo != null) {
ProgressStepView(
chatModel, gInfo, groupRelays, relayListExpanded,
@@ -65,9 +66,9 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
chatModel.creatingChannelId.value = null
closeAll()
withBGApi {
openGroupChat(null, gInfo.groupId)
openGroupChat(rhId, gInfo.groupId)
ModalManager.end.showModalCloseable(showClose = true, cardScreen = true) { close ->
GroupLinkView(chatModel, rhId = null, groupInfo = gInfo, groupLink = groupLink.value, onGroupLinkUpdated = null, creatingGroup = true, isChannel = true, shareGroupInfo = gInfo, close = close)
GroupLinkView(chatModel, rhId = rhId, groupInfo = gInfo, groupLink = groupLink.value, onGroupLinkUpdated = null, creatingGroup = true, isChannel = true, shareGroupInfo = gInfo, close = close)
}
}
}
@@ -80,9 +81,9 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
closeAll()
withBGApi {
try {
chatModel.controller.apiDeleteChat(rh = null, type = ChatType.Group, id = gInfo.apiId)
chatModel.controller.apiDeleteChat(rh = rhId, type = ChatType.Group, id = gInfo.apiId)
withContext(Dispatchers.Main) {
chatModel.chatsContext.removeChat(null, gInfo.id)
chatModel.chatsContext.removeChat(rhId, gInfo.id)
}
} catch (e: Exception) {
Log.e(TAG, "cancelChannelCreation error: ${e.message}")
@@ -93,6 +94,7 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
} else {
ProfileStepView(
chatModel = chatModel,
rhId = rhId,
displayName = displayName,
profileImage = profileImage,
chosenImage = chosenImage,
@@ -120,7 +122,7 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
creationInProgress.value = true
withBGApi {
try {
val enabledRelays = chooseRandomRelays()
val enabledRelays = chooseRandomRelays(rhId)
val relayIds = enabledRelays.mapNotNull { it.chatRelayId }
if (relayIds.isEmpty()) {
withContext(Dispatchers.Main) {
@@ -130,7 +132,7 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
return@withBGApi
}
val result = chatModel.controller.apiNewPublicGroup(
rh = null,
rh = rhId,
incognito = false,
relayIds = relayIds,
groupProfile = profile
@@ -138,7 +140,7 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
when (result) {
is ChatController.PublicGroupCreationResult.Created -> {
withContext(Dispatchers.Main) {
chatModel.chatsContext.updateGroup(rhId = null, result.groupInfo)
chatModel.chatsContext.updateGroup(rhId = rhId, result.groupInfo)
chatModel.creatingChannelId.value = result.groupInfo.id
groupInfo.value = result.groupInfo
groupLink.value = result.groupLink
@@ -178,8 +180,8 @@ fun AddChannelView(chatModel: ChatModel, close: () -> Unit, closeAll: () -> Unit
private const val maxRelays = 3
private suspend fun chooseRandomRelays(): List<UserChatRelay> {
val servers = getUserServers(rh = null) ?: return emptyList()
private suspend fun chooseRandomRelays(rhId: Long?): List<UserChatRelay> {
val servers = getUserServers(rh = rhId) ?: return emptyList()
// Operator relays are grouped per operator; custom relays (null operator)
// are treated independently to maximize trust distribution.
val operatorGroups = mutableListOf<List<UserChatRelay>>()
@@ -215,8 +217,8 @@ private suspend fun chooseRandomRelays(): List<UserChatRelay> {
return selected
}
private suspend fun checkHasRelays(): Boolean {
val servers = try { getUserServers(rh = null) } catch (_: Exception) { null } ?: return false
private suspend fun checkHasRelays(rhId: Long?): Boolean {
val servers = try { getUserServers(rh = rhId) } catch (_: Exception) { null } ?: return false
return servers.any { op ->
(op.operator?.enabled ?: true) &&
op.chatRelays.any { it.enabled && !it.deleted && it.chatRelayId != null }
@@ -226,6 +228,7 @@ private suspend fun checkHasRelays(): Boolean {
@Composable
private fun ProfileStepView(
chatModel: ChatModel,
rhId: Long?,
displayName: MutableState<String>,
profileImage: MutableState<String?>,
chosenImage: MutableState<URI?>,
@@ -239,7 +242,7 @@ private fun ProfileStepView(
createChannel: () -> Unit
) {
LaunchedEffect(Unit) {
hasRelays.value = checkHasRelays()
hasRelays.value = checkHasRelays(rhId)
}
ModalBottomSheetLayout(
@@ -553,6 +556,7 @@ private fun RelayRow(relay: GroupRelay, connFailed: Boolean) {
@Composable
private fun LinkStepView(
chatModel: ChatModel,
rhId: Long?,
gInfo: GroupInfo,
groupLink: MutableState<GroupLink?>,
closeAll: () -> Unit
@@ -563,14 +567,14 @@ private fun LinkStepView(
delay(500)
withContext(Dispatchers.Main) {
ModalManager.start.closeModals()
openGroupChat(null, gInfo.groupId)
openGroupChat(rhId, gInfo.groupId)
}
}
}
ModalView(close = close, showClose = false, cardScreen = true) {
GroupLinkView(
chatModel = chatModel,
rhId = null,
rhId = rhId,
groupInfo = gInfo,
groupLink = groupLink.value,
onGroupLinkUpdated = { groupLink.value = it },
@@ -660,6 +664,6 @@ fun RelayProgressIndicator(active: Int, total: Int) {
@Composable
fun PreviewAddChannelView() {
SimpleXTheme {
AddChannelView(chatModel = ChatModel, close = {}, closeAll = {})
AddChannelView(chatModel = ChatModel, rh = null, close = {}, closeAll = {})
}
}
@@ -64,7 +64,7 @@ fun ModalData.NewChatSheet(rh: RemoteHostInfo?, close: () -> Unit) {
ModalManager.start.showCustomModal { close -> AddGroupView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) }
},
createChannel = {
ModalManager.start.showCustomModal { close -> AddChannelView(chatModel, close, closeAll) }
ModalManager.start.showCustomModal { close -> AddChannelView(chatModel, chatModel.currentRemoteHost.value, close, closeAll) }
},
rh = rh,
close = close