This commit is contained in:
overtake 2017-05-07 16:40:55 +03:00
commit dc46d2a473
5 changed files with 217 additions and 132 deletions

View File

@ -335,6 +335,8 @@
D0B418BA1D7E05BB004562A4 /* NetworkLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = D03B0E421D631E6600955575 /* NetworkLogging.m */; };
D0B418BB1D7E05BE004562A4 /* NetworkLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E411D631E6600955575 /* NetworkLogging.h */; };
D0B418BC1D7E05D0004562A4 /* TelegramCoreIncludes.h in Headers */ = {isa = PBXBuildFile; fileRef = D03B0E5B1D63240700955575 /* TelegramCoreIncludes.h */; };
D0B477731EBF54A20033A0AB /* RecentCalls.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B477721EBF54A20033A0AB /* RecentCalls.swift */; };
D0B477741EBF54A20033A0AB /* RecentCalls.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B477721EBF54A20033A0AB /* RecentCalls.swift */; };
D0B843811DA6EDAE005F29E1 /* CachedUserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */; };
D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */; };
D0B843851DA6EDC4005F29E1 /* CachedChannelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */; };
@ -418,8 +420,6 @@
D0C48F3A1E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */; };
D0C48F3C1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */; };
D0C48F3D1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */; };
D0C50E311E93A85E00F62E39 /* CallSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E301E93A85D00F62E39 /* CallSession.swift */; };
D0C50E321E93A85E00F62E39 /* CallSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E301E93A85D00F62E39 /* CallSession.swift */; };
D0C50E341E93A86600F62E39 /* CallSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E331E93A86600F62E39 /* CallSessionManager.swift */; };
D0C50E351E93A86600F62E39 /* CallSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C50E331E93A86600F62E39 /* CallSessionManager.swift */; };
D0CAF2EA1D75EC600011F558 /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CAF2E91D75EC600011F558 /* MtProtoKitDynamic.framework */; };
@ -704,6 +704,7 @@
D0B418701D7E0409004562A4 /* PostboxMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PostboxMac.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug/PostboxMac.framework"; sourceTree = "<group>"; };
D0B418711D7E0409004562A4 /* SwiftSignalKitMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftSignalKitMac.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug/SwiftSignalKitMac.framework"; sourceTree = "<group>"; };
D0B4187E1D7E054E004562A4 /* MtProtoKitMac.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MtProtoKitMac.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug/MtProtoKitMac.framework"; sourceTree = "<group>"; };
D0B477721EBF54A20033A0AB /* RecentCalls.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecentCalls.swift; sourceTree = "<group>"; };
D0B843801DA6EDAE005F29E1 /* CachedUserData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedUserData.swift; sourceTree = "<group>"; };
D0B843821DA6EDB8005F29E1 /* CachedGroupData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedGroupData.swift; sourceTree = "<group>"; };
D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedChannelData.swift; sourceTree = "<group>"; };
@ -751,7 +752,6 @@
D0BEAF5F1E54ACF900BD963D /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = "<group>"; };
D0C48F381E8138DF0075317D /* ArchivedStickerPacksInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArchivedStickerPacksInfo.swift; sourceTree = "<group>"; };
D0C48F3B1E8142EF0075317D /* LoadedPeerFromMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadedPeerFromMessage.swift; sourceTree = "<group>"; };
D0C50E301E93A85D00F62E39 /* CallSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallSession.swift; sourceTree = "<group>"; };
D0C50E331E93A86600F62E39 /* CallSessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallSessionManager.swift; sourceTree = "<group>"; };
D0CAF2E91D75EC600011F558 /* MtProtoKitDynamic.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MtProtoKitDynamic.framework; path = "../../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-diblohvjozhgaifjcniwdlixlilx/Build/Products/Debug-iphonesimulator/MtProtoKitDynamic.framework"; sourceTree = "<group>"; };
D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerPackInteractiveOperations.swift; sourceTree = "<group>"; };
@ -1275,8 +1275,8 @@
D0C50E2F1E93A83B00F62E39 /* Calls */ = {
isa = PBXGroup;
children = (
D0C50E301E93A85D00F62E39 /* CallSession.swift */,
D0C50E331E93A86600F62E39 /* CallSessionManager.swift */,
D0B477721EBF54A20033A0AB /* RecentCalls.swift */,
);
name = Calls;
sourceTree = "<group>";
@ -1616,6 +1616,7 @@
D03B0D0A1D62255C00955575 /* Holes.swift in Sources */,
D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */,
D03B0D5E1D631A6900955575 /* Network.swift in Sources */,
D0B477731EBF54A20033A0AB /* RecentCalls.swift in Sources */,
D0B8438E1DA7D296005F29E1 /* CachedGroupParticipants.swift in Sources */,
D0B843BD1DA7FF30005F29E1 /* NBMetadataHelper.m in Sources */,
D03B0CF51D62250800955575 /* TelegramMediaContact.swift in Sources */,
@ -1756,7 +1757,6 @@
D0E305A71E5B5CBE00D7A3A2 /* PeerAdmins.swift in Sources */,
D0B843C51DA7FF30005F29E1 /* NBPhoneNumber.m in Sources */,
D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */,
D0C50E311E93A85E00F62E39 /* CallSession.swift in Sources */,
D03B0D081D62255C00955575 /* ChannelState.swift in Sources */,
C251D7431E65E50500283EDE /* StickerSetInstallation.swift in Sources */,
);
@ -1806,8 +1806,8 @@
D0E23DE01E8082A400B9B6D2 /* ArchivedStickerPacks.swift in Sources */,
D050F2521E4A59C200988324 /* JoinLink.swift in Sources */,
D0F7B1E91E045C87007EB8A5 /* PeerCommands.swift in Sources */,
D0B477741EBF54A20033A0AB /* RecentCalls.swift in Sources */,
D00D97C81E32901700E5C2B6 /* PeerInputActivity.swift in Sources */,
D0C50E321E93A85E00F62E39 /* CallSession.swift in Sources */,
D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */,
C22EE61C1E67418000334C38 /* ToggleChannelSignatures.swift in Sources */,
D0B418AC1D7E0597004562A4 /* Network.swift in Sources */,

View File

@ -1,9 +0,0 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
#else
import Postbox
import SwiftSignalKit
#endif

View File

@ -9,6 +9,18 @@ import Foundation
import SwiftSignalKit
#endif
public enum CallSessionError {
case generic
case privacyRestricted
case notSupportedByPeer
case serverProvided(String)
}
public enum CallSessionTerminationReason {
case ended
case error(CallSessionError)
}
enum CallSessionInternalState {
case ringing(id: Int64, accessHash: Int64, gAHash: Data, b: Data)
case accepting(id: Int64, accessHash: Int64, gAHash: Data, b: Data, disposable: Disposable)
@ -18,7 +30,7 @@ enum CallSessionInternalState {
case confirming(id: Int64, accessHash: Int64, key: Data, keyId: Int64, keyVisualHash: Data, disposable: Disposable)
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet)
case dropping(Disposable)
case terminated
case terminated(CallSessionTerminationReason)
}
public typealias CallSessionInternalId = Int64
@ -35,7 +47,7 @@ public enum CallSessionState {
case requesting(ringing: Bool)
case active(key: Data, keyVisualHash: Data, connections: CallSessionConnectionSet)
case dropping
case terminated
case terminated(CallSessionTerminationReason)
fileprivate init(_ context: CallSessionContext) {
switch context.state {
@ -51,8 +63,8 @@ public enum CallSessionState {
self = .active(key: key, keyVisualHash: keyVisualHash, connections: connections)
case .dropping:
self = .dropping
case .terminated:
self = .terminated
case let .terminated(reason):
self = .terminated(reason)
}
}
}
@ -250,7 +262,7 @@ private final class CallSessionManagerContext {
dropData = (id, accessHash, .abort)
case let .requesting(_, disposable):
disposable.dispose()
context.state = .terminated
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
if context.isEmpty {
self.contexts.removeValue(forKey: internalId)
@ -262,7 +274,7 @@ private final class CallSessionManagerContext {
context.state = .dropping((dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, reason: reason) |> deliverOn(self.queue)).start(completed: { [weak self] in
if let strongSelf = self {
if let context = strongSelf.contexts[internalId] {
context.state = .terminated
context.state = .terminated(.ended)
strongSelf.contextUpdated(internalId: internalId)
if context.isEmpty {
strongSelf.contexts.removeValue(forKey: internalId)
@ -324,94 +336,103 @@ private final class CallSessionManagerContext {
switch call {
case .phoneCallEmpty:
break
case let .phoneCallAccepted(id, _, date, _, _, gB, `protocol`):
case let .phoneCallAccepted(id, _, _, _, _, gB, _):
if let internalId = self.contextIdByStableId[id] {
let context = self.contexts[internalId]!
switch context.state {
case let .requested(_, accessHash, a, gA, config, _):
var key = MTExp(gB.makeData(), a, config.p.makeData())!
if key.count > 256 {
key.count = 256
} else {
while key.count < 256 {
key.insert(0, at: 0)
}
}
let keyHash = MTSha1(key)!
var keyId: Int64 = 0
keyHash.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8)
}
let keyVisualHash = MTSha256(key + gA)!
context.state = .confirming(id: id, accessHash: accessHash, key: key, keyId: keyId, keyVisualHash: keyVisualHash, disposable: (confirmCallSession(network: self.network, stableId: id, accessHash: accessHash, gA: gA, keyFingerprint: keyId) |> deliverOnMainQueue).start(next: { [weak self] updatedCall in
if let strongSelf = self, let context = strongSelf.contexts[internalId], case .confirming = context.state {
if let updatedCall = updatedCall {
strongSelf.updateSession(updatedCall)
} else {
strongSelf.drop(internalId: internalId)
if let context = self.contexts[internalId] {
switch context.state {
case let .requested(_, accessHash, a, gA, config, _):
var key = MTExp(gB.makeData(), a, config.p.makeData())!
if key.count > 256 {
key.count = 256
} else {
while key.count < 256 {
key.insert(0, at: 0)
}
}
}))
self.contextUpdated(internalId: internalId)
default:
self.drop(internalId: internalId)
let keyHash = MTSha1(key)!
var keyId: Int64 = 0
keyHash.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
memcpy(&keyId, bytes.advanced(by: keyHash.count - 8), 8)
}
let keyVisualHash = MTSha256(key + gA)!
context.state = .confirming(id: id, accessHash: accessHash, key: key, keyId: keyId, keyVisualHash: keyVisualHash, disposable: (confirmCallSession(network: self.network, stableId: id, accessHash: accessHash, gA: gA, keyFingerprint: keyId) |> deliverOnMainQueue).start(next: { [weak self] updatedCall in
if let strongSelf = self, let context = strongSelf.contexts[internalId], case .confirming = context.state {
if let updatedCall = updatedCall {
strongSelf.updateSession(updatedCall)
} else {
strongSelf.drop(internalId: internalId)
}
}
}))
self.contextUpdated(internalId: internalId)
default:
self.drop(internalId: internalId)
}
} else {
assertionFailure()
}
}
case let .phoneCallDiscarded(_, id, reason, duration):
if let internalId = self.contextIdByStableId[id] {
let context = self.contexts[internalId]!
switch context.state {
case let .accepting(_, _, _, _, disposable):
disposable.dispose()
context.state = .terminated
self.contextUpdated(internalId: internalId)
case .active:
context.state = .terminated
self.contextUpdated(internalId: internalId)
case .awaitingConfirmation, .requested:
context.state = .terminated
self.contextUpdated(internalId: internalId)
case let .confirming(_, _, _, _, _, disposable):
disposable.dispose()
context.state = .terminated
self.contextUpdated(internalId: internalId)
case let .requesting(_, disposable):
disposable.dispose()
context.state = .terminated
self.contextUpdated(internalId: internalId)
case .ringing:
context.state = .terminated
self.ringingStatesUpdated()
self.contextUpdated(internalId: internalId)
case .dropping, .terminated:
break
if let context = self.contexts[internalId] {
switch context.state {
case let .accepting(_, _, _, _, disposable):
disposable.dispose()
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
case .active:
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
case .awaitingConfirmation, .requested:
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
case let .confirming(_, _, _, _, _, disposable):
disposable.dispose()
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
case let .requesting(_, disposable):
disposable.dispose()
context.state = .terminated(.ended)
self.contextUpdated(internalId: internalId)
case .ringing:
context.state = .terminated(.ended)
self.ringingStatesUpdated()
self.contextUpdated(internalId: internalId)
case .dropping, .terminated:
break
}
} else {
assertionFailure()
}
}
case let .phoneCall(id, _, _, _, _, gAOrB, keyFingerprint, _, connection, alternativeConnections, startDate):
if let internalId = self.contextIdByStableId[id] {
let context = self.contexts[internalId]!
switch context.state {
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested:
break
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) {
if keyFingerprint == calculatedKeyId {
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connection, alternative: alternativeConnections))
self.contextUpdated(internalId: internalId)
if let context = self.contexts[internalId] {
switch context.state {
case .accepting, .active, .dropping, .requesting, .ringing, .terminated, .requested:
break
case let .awaitingConfirmation(_, accessHash, gAHash, b, config):
if let (key, calculatedKeyId, keyVisualHash) = self.makeSessionEncryptionKey(config: config, gAHash: gAHash, b: b, gA: gAOrB.makeData()) {
if keyFingerprint == calculatedKeyId {
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connection, alternative: alternativeConnections))
self.contextUpdated(internalId: internalId)
} else {
self.drop(internalId: internalId)
}
} else {
self.drop(internalId: internalId)
}
} else {
self.drop(internalId: internalId)
}
case let .confirming(id, accessHash, key, keyId, keyVisualHash, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connection, alternative: alternativeConnections))
self.contextUpdated(internalId: internalId)
case let .confirming(id, accessHash, key, keyId, keyVisualHash, _):
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connection, alternative: alternativeConnections))
self.contextUpdated(internalId: internalId)
}
} else {
assertionFailure()
}
}
case let .phoneCallRequested(id, accessHash, date, adminId, _, gAHash, _):
@ -420,15 +441,18 @@ private final class CallSessionManagerContext {
}
case let .phoneCallWaiting(_, id, _, _, _, _, _, receiveDate):
if let internalId = self.contextIdByStableId[id] {
let context = self.contexts[internalId]!
switch context.state {
case let .requested(id, accessHash, a, gA, config, remoteConfirmationTimestamp):
if let receiveDate = receiveDate, remoteConfirmationTimestamp == nil {
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: receiveDate)
self.contextUpdated(internalId: internalId)
}
default:
break
if let context = self.contexts[internalId] {
switch context.state {
case let .requested(id, accessHash, a, gA, config, remoteConfirmationTimestamp):
if let receiveDate = receiveDate, remoteConfirmationTimestamp == nil {
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: receiveDate)
self.contextUpdated(internalId: internalId)
}
default:
break
}
} else {
assertionFailure()
}
}
}
@ -473,12 +497,12 @@ private final class CallSessionManagerContext {
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
if case .requesting = context.state {
switch result {
case let .success(id, accessHash, config, gA):
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: nil)
case let .success(id, accessHash, config, gA, remoteConfirmationTimestamp):
context.state = .requested(id: id, accessHash: accessHash, a: a, gA: gA, config: config, remoteConfirmationTimestamp: remoteConfirmationTimestamp)
strongSelf.contextIdByStableId[id] = internalId
strongSelf.contextUpdated(internalId: internalId)
case .failed:
context.state = .terminated
case let .failed(error):
context.state = .terminated(.error(error))
strongSelf.contextUpdated(internalId: internalId)
if context.isEmpty {
strongSelf.contexts.removeValue(forKey: internalId)
@ -651,8 +675,8 @@ private func acceptCallSession(postbox: Postbox, network: Network, stableId: Cal
}
private enum RequestCallSessionResult {
case success(id: CallSessionStableId, accessHash: Int64, config: SecretChatEncryptionConfig, gA: Data)
case failed
case success(id: CallSessionStableId, accessHash: Int64, config: SecretChatEncryptionConfig, gA: Data, remoteConfirmationTimestamp: Int32?)
case failed(CallSessionError)
}
private func requestCallSession(postbox: Postbox, network: Network, peerId: PeerId, a: Data) -> Signal<RequestCallSessionResult, NoError> {
@ -669,29 +693,35 @@ private func requestCallSession(postbox: Postbox, network: Network, peerId: Peer
let gAHash = MTSha256(ga)!
return network.request(Api.functions.phone.requestCall(userId: inputUser, randomId: Int32(bitPattern: arc4random()), gAHash: Buffer(data: gAHash), protocol: .phoneCallProtocol(flags: (1 << 0) | (1 << 1), minLayer: 65, maxLayer: 66)))
|> map { Optional($0) }
|> `catch` { _ -> Signal<Api.phone.PhoneCall?, NoError> in
return .single(nil)
}
|> map { result -> RequestCallSessionResult in
if let result = result {
switch result {
case let .phoneCall(phoneCall, _):
switch phoneCall {
case let .phoneCallRequested(id, accessHash, _, _, _, _, _):
return .success(id: id, accessHash: accessHash, config: config, gA: ga)
case let .phoneCallWaiting(_, id, accessHash, date, _, _, _, receiveDate):
return .success(id: id, accessHash: accessHash, config: config, gA: ga)
default:
return .failed
}
}
} else {
return .failed
switch result {
case let .phoneCall(phoneCall, _):
switch phoneCall {
case let .phoneCallRequested(id, accessHash, _, _, _, _, _):
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: nil)
case let .phoneCallWaiting(_, id, accessHash, _, _, _, _, receiveDate):
return .success(id: id, accessHash: accessHash, config: config, gA: ga, remoteConfirmationTimestamp: receiveDate)
default:
return .failed(.generic)
}
}
}
|> `catch` { error -> Signal<RequestCallSessionResult, NoError> in
switch error.errorDescription {
case "PARTICIPANT_VERSION_OUTDATED":
return .single(.failed(.notSupportedByPeer))
case "USER_PRIVACY_RESTRICTED":
return .single(.failed(.privacyRestricted))
default:
if error.errorCode == 406 {
return .single(.failed(.serverProvided(error.errorDescription)))
} else {
return .single(.failed(.generic))
}
}
}
} else {
return .single(.failed)
return .single(.failed(.generic))
}
} |> switchToLatest
}

View File

@ -0,0 +1,66 @@
import Foundation
#if os(macOS)
import PostboxMac
import MtProtoKitMac
import SwiftSignalKitMac
#else
import Postbox
import MtProtoKitDynamic
import SwiftSignalKit
#endif
public func recentCalls(account: Account, limit: Int) -> Signal<[Message], NoError> {
let filter: Api.MessagesFilter = .inputMessagesFilterPhoneCalls(flags: 0)
let searchResult = account.network.request(Api.functions.messages.search(flags: 0, peer: .inputPeerEmpty, q: "", filter: filter, minDate: 0, maxDate: Int32.max, offset: 0, maxId: Int32.max, limit: Int32(limit)))
|> retryRequest
let processedSearchResult = searchResult
|> mapToSignal { result -> Signal<[Message], NoError> in
let messages: [Api.Message]
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
case let .messages(apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
case let.messagesSlice(_, apiMessages, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers
}
return account.postbox.modify { modifier -> [Message] in
var peers: [PeerId: Peer] = [:]
for user in users {
if let user = TelegramUser.merge(modifier.getPeer(user.peerId) as? TelegramUser, rhs: user) {
peers[user.id] = user
}
}
for chat in chats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers[groupOrChannel.id] = groupOrChannel
}
}
var renderedMessages: [Message] = []
for message in messages {
if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) {
renderedMessages.append(renderedMessage)
}
}
return renderedMessages
}
}
return processedSearchResult
}

View File

@ -9,8 +9,7 @@ import Foundation
import MtProtoKitDynamic
#endif
public func searchMessages(account: Account, peerId: PeerId?, query: String, tagMask:MessageTags? = nil) -> Signal<[Message], NoError> {
public func searchMessages(account: Account, peerId: PeerId?, query: String, tagMask: MessageTags? = nil) -> Signal<[Message], NoError> {
let searchResult: Signal<Api.messages.Messages, NoError>
let filter:Api.MessagesFilter
@ -105,7 +104,6 @@ public func downloadMessage(account: Account, message: MessageId) -> Signal<Mess
return signal
|> retryRequest
|> mapToSignal { result -> Signal<Message?, NoError> in
NSLog("TGNT download message3 \(result)")
let messages: [Api.Message]
let chats: [Api.Chat]
let users: [Api.User]