Files

120 lines
5.4 KiB
Swift

import Foundation
import Postbox
import TelegramApi
import SwiftSignalKit
import MtProtoKit
public enum JoinChannelError {
case generic
case tooMuchJoined
case tooMuchUsers
case inviteRequestSent
}
public enum JoinChannelResult {
case joined(RenderedChannelParticipant?)
case webView(JoinChatWebView)
}
func _internal_joinChannel(account: Account, peerId: PeerId, hash: String?) -> Signal<JoinChannelResult, JoinChannelError> {
return account.postbox.loadedPeerWithId(peerId)
|> take(1)
|> castError(JoinChannelError.self)
|> mapToSignal { peer -> Signal<JoinChannelResult, JoinChannelError> in
let request: Signal<Api.messages.ChatInviteJoinResult, MTRpcError>
if let hash = hash {
request = account.network.request(Api.functions.messages.importChatInvite(hash: hash))
} else if let inputChannel = apiInputChannel(peer) {
request = account.network.request(Api.functions.channels.joinChannel(channel: inputChannel))
} else {
request = .fail(.init())
}
return request
|> mapError { error -> JoinChannelError in
switch error.errorDescription {
case "CHANNELS_TOO_MUCH":
return .tooMuchJoined
case "USERS_TOO_MUCH":
return .tooMuchUsers
case "INVITE_REQUEST_SENT":
return .inviteRequestSent
default:
return .generic
}
}
|> mapToSignal { result -> Signal<JoinChannelResult, JoinChannelError> in
let updates: Api.Updates
switch result {
case let .chatInviteJoinResultOk(data):
updates = data.updates
case let .chatInviteJoinResultWebView(data):
switch data.webview {
case let .webViewResultUrl(urlData):
let botPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(data.botId))
return account.postbox.transaction { transaction -> Signal<JoinChannelResult, JoinChannelError> in
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: AccumulatedPeers(users: data.users))
guard let botPeer = transaction.getPeer(botPeerId) else {
return .fail(.generic)
}
return .single(.webView(JoinChatWebView(botPeer: EnginePeer(botPeer), url: urlData.url, queryId: urlData.queryId ?? 0, peerId: peerId)))
}
|> castError(JoinChannelError.self)
|> switchToLatest
}
}
account.stateManager.addUpdates(updates)
if hash == nil {
let _ = _internal_requestRecommendedChannels(account: account, peerId: peerId, forceUpdate: true).startStandalone()
}
let channels = updates.chats.compactMap { parseTelegramGroupOrChannel(chat: $0) }.compactMap(apiInputChannel)
if let inputChannel = channels.first {
return account.network.request(Api.functions.channels.getParticipant(channel: inputChannel, participant: .inputPeerSelf))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.channels.ChannelParticipant?, JoinChannelError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<JoinChannelResult, JoinChannelError> in
guard let result = result else {
return .fail(.generic)
}
return account.postbox.transaction { transaction -> JoinChannelResult in
var peers: [EnginePeer.Id: EnginePeer] = [:]
var presences: [PeerId: PeerPresence] = [:]
guard let peer = transaction.getPeer(account.peerId) else {
return .joined(nil)
}
peers[account.peerId] = EnginePeer(peer)
if let presence = transaction.getPeerPresence(peerId: account.peerId) {
presences[account.peerId] = presence
}
let updatedParticipant: ChannelParticipant
switch result {
case let .channelParticipant(channelParticipantData):
let participant = channelParticipantData.participant
updatedParticipant = ChannelParticipant(apiParticipant: participant)
}
if case let .member(_, _, maybeAdminInfo, _, _, _) = updatedParticipant {
if let adminInfo = maybeAdminInfo {
if let peer = transaction.getPeer(adminInfo.promotedBy) {
peers[peer.id] = EnginePeer(peer)
}
}
}
return .joined(RenderedChannelParticipant(participant: updatedParticipant, peer: EnginePeer(peer), peers: peers, presences: presences))
}
|> castError(JoinChannelError.self)
}
} else {
return .fail(.generic)
}
}
}
}