mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Conference updates
This commit is contained in:
parent
e8b7f53c84
commit
0a499f4e2b
@ -961,7 +961,6 @@ private final class NotificationServiceHandler {
|
|||||||
|
|
||||||
if let locKey = payloadJson["loc-key"] as? String, (locKey == "CONF_CALL_REQUEST" || locKey == "CONF_CALL_MISSED"), let callIdString = payloadJson["call_id"] as? String {
|
if let locKey = payloadJson["loc-key"] as? String, (locKey == "CONF_CALL_REQUEST" || locKey == "CONF_CALL_MISSED"), let callIdString = payloadJson["call_id"] as? String {
|
||||||
if let callId = Int64(callIdString) {
|
if let callId = Int64(callIdString) {
|
||||||
|
|
||||||
if let updates = payloadJson["updates"] as? String {
|
if let updates = payloadJson["updates"] as? String {
|
||||||
var updateString = updates
|
var updateString = updates
|
||||||
updateString = updateString.replacingOccurrences(of: "-", with: "+")
|
updateString = updateString.replacingOccurrences(of: "-", with: "+")
|
||||||
|
@ -487,6 +487,7 @@ public protocol PresentationGroupCall: AnyObject {
|
|||||||
func updateTitle(_ title: String)
|
func updateTitle(_ title: String)
|
||||||
|
|
||||||
func invitePeer(_ peerId: EnginePeer.Id, isVideo: Bool) -> Bool
|
func invitePeer(_ peerId: EnginePeer.Id, isVideo: Bool) -> Bool
|
||||||
|
func kickPeer(id: EnginePeer.Id)
|
||||||
func removedPeer(_ peerId: EnginePeer.Id)
|
func removedPeer(_ peerId: EnginePeer.Id)
|
||||||
var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get }
|
var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get }
|
||||||
|
|
||||||
|
@ -217,6 +217,12 @@ public final class SharedCallAudioContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func switchToSpeakerIfBuiltin() {
|
||||||
|
if case .builtin = self.currentAudioOutputValue {
|
||||||
|
self.setCurrentAudioOutput(.speaker)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class PresentationCallImpl: PresentationCall {
|
public final class PresentationCallImpl: PresentationCall {
|
||||||
@ -1032,6 +1038,8 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
self.conferenceCallImpl = conferenceCall
|
self.conferenceCallImpl = conferenceCall
|
||||||
conferenceCall.upgradedConferenceCall = self
|
conferenceCall.upgradedConferenceCall = self
|
||||||
|
|
||||||
|
self.sharedAudioContext?.switchToSpeakerIfBuiltin()
|
||||||
|
|
||||||
for (peerId, isVideo) in self.pendingInviteToConferencePeerIds {
|
for (peerId, isVideo) in self.pendingInviteToConferencePeerIds {
|
||||||
let _ = conferenceCall.invitePeer(peerId, isVideo: isVideo)
|
let _ = conferenceCall.invitePeer(peerId, isVideo: isVideo)
|
||||||
}
|
}
|
||||||
|
@ -3986,6 +3986,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func kickPeer(id: EnginePeer.Id) {
|
||||||
|
if self.isConference {
|
||||||
|
self.removedPeer(id)
|
||||||
|
|
||||||
|
self.e2eContext?.kickPeer(id: id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func removedPeer(_ peerId: PeerId) {
|
public func removedPeer(_ peerId: PeerId) {
|
||||||
var updatedInvitedPeers = self.invitedPeersValue
|
var updatedInvitedPeers = self.invitedPeersValue
|
||||||
updatedInvitedPeers.removeAll(where: { $0.id == peerId})
|
updatedInvitedPeers.removeAll(where: { $0.id == peerId})
|
||||||
|
@ -149,6 +149,7 @@ final class VideoChatParticipantsComponent: Component {
|
|||||||
let safeInsets: UIEdgeInsets
|
let safeInsets: UIEdgeInsets
|
||||||
let interfaceOrientation: UIInterfaceOrientation
|
let interfaceOrientation: UIInterfaceOrientation
|
||||||
let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
|
let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
|
||||||
|
let openInvitedParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
|
||||||
let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void
|
let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void
|
||||||
let updateIsMainParticipantPinned: (Bool) -> Void
|
let updateIsMainParticipantPinned: (Bool) -> Void
|
||||||
let updateIsExpandedUIHidden: (Bool) -> Void
|
let updateIsExpandedUIHidden: (Bool) -> Void
|
||||||
@ -169,6 +170,7 @@ final class VideoChatParticipantsComponent: Component {
|
|||||||
safeInsets: UIEdgeInsets,
|
safeInsets: UIEdgeInsets,
|
||||||
interfaceOrientation: UIInterfaceOrientation,
|
interfaceOrientation: UIInterfaceOrientation,
|
||||||
openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
|
openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
|
||||||
|
openInvitedParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
|
||||||
updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void,
|
updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void,
|
||||||
updateIsMainParticipantPinned: @escaping (Bool) -> Void,
|
updateIsMainParticipantPinned: @escaping (Bool) -> Void,
|
||||||
updateIsExpandedUIHidden: @escaping (Bool) -> Void,
|
updateIsExpandedUIHidden: @escaping (Bool) -> Void,
|
||||||
@ -188,6 +190,7 @@ final class VideoChatParticipantsComponent: Component {
|
|||||||
self.safeInsets = safeInsets
|
self.safeInsets = safeInsets
|
||||||
self.interfaceOrientation = interfaceOrientation
|
self.interfaceOrientation = interfaceOrientation
|
||||||
self.openParticipantContextMenu = openParticipantContextMenu
|
self.openParticipantContextMenu = openParticipantContextMenu
|
||||||
|
self.openInvitedParticipantContextMenu = openInvitedParticipantContextMenu
|
||||||
self.updateMainParticipant = updateMainParticipant
|
self.updateMainParticipant = updateMainParticipant
|
||||||
self.updateIsMainParticipantPinned = updateIsMainParticipantPinned
|
self.updateIsMainParticipantPinned = updateIsMainParticipantPinned
|
||||||
self.updateIsExpandedUIHidden = updateIsExpandedUIHidden
|
self.updateIsExpandedUIHidden = updateIsExpandedUIHidden
|
||||||
@ -1317,8 +1320,18 @@ final class VideoChatParticipantsComponent: Component {
|
|||||||
inset: 2.0,
|
inset: 2.0,
|
||||||
background: UIColor(white: 0.1, alpha: 1.0)
|
background: UIColor(white: 0.1, alpha: 1.0)
|
||||||
),
|
),
|
||||||
action: nil,
|
action: { [weak self] peer, _, itemView in
|
||||||
contextAction: nil
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.openInvitedParticipantContextMenu(peer.id, itemView.extractedContainerView, nil)
|
||||||
|
},
|
||||||
|
contextAction: { [weak self] peer, sourceView, gesture in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.openInvitedParticipantContextMenu(peer.id, sourceView, gesture)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2329,6 +2329,12 @@ final class VideoChatScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
|
self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
|
||||||
},
|
},
|
||||||
|
openInvitedParticipantContextMenu: { [weak self] id, sourceView, gesture in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openInvitedParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
|
||||||
|
},
|
||||||
updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in
|
updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
|
@ -299,7 +299,11 @@ extension VideoChatScreenComponent.View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _ = groupCall.accountContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: groupCall.accountContext.engine, peerId: callPeerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start()
|
let _ = groupCall.accountContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: groupCall.accountContext.engine, peerId: callPeerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start()
|
||||||
groupCall.removedPeer(peer.id)
|
if groupCall.isConference {
|
||||||
|
groupCall.kickPeer(id: peer.id)
|
||||||
|
} else {
|
||||||
|
groupCall.removedPeer(peer.id)
|
||||||
|
}
|
||||||
|
|
||||||
self.presentUndoOverlay(content: .banned(text: environment.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: environment.strings, displayOrder: nameDisplayOrder)).string), action: { _ in return false })
|
self.presentUndoOverlay(content: .banned(text: environment.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: environment.strings, displayOrder: nameDisplayOrder)).string), action: { _ in return false })
|
||||||
}))
|
}))
|
||||||
@ -347,6 +351,62 @@ extension VideoChatScreenComponent.View {
|
|||||||
environment.controller()?.presentInGlobalOverlay(contextController)
|
environment.controller()?.presentInGlobalOverlay(contextController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func openInvitedParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) {
|
||||||
|
guard let environment = self.environment else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let currentCall = self.currentCall else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard case .group = self.currentCall else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let itemsForEntry: () -> [ContextMenuItem] = { [weak self] in
|
||||||
|
guard let self, let environment = self.environment else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
var items: [ContextMenuItem] = []
|
||||||
|
|
||||||
|
items.append(.action(ContextMenuActionItem(text: environment.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
|
||||||
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||||
|
}, action: { [weak self] c, _ in
|
||||||
|
c?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||||
|
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard case let .group(groupCall) = self.currentCall else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
groupCall.kickPeer(id: id)
|
||||||
|
})))
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
let items = itemsForEntry()
|
||||||
|
|
||||||
|
let presentationData = currentCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||||
|
let contextController = ContextController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
source: .extracted(ParticipantExtractedContentSource(contentView: sourceView)),
|
||||||
|
items: .single(ContextController.Items(content: .list(items))),
|
||||||
|
recognizer: nil,
|
||||||
|
gesture: gesture
|
||||||
|
)
|
||||||
|
|
||||||
|
environment.controller()?.forEachController({ controller in
|
||||||
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
controller.dismiss()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
environment.controller()?.presentInGlobalOverlay(contextController)
|
||||||
|
}
|
||||||
|
|
||||||
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||||
guard let currentCall = self.currentCall else {
|
guard let currentCall = self.currentCall else {
|
||||||
return
|
return
|
||||||
|
@ -53,6 +53,8 @@ public final class ConferenceCallE2EContext {
|
|||||||
private var synchronizeRemovedParticipantsDisposable: Disposable?
|
private var synchronizeRemovedParticipantsDisposable: Disposable?
|
||||||
private var synchronizeRemovedParticipantsTimer: Foundation.Timer?
|
private var synchronizeRemovedParticipantsTimer: Foundation.Timer?
|
||||||
|
|
||||||
|
private var pendingKickPeers: [EnginePeer.Id] = []
|
||||||
|
|
||||||
init(queue: Queue, engine: TelegramEngine, callId: Int64, accessHash: Int64, userId: Int64, reference: InternalGroupCallReference, state: Atomic<ContextStateHolder>, initializeState: @escaping (TelegramKeyPair, Int64, Data) -> ConferenceCallE2EContextState?, keyPair: TelegramKeyPair) {
|
init(queue: Queue, engine: TelegramEngine, callId: Int64, accessHash: Int64, userId: Int64, reference: InternalGroupCallReference, state: Atomic<ContextStateHolder>, initializeState: @escaping (TelegramKeyPair, Int64, Data) -> ConferenceCallE2EContextState?, keyPair: TelegramKeyPair) {
|
||||||
precondition(queue.isCurrent())
|
precondition(queue.isCurrent())
|
||||||
precondition(Queue.mainQueue().isCurrent())
|
precondition(Queue.mainQueue().isCurrent())
|
||||||
@ -91,37 +93,53 @@ public final class ConferenceCallE2EContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addChainBlocksUpdate(subChainId: Int, blocks: [Data], nextOffset: Int) {
|
func addChainBlocksUpdate(subChainId: Int, blocks: [Data], nextOffset: Int) {
|
||||||
var processBlock = true
|
|
||||||
let updateBaseOffset = nextOffset - blocks.count
|
let updateBaseOffset = nextOffset - blocks.count
|
||||||
if subChainId == 0 {
|
var blocksToProcess: [Data] = []
|
||||||
if let e2ePoll0Offset = self.e2ePoll0Offset {
|
var shouldPoll = false
|
||||||
if e2ePoll0Offset == updateBaseOffset {
|
for i in 0 ..< blocks.count {
|
||||||
self.e2ePoll0Offset = nextOffset
|
let blockOffset = updateBaseOffset + i
|
||||||
} else if e2ePoll0Offset < updateBaseOffset {
|
if subChainId == 0 {
|
||||||
self.e2ePoll(subChainId: subChainId)
|
if var e2ePoll0Offset = self.e2ePoll0Offset {
|
||||||
} else {
|
if blockOffset == e2ePoll0Offset {
|
||||||
processBlock = false
|
e2ePoll0Offset += 1
|
||||||
|
self.e2ePoll0Offset = e2ePoll0Offset
|
||||||
|
blocksToProcess.append(blocks[i])
|
||||||
|
} else if blockOffset > e2ePoll0Offset {
|
||||||
|
shouldPoll = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if subChainId == 1 {
|
||||||
processBlock = false
|
if var e2ePoll1Offset = self.e2ePoll1Offset {
|
||||||
}
|
if blockOffset == e2ePoll1Offset {
|
||||||
} else if subChainId == 1 {
|
e2ePoll1Offset += 1
|
||||||
if let e2ePoll1Offset = self.e2ePoll1Offset {
|
self.e2ePoll1Offset = e2ePoll1Offset
|
||||||
if e2ePoll1Offset == updateBaseOffset {
|
blocksToProcess.append(blocks[i])
|
||||||
self.e2ePoll1Offset = nextOffset
|
} else if blockOffset > e2ePoll1Offset {
|
||||||
} else if e2ePoll1Offset < updateBaseOffset {
|
shouldPoll = true
|
||||||
self.e2ePoll(subChainId: subChainId)
|
}
|
||||||
} else {
|
|
||||||
processBlock = false
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
processBlock = false
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
processBlock = false
|
|
||||||
}
|
}
|
||||||
if processBlock {
|
|
||||||
self.addE2EBlocks(blocks: blocks, subChainId: subChainId)
|
if !blocksToProcess.isEmpty {
|
||||||
|
if subChainId == 0 {
|
||||||
|
if self.e2ePoll0Disposable != nil {
|
||||||
|
self.e2ePoll0Disposable?.dispose()
|
||||||
|
self.e2ePoll0Disposable = nil
|
||||||
|
shouldPoll = true
|
||||||
|
}
|
||||||
|
} else if subChainId == 1 {
|
||||||
|
if self.e2ePoll1Disposable != nil {
|
||||||
|
self.e2ePoll1Disposable?.dispose()
|
||||||
|
self.e2ePoll1Disposable = nil
|
||||||
|
shouldPoll = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.addE2EBlocks(blocks: blocksToProcess, subChainId: subChainId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if shouldPoll {
|
||||||
|
self.e2ePoll(subChainId: subChainId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +205,14 @@ public final class ConferenceCallE2EContext {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subChainId == 0 {
|
||||||
|
self.e2ePoll0Disposable?.dispose()
|
||||||
|
self.e2ePoll0Disposable = nil
|
||||||
|
} else if subChainId == 1 {
|
||||||
|
self.e2ePoll1Disposable?.dispose()
|
||||||
|
self.e2ePoll1Disposable = nil
|
||||||
|
}
|
||||||
|
|
||||||
var delayPoll = true
|
var delayPoll = true
|
||||||
if let result {
|
if let result {
|
||||||
if subChainId == 0 {
|
if subChainId == 0 {
|
||||||
@ -247,71 +273,139 @@ public final class ConferenceCallE2EContext {
|
|||||||
let callId = self.callId
|
let callId = self.callId
|
||||||
let accessHash = self.accessHash
|
let accessHash = self.accessHash
|
||||||
|
|
||||||
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
if !self.pendingKickPeers.isEmpty {
|
||||||
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants(
|
let pendingKickPeers = self.pendingKickPeers
|
||||||
account: self.engine.account,
|
self.pendingKickPeers.removeAll()
|
||||||
reference: self.reference,
|
|
||||||
offset: "",
|
|
||||||
ssrcs: [],
|
|
||||||
limit: 100,
|
|
||||||
sortAscending: true
|
|
||||||
)
|
|
||||||
|> map(Optional.init)
|
|
||||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
|
||||||
return .single(nil)
|
|
||||||
}
|
|
||||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
|
||||||
guard let result else {
|
|
||||||
return .single(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
let blockchainPeerIds = state.with { state -> [Int64] in
|
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
||||||
guard let state = state.state else {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return state.getParticipantIds()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Peer ids that are in the blockchain but not in the server list
|
let removeBlock = state.with({ state -> Data? in
|
||||||
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
|
|
||||||
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
|
|
||||||
}
|
|
||||||
|
|
||||||
if removedPeerIds.isEmpty {
|
|
||||||
return .single(false)
|
|
||||||
}
|
|
||||||
guard let removeBlock = state.with({ state -> Data? in
|
|
||||||
guard let state = state.state else {
|
guard let state = state.state else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds)
|
let currentIds = state.getParticipantIds()
|
||||||
}) else {
|
let remainingIds = pendingKickPeers.filter({ currentIds.contains($0.id._internalGetInt64Value()) })
|
||||||
return .single(false)
|
if remainingIds.isEmpty {
|
||||||
}
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|
return state.generateRemoveParticipantsBlock(participantIds: remainingIds.map { $0.id._internalGetInt64Value() })
|
||||||
|> map { result -> Bool in
|
})
|
||||||
switch result {
|
if let removeBlock {
|
||||||
case .success:
|
self.synchronizeRemovedParticipantsDisposable = (engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .kick, participantIds: pendingKickPeers.map { $0.id._internalGetInt64Value() }, block: removeBlock)
|
||||||
return true
|
|> map { result -> Bool in
|
||||||
case .pollBlocksAndRetry:
|
switch result {
|
||||||
return false
|
case .success:
|
||||||
|
return true
|
||||||
|
case .pollBlocksAndRetry:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] shouldRetry in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if shouldRetry {
|
||||||
|
for id in pendingKickPeers {
|
||||||
|
if !self.pendingKickPeers.contains(id) {
|
||||||
|
self.pendingKickPeers.append(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.isSynchronizingRemovedParticipants = false
|
||||||
|
if self.scheduledSynchronizeRemovedParticipants {
|
||||||
|
self.scheduledSynchronizeRemovedParticipants = false
|
||||||
|
self.synchronizeRemovedParticipants()
|
||||||
|
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
||||||
|
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
||||||
|
self.e2ePoll(subChainId: 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.isSynchronizingRemovedParticipants = false
|
||||||
|
if self.scheduledSynchronizeRemovedParticipants {
|
||||||
|
self.scheduledSynchronizeRemovedParticipants = false
|
||||||
|
self.synchronizeRemovedParticipants()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
||||||
|
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants(
|
||||||
|
account: self.engine.account,
|
||||||
|
reference: self.reference,
|
||||||
|
offset: "",
|
||||||
|
ssrcs: [],
|
||||||
|
limit: 100,
|
||||||
|
sortAscending: true
|
||||||
|
)
|
||||||
|
|> map(Optional.init)
|
||||||
|
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||||
|
guard let result else {
|
||||||
|
return .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
let blockchainPeerIds = state.with { state -> [Int64] in
|
||||||
|
guard let state = state.state else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return state.getParticipantIds()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peer ids that are in the blockchain but not in the server list
|
||||||
|
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
|
||||||
|
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
|
||||||
|
}
|
||||||
|
|
||||||
|
if removedPeerIds.isEmpty {
|
||||||
|
return .single(false)
|
||||||
|
}
|
||||||
|
guard let removeBlock = state.with({ state -> Data? in
|
||||||
|
guard let state = state.state else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds)
|
||||||
|
}) else {
|
||||||
|
return .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|
||||||
|
|> map { result -> Bool in
|
||||||
|
switch result {
|
||||||
|
case .success:
|
||||||
|
return true
|
||||||
|
case .pollBlocksAndRetry:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isSynchronizingRemovedParticipants = false
|
||||||
|
if self.scheduledSynchronizeRemovedParticipants {
|
||||||
|
self.scheduledSynchronizeRemovedParticipants = false
|
||||||
|
self.synchronizeRemovedParticipants()
|
||||||
|
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
||||||
|
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
||||||
|
self.e2ePoll(subChainId: 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func kickPeer(id: EnginePeer.Id) {
|
||||||
|
//TODO:release
|
||||||
|
if !self.pendingKickPeers.contains(id) {
|
||||||
|
self.pendingKickPeers.append(id)
|
||||||
|
|
||||||
|
self.synchronizeRemovedParticipants()
|
||||||
}
|
}
|
||||||
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.isSynchronizingRemovedParticipants = false
|
|
||||||
if self.scheduledSynchronizeRemovedParticipants {
|
|
||||||
self.scheduledSynchronizeRemovedParticipants = false
|
|
||||||
self.synchronizeRemovedParticipants()
|
|
||||||
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
|
||||||
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
|
||||||
self.e2ePoll(subChainId: 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,4 +443,10 @@ public final class ConferenceCallE2EContext {
|
|||||||
impl.synchronizeRemovedParticipants()
|
impl.synchronizeRemovedParticipants()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func kickPeer(id: EnginePeer.Id) {
|
||||||
|
self.impl.with { impl in
|
||||||
|
impl.kickPeer(id: id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
60
third-party/td/TdBinding/Sources/TdBinding.mm
vendored
60
third-party/td/TdBinding/Sources/TdBinding.mm
vendored
@ -83,6 +83,13 @@ static NSString *hexStringFromData(NSData *data) {
|
|||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_callId = callId;
|
_callId = callId;
|
||||||
_keyPair = keyPair;
|
_keyPair = keyPair;
|
||||||
|
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^{
|
||||||
|
#if DEBUG
|
||||||
|
tde2e_api::set_log_verbosity_level(4);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -130,7 +137,17 @@ static NSString *hexStringFromData(NSData *data) {
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
auto describeResult = tde2e_api::call_describe_message(it);
|
auto describeResult = tde2e_api::call_describe_message(it);
|
||||||
if (describeResult.is_ok()) {
|
if (describeResult.is_ok()) {
|
||||||
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: block %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||||
|
if (utf8String) {
|
||||||
|
NSLog(@"TdCall.call_pull_outbound_messages block: %@", utf8String);
|
||||||
|
} else {
|
||||||
|
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||||
|
if (lossyString) {
|
||||||
|
NSLog(@"TdCall.call_pull_outbound_messages block (lossy conversion): %@", lossyString);
|
||||||
|
} else {
|
||||||
|
NSLog(@"TdCall.call_pull_outbound_messages block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: describe block failed");
|
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: describe block failed");
|
||||||
}
|
}
|
||||||
@ -178,7 +195,17 @@ static NSString *hexStringFromData(NSData *data) {
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
auto describeResult = tde2e_api::call_describe_block(mappedBlock);
|
auto describeResult = tde2e_api::call_describe_block(mappedBlock);
|
||||||
if (describeResult.is_ok()) {
|
if (describeResult.is_ok()) {
|
||||||
NSLog(@"TdCall.applyBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||||
|
if (utf8String) {
|
||||||
|
NSLog(@"TdCall.applyBlock block: %@", utf8String);
|
||||||
|
} else {
|
||||||
|
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||||
|
if (lossyString) {
|
||||||
|
NSLog(@"TdCall.applyBlock block (lossy conversion): %@", lossyString);
|
||||||
|
} else {
|
||||||
|
NSLog(@"TdCall.applyBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"TdCall.applyBlock block: describe block failed");
|
NSLog(@"TdCall.applyBlock block: describe block failed");
|
||||||
}
|
}
|
||||||
@ -196,7 +223,17 @@ static NSString *hexStringFromData(NSData *data) {
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
auto describeResult = tde2e_api::call_describe_message(mappedBlock);
|
auto describeResult = tde2e_api::call_describe_message(mappedBlock);
|
||||||
if (describeResult.is_ok()) {
|
if (describeResult.is_ok()) {
|
||||||
NSLog(@"TdCall.applyBroadcastBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||||
|
if (utf8String) {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock block: %@", utf8String);
|
||||||
|
} else {
|
||||||
|
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||||
|
if (lossyString) {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock block (lossy conversion): %@", lossyString);
|
||||||
|
} else {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
NSLog(@"TdCall.applyBroadcastBlock block: describe block failed");
|
NSLog(@"TdCall.applyBroadcastBlock block: describe block failed");
|
||||||
}
|
}
|
||||||
@ -206,6 +243,23 @@ static NSString *hexStringFromData(NSData *data) {
|
|||||||
if (!result.is_ok()) {
|
if (!result.is_ok()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
describeResult = tde2e_api::call_describe(_callId);
|
||||||
|
if (describeResult.is_ok()) {
|
||||||
|
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||||
|
if (utf8String) {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock call after apply: %@", utf8String);
|
||||||
|
} else {
|
||||||
|
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||||
|
if (lossyString) {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock call after apply (lossy conversion): %@", lossyString);
|
||||||
|
} else {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock call after apply: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSLog(@"TdCall.applyBroadcastBlock call after apply: describe block failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (nullable NSData *)generateRemoveParticipantsBlock:(NSArray<NSNumber *> *)participantIds {
|
- (nullable NSData *)generateRemoveParticipantsBlock:(NSArray<NSNumber *> *)participantIds {
|
||||||
|
1
third-party/td/build-td-bazel.sh
vendored
1
third-party/td/build-td-bazel.sh
vendored
@ -14,7 +14,6 @@ options=""
|
|||||||
options="$options -DOPENSSL_FOUND=1"
|
options="$options -DOPENSSL_FOUND=1"
|
||||||
options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
|
options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
|
||||||
options="$options -DOPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/src/include"
|
options="$options -DOPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/src/include"
|
||||||
#options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library}"
|
|
||||||
options="$options -DCMAKE_BUILD_TYPE=Release"
|
options="$options -DCMAKE_BUILD_TYPE=Release"
|
||||||
|
|
||||||
cd "$BUILD_DIR"
|
cd "$BUILD_DIR"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user