no message

This commit is contained in:
Peter 2017-04-08 17:23:13 +03:00
parent 5840a60096
commit f747bb4716
23 changed files with 2404 additions and 252 deletions

View File

@ -176,6 +176,8 @@
D041E3F61E535464008C24B4 /* AddPeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F41E535464008C24B4 /* AddPeerMember.swift */; };
D041E3F81E535A88008C24B4 /* RemovePeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */; };
D041E3F91E535A88008C24B4 /* RemovePeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */; };
D042C6831E8D9DF800C863B0 /* Unixtime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D042C6821E8D9DF800C863B0 /* Unixtime.swift */; };
D042C6841E8D9DF800C863B0 /* Unixtime.swift in Sources */ = {isa = PBXBuildFile; fileRef = D042C6821E8D9DF800C863B0 /* Unixtime.swift */; };
D0448C8E1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */; };
D0448C8F1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */; };
D0448C911E251F96005A61A7 /* SecretChatEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */; };
@ -404,6 +406,10 @@
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 */; };
D0D748021E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; };
D0D748031E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D748011E7AE98B00F4B1F6 /* StickerPackInteractiveOperations.swift */; };
@ -433,6 +439,8 @@
D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */; };
D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; };
D0E652201E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; };
D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; };
D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; };
D0F3A89F1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; };
D0F3A8A01E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; };
D0F3A8A21E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */; };
@ -604,6 +612,7 @@
D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutAccountAttribute.swift; sourceTree = "<group>"; };
D041E3F41E535464008C24B4 /* AddPeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPeerMember.swift; sourceTree = "<group>"; };
D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePeerMember.swift; sourceTree = "<group>"; };
D042C6821E8D9DF800C863B0 /* Unixtime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unixtime.swift; sourceTree = "<group>"; };
D0448C8D1E22993C005A61A7 /* ProcessSecretChatIncomingDecryptedOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProcessSecretChatIncomingDecryptedOperations.swift; sourceTree = "<group>"; };
D0448C901E251F96005A61A7 /* SecretChatEncryption.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatEncryption.swift; sourceTree = "<group>"; };
D0448C981E268F9A005A61A7 /* SecretApiLayer46.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretApiLayer46.swift; sourceTree = "<group>"; };
@ -720,6 +729,8 @@
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>"; };
D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestChatContextResults.swift; sourceTree = "<group>"; };
@ -737,6 +748,7 @@
D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingMessageWithChatContextResult.swift; sourceTree = "<group>"; };
D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingChatContextResultMessageAttribute.swift; sourceTree = "<group>"; };
D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateAccountPeerName.swift; sourceTree = "<group>"; };
D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedConfigurationUpdates.swift; sourceTree = "<group>"; };
D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeChatInputStateOperation.swift; sourceTree = "<group>"; };
D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeChatInputStateOperations.swift; sourceTree = "<group>"; };
D0F3A8A41E82C94C00B4C64C /* SynchronizeableChatInputState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeableChatInputState.swift; sourceTree = "<group>"; };
@ -893,6 +905,7 @@
D050F20F1E48AB0600988324 /* InteractivePhoneFormatter.swift */,
D03229F31E6B39700000AF9C /* ImportAccount.swift */,
D04CAA591E83310D0047E51F /* MD5.swift */,
D042C6821E8D9DF800C863B0 /* Unixtime.swift */,
);
name = Utils;
sourceTree = "<group>";
@ -1017,6 +1030,7 @@
D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */,
D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */,
D058E0D01E8AD65C00A442DE /* StandaloneSendMessage.swift */,
D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */,
);
name = State;
sourceTree = "<group>";
@ -1200,6 +1214,7 @@
D03B0D691D631A9200955575 /* Contacts */,
D03B0D6E1D631AA900955575 /* Messages */,
D0DF0C881D819C5F008AEB01 /* Peers */,
D0C50E2F1E93A83B00F62E39 /* Calls */,
D021E0E01DB5400200C6B04F /* Sticker Management */,
D05A32DF1E6F096B002760B4 /* Settings */,
D03B0E3A1D631E4400955575 /* Supporting Files */,
@ -1227,6 +1242,15 @@
path = TelegramCoreMac;
sourceTree = "<group>";
};
D0C50E2F1E93A83B00F62E39 /* Calls */ = {
isa = PBXGroup;
children = (
D0C50E301E93A85D00F62E39 /* CallSession.swift */,
D0C50E331E93A86600F62E39 /* CallSessionManager.swift */,
);
name = Calls;
sourceTree = "<group>";
};
D0DF0C881D819C5F008AEB01 /* Peers */ = {
isa = PBXGroup;
children = (
@ -1553,6 +1577,7 @@
D00C7CE01E3785710080C3D5 /* MarkMessageContentAsConsumedInteractively.swift in Sources */,
D0B843811DA6EDAE005F29E1 /* CachedUserData.swift in Sources */,
D049EAD51E43D98500A2CD3A /* RecentMediaItem.swift in Sources */,
D0C50E341E93A86600F62E39 /* CallSessionManager.swift in Sources */,
D00D34421E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */,
D03B0D0A1D62255C00955575 /* Holes.swift in Sources */,
D0B843CB1DA7FF30005F29E1 /* NBPhoneNumberUtil.m in Sources */,
@ -1574,6 +1599,7 @@
D0BC38791E40BAF20044D6FE /* SynchronizePinnedChatsOperation.swift in Sources */,
D050F2101E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */,
D0C48F3C1E8142EF0075317D /* LoadedPeerFromMessage.swift in Sources */,
D042C6831E8D9DF800C863B0 /* Unixtime.swift in Sources */,
D0BE383E1E7C5995000079AF /* MediaPool.swift in Sources */,
D03B0D671D631A8B00955575 /* AccountViewTracker.swift in Sources */,
D0B843BB1DA7FF30005F29E1 /* NBMetadataCoreTestMapper.m in Sources */,
@ -1613,6 +1639,7 @@
D0DC354E1DE368F7000195EB /* RequestChatContextResults.swift in Sources */,
D0BC38771E40BAAA0044D6FE /* ManagedSynchronizePinnedChatsOperations.swift in Sources */,
D0B843851DA6EDC4005F29E1 /* CachedChannelData.swift in Sources */,
D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */,
D0528E6A1E65DD2100E2FEF5 /* WebpagePreview.swift in Sources */,
D0BEAF5D1E54941B00BD963D /* Authorization.swift in Sources */,
D0B843831DA6EDB8005F29E1 /* CachedGroupData.swift in Sources */,
@ -1689,6 +1716,7 @@
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 */,
);
@ -1738,6 +1766,7 @@
D050F2521E4A59C200988324 /* JoinLink.swift in Sources */,
D0F7B1E91E045C87007EB8A5 /* PeerCommands.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 */,
@ -1789,6 +1818,7 @@
D00D34431E6EDD2E0057B307 /* ManagedSynchronizeConsumeMessageContentsOperations.swift in Sources */,
D049EAE91E44B67100A2CD3A /* RecentPeerItem.swift in Sources */,
D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */,
D0C50E351E93A86600F62E39 /* CallSessionManager.swift in Sources */,
D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */,
D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */,
D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */,
@ -1832,8 +1862,10 @@
D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */,
D05452081E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */,
D0561DE41E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */,
D042C6841E8D9DF800C863B0 /* Unixtime.swift in Sources */,
D0DC35521DE36908000195EB /* ChatContextResult.swift in Sources */,
D0F7AB301DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */,
D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */,
D073CE6D1DCBCF17007511FD /* InlineBotMessageAttribute.swift in Sources */,
D033FEB71E61F3F900644997 /* BlockedPeers.swift in Sources */,
D0448C9A1E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */,

View File

@ -230,57 +230,66 @@ private func accountRecordIdPathName(_ id: AccountRecordId) -> String {
return "account-\(UInt64(bitPattern: id.int64))"
}
public func accountWithId(apiId: Int32, id: AccountRecordId, supplementary: Bool, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<Either<UnauthorizedAccount, Account>, NoError> {
return Signal<(String, Postbox, Coding?), NoError> { subscriber in
let _ = declaredEncodables
let path = "\(appGroupPath)/\(accountRecordIdPathName(id))"
var initializeMessageNamespacesWithHoles: [(PeerId.Namespace, MessageId.Namespace)] = []
for peerNamespace in peerIdNamespacesWithInitialCloudMessageHoles {
initializeMessageNamespacesWithHoles.append((peerNamespace, Namespaces.Message.Cloud))
}
let seedConfiguration = SeedConfiguration(initializeChatListWithHoles: [ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: 1))], initializeMessageNamespacesWithHoles: initializeMessageNamespacesWithHoles, existingMessageTags: allMessageTags)
let postbox = Postbox(basePath: path + "/postbox", globalMessageIdsNamespace: Namespaces.Message.Cloud, seedConfiguration: seedConfiguration)
return (postbox.stateView() |> take(1) |> map { view -> (String, Postbox, Coding?) in
let accountState = view.state
return (path, postbox, accountState)
}).start(next: { args in
subscriber.putNext(args)
subscriber.putCompletion()
})
} |> mapToSignal { (basePath, postbox, accountState) -> Signal<Either<UnauthorizedAccount, Account>, NoError> in
let keychain = Keychain(get: { key in
return postbox.keychainEntryForKey(key)
}, set: { (key, data) in
postbox.setKeychainEntryForKey(key, value: data)
}, remove: { key in
postbox.removeKeychainEntryForKey(key)
})
if let accountState = accountState {
switch accountState {
case let unauthorizedState as UnauthorizedAccountState:
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: basePath), testingEnvironment: testingEnvironment)
|> map { network -> Either<UnauthorizedAccount, Account> in
.left(value: UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: basePath, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
public enum AccountResult {
case upgrading
case unauthorized(UnauthorizedAccount)
case authorized(Account)
}
public func accountWithId(apiId: Int32, id: AccountRecordId, supplementary: Bool, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods, shouldKeepAutoConnection: Bool = true) -> Signal<AccountResult, NoError> {
let _ = declaredEncodables
let path = "\(appGroupPath)/\(accountRecordIdPathName(id))"
var initializeMessageNamespacesWithHoles: [(PeerId.Namespace, MessageId.Namespace)] = []
for peerNamespace in peerIdNamespacesWithInitialCloudMessageHoles {
initializeMessageNamespacesWithHoles.append((peerNamespace, Namespaces.Message.Cloud))
}
let seedConfiguration = SeedConfiguration(initializeChatListWithHoles: [ChatListHole(index: MessageIndex(id: MessageId(peerId: PeerId(namespace: Namespaces.Peer.Empty, id: 0), namespace: Namespaces.Message.Cloud, id: 1), timestamp: 1))], initializeMessageNamespacesWithHoles: initializeMessageNamespacesWithHoles, existingMessageTags: allMessageTags)
let postbox = openPostbox(basePath: path + "/postbox", globalMessageIdsNamespace: Namespaces.Message.Cloud, seedConfiguration: seedConfiguration)
return postbox |> mapToSignal { result -> Signal<AccountResult, NoError> in
switch result {
case .upgrading:
return .single(.upgrading)
case let .postbox(postbox):
return postbox.stateView()
|> take(1)
|> mapToSignal { view -> Signal<AccountResult, NoError> in
let accountState = view.state
let keychain = Keychain(get: { key in
return postbox.keychainEntryForKey(key)
}, set: { (key, data) in
postbox.setKeychainEntryForKey(key, value: data)
}, remove: { key in
postbox.removeKeychainEntryForKey(key)
})
if let accountState = accountState {
switch accountState {
case let unauthorizedState as UnauthorizedAccountState:
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(unauthorizedState.masterDatacenterId), keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: path), testingEnvironment: testingEnvironment)
|> map { network -> AccountResult in
return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
}
case let authorizedState as AuthorizedAccountState:
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: path), testingEnvironment: testingEnvironment)
|> map { network -> AccountResult in
return .authorized(Account(id: id, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods))
}
case _:
assertionFailure("Unexpected accountState \(accountState)")
}
}
case let authorizedState as AuthorizedAccountState:
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: Int(authorizedState.masterDatacenterId), keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: basePath), testingEnvironment: testingEnvironment)
|> map { network -> Either<UnauthorizedAccount, Account> in
return .right(value: Account(id: id, basePath: basePath, testingEnvironment: testingEnvironment, postbox: postbox, network: network, peerId: authorizedState.peerId, auxiliaryMethods: auxiliaryMethods))
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: 2, keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: path), testingEnvironment: testingEnvironment)
|> map { network -> AccountResult in
return .unauthorized(UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: path, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
}
case _:
assertionFailure("Unexpected accountState \(accountState)")
}
}
return initializedNetwork(apiId: apiId, supplementary: supplementary, datacenterId: 2, keychain: keychain, networkUsageInfoPath: accountNetworkUsageInfoPath(basePath: basePath), testingEnvironment: testingEnvironment)
|> map { network -> Either<UnauthorizedAccount, Account> in
return .left(value: UnauthorizedAccount(apiId: apiId, id: id, appGroupPath: appGroupPath, basePath: basePath, testingEnvironment: testingEnvironment, postbox: postbox, network: network, shouldKeepAutoConnection: shouldKeepAutoConnection))
}
}
}
}
@ -566,7 +575,7 @@ public class Account {
self.managedOperationsDisposable.add(managedLocalTypingActivities(activities: self.localInputActivityManager.allActivities(), postbox: self.postbox, network: self.network).start())
self.managedOperationsDisposable.add(managedSynchronizeConsumeMessageContentOperations(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start())
self.managedOperationsDisposable.add(managedSynchronizeChatInputStateOperations(postbox: self.postbox, network: self.network).start())
self.managedOperationsDisposable.add(managedConfigurationUpdates(postbox: self.postbox, network: self.network).start())
let updatedPresence = self.shouldKeepOnlinePresence.get()
|> distinctUntilChanged

View File

@ -199,7 +199,7 @@ struct AccountMutableState {
var presences: [PeerId: PeerPresence] = [:]
for user in users {
switch user {
case let .user(_, id, _, _, _, _, _, _, status, _, _, _):
case let .user(_, id, _, _, _, _, _, _, status, _, _, _, _):
if let status = status {
presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] = TelegramUserPresence(apiStatus: status)
}

View File

@ -14,24 +14,26 @@ private enum AccountKind {
case unauthorized
}
public func currentAccount(apiId: Int32, supplementary: Bool, manager: AccountManager, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal<Either<UnauthorizedAccount, Account>?, NoError> {
public func currentAccount(apiId: Int32, supplementary: Bool, manager: AccountManager, appGroupPath: String, testingEnvironment: Bool, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal<AccountResult?, NoError> {
return manager.allocatedCurrentAccountId()
|> distinctUntilChanged(isEqual: { lhs, rhs in
return lhs == rhs
})
|> mapToSignal { id -> Signal<Either<UnauthorizedAccount, Account>?, NoError> in
|> mapToSignal { id -> Signal<AccountResult?, NoError> in
if let id = id {
let reload = ValuePromise<Bool>(true, ignoreRepeated: false)
return reload.get() |> mapToSignal { _ -> Signal<Either<UnauthorizedAccount, Account>?, NoError> in
return reload.get() |> mapToSignal { _ -> Signal<AccountResult?, NoError> in
return accountWithId(apiId: apiId, id: id, supplementary: supplementary, appGroupPath: appGroupPath, testingEnvironment: testingEnvironment, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Either<UnauthorizedAccount, Account>?, NoError> in
|> mapToSignal { accountResult -> Signal<AccountResult?, NoError> in
let postbox: Postbox
let initialKind: AccountKind
switch account {
case let .left(value: account):
switch accountResult {
case .upgrading:
return .complete()
case let .unauthorized(account):
postbox = account.postbox
initialKind = .unauthorized
case let.right(value: account):
case let .authorized(account):
postbox = account.postbox
initialKind = .authorized
}
@ -52,7 +54,7 @@ public func currentAccount(apiId: Int32, supplementary: Bool, manager: AccountMa
|> distinctUntilChanged
return Signal { subscriber in
subscriber.putNext(account)
subscriber.putNext(accountResult)
return updatedKind.start(next: { value in
if value {
@ -154,9 +156,11 @@ private func cleanupAccount(apiId: Int32, accountManager: AccountManager, id: Ac
return accountWithId(apiId: apiId, id: id, supplementary: true, appGroupPath: appGroupPath, testingEnvironment: false, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Void, NoError> in
switch account {
case .left:
case .upgrading:
return .complete()
case let .right(account):
case .unauthorized:
return .complete()
case let .authorized(account):
account.shouldBeServiceTaskMaster.set(.single(.always))
return account.network.request(Api.functions.auth.logOut())
|> map { Optional($0) }

View File

@ -6,9 +6,9 @@ import Foundation
#endif
public struct AutomaticDownloadSettings {
public let downloadPhoto: Bool
public let downloadVideo: Bool
public let downloadAudio: Bool
public let downloadPhotos: Bool
public let downloadVoiceMessages: Bool
public let downloadGifs: Bool
}
public struct AccountSettings {
@ -17,7 +17,7 @@ public struct AccountSettings {
}
func defaultAccountSettings() -> AccountSettings {
return AccountSettings(oneToOneChatsAutomaticDownloadSettings: AutomaticDownloadSettings(downloadPhoto: true, downloadVideo: false, downloadAudio: true), groupChatsAutomaticDownloadSettings: AutomaticDownloadSettings(downloadPhoto: true, downloadVideo: false, downloadAudio: true))
return AccountSettings(oneToOneChatsAutomaticDownloadSettings: AutomaticDownloadSettings(downloadPhotos: true, downloadVoiceMessages: true, downloadGifs: true), groupChatsAutomaticDownloadSettings: AutomaticDownloadSettings(downloadPhotos: true, downloadVoiceMessages: true, downloadGifs: true))
}
public extension AccountSettings {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
enum CallSessionState {
case requested(a: MemoryBuffer, config: SecretChatEncryptionConfig)
case accepting(gAHash: MemoryBuffer, b: MemoryBuffer, config: SecretChatEncryptionConfig)
case confirming(a: MemoryBuffer, gB: MemoryBuffer, config: SecretChatEncryptionConfig)
case active
}

View File

@ -0,0 +1,80 @@
import Foundation
#if os(macOS)
import PostboxMac
import MtProtoKitMac
import SwiftSignalKitMac
#else
import Postbox
import MtProtoKitDynamic
import SwiftSignalKit
#endif
private struct CallSessionId: Hashable {
let id: Int64
init(_ id: Int64) {
self.id = id
}
var hashValue: Int {
return self.id.hashValue
}
static func ==(lhs: CallSessionId, rhs: CallSessionId) -> Bool {
return lhs.id == rhs.id
}
}
private final class CallSessionContext {
let peerId: PeerId
var state: CallSessionState
init(peerId: PeerId, state: CallSessionState) {
self.peerId = peerId
self.state = state
}
}
private final class CallSessionManagerContext {
private let queue: Queue
private var contexts: [CallSessionId: CallSessionContext] = [:]
init(queue: Queue) {
self.queue = queue
}
deinit {
assert(self.queue.isCurrent())
}
}
final class CallSessionManager {
private let queue = Queue()
private var contextRef: Unmanaged<CallSessionManagerContext>?
init() {
self.queue.async {
let context = CallSessionManagerContext(queue: self.queue)
self.contextRef = Unmanaged.passRetained(context)
}
}
deinit {
let contextRef = self.contextRef
self.queue.async {
contextRef?.release()
}
}
private func withContext(_ f: @escaping (CallSessionManagerContext) -> Void) {
self.queue.async {
if let contextRef = self.contextRef {
let context = contextRef.takeUnretainedValue()
f(context)
}
}
}
}

View File

@ -9,6 +9,19 @@ import Foundation
import SwiftSignalKit
#endif
private func roundUp(_ value: Int, to multiple: Int) -> Int {
if multiple == 0 {
return value
}
let remainder = value % multiple
if remainder == 0 {
return value
}
return value + multiple - remainder
}
class Download: NSObject, MTRequestMessageServiceDelegate {
let datacenterId: Int
let context: MTContext
@ -84,7 +97,12 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
return Signal<Data, MTRpcError> { subscriber in
let request = MTRequest()
let data = Api.functions.upload.getFile(location: location, offset: Int32(offset), limit: Int32(length))
var updatedLength = roundUp(length, to: 4096)
while updatedLength % 4096 != 0 || 1048576 % updatedLength != 0 {
updatedLength += 1
}
let data = Api.functions.upload.getFile(location: location, offset: Int32(offset), limit: Int32(updatedLength))
request.setPayload(data.1.makeData() as Data!, metadata: WrappedRequestMetadata(metadata: data.0, tag: nil), responseParser: { response in
if let result = data.2(Buffer(data: response)) {
@ -103,6 +121,8 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
switch result {
case let .file(_, _, bytes):
subscriber.putNext(bytes.makeData())
case let .fileCdnRedirect(dcId, fileToken, encryptionKey, encryptionIv):
break
}
subscriber.putCompletion()
}

View File

@ -0,0 +1,38 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let poll = Signal<Void, NoError> { subscriber in
return network.request(Api.functions.help.getConfig()).start(next: { result in
switch result {
case let .config(_, _, _, _, _, dcOptions, chatSizeMax, megagroupSizeMax, forwardedCountMax, onlineUpdatePeriodMs, offlineBlurTimeoutMs, offlineIdleTimeoutMs, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, tmpSessions, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, disabledFeatures):
var addressList: [Int: [MTDatacenterAddress]] = [:]
for option in dcOptions {
switch option {
case let .dcOption(flags, id, ipAddress, port):
let preferForMedia = (flags & (1 << 1)) != 0
if addressList[Int(id)] == nil {
addressList[Int(id)] = []
}
addressList[Int(id)]!.append(MTDatacenterAddress(ip: ipAddress, port: UInt16(port), preferForMedia: preferForMedia, restrictToTcp: false))
}
}
network.context.performBatchUpdates {
for (id, list) in addressList {
network.context.updateAddressSetForDatacenter(withId: id, addressSet: MTDatacenterAddressSet(addressList: list))
}
}
}
})
}
return (poll |> then(.complete() |> delay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
}

View File

@ -115,7 +115,7 @@ func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaF
case .HasLinkedStickers:
attributes.append(.documentAttributeHasStickers)
case let .Video(duration, size):
attributes.append(.documentAttributeVideo(duration: Int32(duration), w: Int32(size.width), h: Int32(size.height)))
attributes.append(.documentAttributeVideo(flags: 0, duration: Int32(duration), w: Int32(size.width), h: Int32(size.height)))
case let .Audio(isVoice, duration, title, performer, waveform):
var flags: Int32 = 0
if isVoice {

View File

@ -29,7 +29,7 @@ public struct RecentMediaItemId {
}
}
public final class RecentMediaItem: OrderedItemListEntryContents {
public final class RecentMediaItem: OrderedItemListEntryContents, Equatable {
public let media: Media
init(_ media: Media) {
@ -43,4 +43,8 @@ public final class RecentMediaItem: OrderedItemListEntryContents {
public func encode(_ encoder: Encoder) {
encoder.encodeObject(self.media, forKey: "m")
}
public static func ==(lhs: RecentMediaItem, rhs: RecentMediaItem) -> Bool {
return lhs.media.isEqual(rhs.media)
}
}

View File

@ -13,6 +13,7 @@ public enum ReplyMarkupButtonAction: Coding, Equatable {
case requestMap
case switchInline(samePeer: Bool, query: String)
case openWebApp
case payment
public init(decoder: Decoder) {
switch decoder.decodeInt32ForKey("v") as Int32 {
@ -30,6 +31,8 @@ public enum ReplyMarkupButtonAction: Coding, Equatable {
self = .switchInline(samePeer: decoder.decodeInt32ForKey("s") != 0, query: decoder.decodeStringForKey("q"))
case 6:
self = .openWebApp
case 7:
self = .payment
default:
self = .text
}
@ -55,6 +58,8 @@ public enum ReplyMarkupButtonAction: Coding, Equatable {
encoder.encodeString(query, forKey: "q")
case .openWebApp:
encoder.encodeInt32(6, forKey: "v")
case .payment:
encoder.encodeInt32(7, forKey: "v")
}
}
@ -102,6 +107,12 @@ public enum ReplyMarkupButtonAction: Coding, Equatable {
} else {
return false
}
case .payment:
if case .payment = rhs {
return true
} else {
return false
}
}
}
}
@ -212,6 +223,8 @@ extension ReplyMarkupButton {
self.init(title: text, action: .url(url))
case let .keyboardButtonGame(text):
self.init(title: text, action: .openWebApp)
case let .keyboardButtonBuy(text):
self.init(title: text, action: .payment)
}
}
}

View File

@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 62
return 66
}
public func parseMessage(_ data: Data!) -> Any! {
@ -57,7 +57,7 @@ public class Serialization: NSObject, MTSerialization {
if let config = parse(Buffer(data: response)) {
switch config {
//config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int tmp_sessions:flags.0?int phonecalls_enabled:flags.1?true disabled_features:Vector<DisabledFeature> = Config;
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
var addressList = [MTDatacenterAddress]()
for option in dcOptions {
switch option {

View File

@ -22,10 +22,10 @@ private func hashForIdsReverse(_ ids: [Int64]) -> Int32 {
}
func manageStickerPacks(network: Network, postbox: Postbox) -> Signal<Void, NoError> {
return postbox.modify { modifier -> Void in
return (postbox.modify { modifier -> Void in
addSynchronizeInstalledStickerPacksOperation(modifier: modifier, namespace: .stickers)
addSynchronizeInstalledStickerPacksOperation(modifier: modifier, namespace: .masks)
} |> then(.complete() |> delay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue())) |> restart
} |> then(.complete() |> delay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart
}
func updatedFeaturedStickerPacks(network: Network, postbox: Postbox) -> Signal<Void, NoError> {

View File

@ -161,6 +161,10 @@ extension Api.Message {
result.append(PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId))
case let .messageActionPhoneCall(flags, callId, reason, duration):
break
case let .messageActionPaymentSent(currency, totalAmount):
break
case .messageActionPaymentSentMe:
break
}
return result
@ -236,6 +240,8 @@ func textAndMediaFromApiMedia(_ media: Api.MessageMedia?) -> (String?, Media?) {
break
case let .messageMediaGame(game):
return (nil, TelegramMediaGame(apiGame: game))
case let .messageMediaInvoice(flags, title, description, photo, receiptMsgId, currency, totalAmount, startParam):
break
}
}

View File

@ -63,6 +63,8 @@ func addSynchronizeInstalledStickerPacksOperation(modifier: Modifier, namespace:
updateLocalIndex = entry.tagLocalIndex
if let operation = entry.contents as? SynchronizeInstalledStickerPacksOperation {
previousSrickerPackIds = operation.previousPacks
} else {
assertionFailure()
}
return false
})
@ -81,6 +83,8 @@ func addSynchronizeMarkFeaturedStickerPacksAsSeenOperation(modifier: Modifier, i
updateLocalIndex = entry.tagLocalIndex
if let operation = entry.contents as? SynchronizeMarkFeaturedStickerPacksAsSeenOperation {
previousIds = Set(operation.ids)
} else {
assertionFailure()
}
return false
})

View File

@ -311,6 +311,10 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration))
case .messageActionEmpty:
return nil
case let .messageActionPaymentSent(currency, totalAmount):
return nil
case .messageActionPaymentSentMe:
return nil
}
}

View File

@ -312,7 +312,7 @@ public func telegramMediaFileAttributesFromApiAttributes(_ attributes: [Api.Docu
result.append(.ImageSize(size: CGSize(width: CGFloat(w), height: CGFloat(h))))
case .documentAttributeAnimated:
result.append(.Animated)
case let .documentAttributeVideo(duration, w, h):
case let .documentAttributeVideo(flags, duration, w, h):
result.append(.Video(duration: Int(duration), size: CGSize(width: CGFloat(w), height: CGFloat(h))))
case let .documentAttributeAudio(flags, duration, title, performer, waveform):
let isVoice = (flags & (1 << 10)) != 0

View File

@ -225,7 +225,7 @@ public final class TelegramUser: Peer {
public extension TelegramUser {
public convenience init(user: Api.User) {
switch user {
case let .user(flags, id, accessHash, firstName, lastName, username, phone, photo, _, _, _, botInlinePlaceholder):
case let .user(flags, id, accessHash, firstName, lastName, username, phone, photo, _, _, _, botInlinePlaceholder, _):
var telegramPhoto: [TelegramMediaImageRepresentation] = []
if let photo = photo {
switch photo {
@ -266,7 +266,7 @@ public extension TelegramUser {
public static func merge(_ lhs: TelegramUser?, rhs: Api.User) -> TelegramUser? {
switch rhs {
case let .user(flags, _, accessHash, _, _, username, _, photo, _, _, _, botInlinePlaceholder):
case let .user(flags, _, accessHash, _, _, username, _, photo, _, _, _, botInlinePlaceholder, _):
if let _ = accessHash {
return TelegramUser(user: rhs)
} else {

View File

@ -167,7 +167,7 @@ extension TelegramUserPresence {
convenience init?(apiUser: Api.User) {
switch apiUser {
case let .user(_, _, _, _, _, _, _, _, status, _, _, _):
case let .user(_, _, _, _, _, _, _, _, status, _, _, _, _):
if let status = status {
self.init(apiStatus: status)
} else {

128
TelegramCore/Unixtime.swift Normal file
View File

@ -0,0 +1,128 @@
import Foundation
public struct DateTime {
public let seconds: Int32 // 0 ... 59
public let minutes: Int32 // 0 ... 59
public let hours: Int32 // 0 ... 23
public let dayOfMonth: Int32 // 1 ... 31
public let month: Int32 // 0 ... 11
public let year: Int32 // since 1900
public let dayOfWeek: Int32 // 0 ... 6
public let dayOfYear: Int32 // 0 ... 365
}
private let daysSinceJan1st: [[UInt32]] =
[
[0,31,59,90,120,151,181,212,243,273,304,334,365], // 365 days, non-leap
[0,31,60,91,121,152,182,213,244,274,305,335,366] // 366 days, leap
]
public func secondsSinceEpochToDateTime(_ secondsSinceEpoch: Int64) -> DateTime {
var sec: UInt64
let quadricentennials: UInt32
var centennials: UInt32
var quadrennials: UInt32
var annuals: UInt32
let year: UInt32
let leap: UInt32
let yday: UInt32
let hour: UInt32
let min: UInt32
var month: UInt32
var mday: UInt32
let wday: UInt32
/*
400 years:
1st hundred, starting immediately after a leap year that's a multiple of 400:
n n n l \
n n n l } 24 times
... /
n n n l /
n n n n
2nd hundred:
n n n l \
n n n l } 24 times
... /
n n n l /
n n n n
3rd hundred:
n n n l \
n n n l } 24 times
... /
n n n l /
n n n n
4th hundred:
n n n l \
n n n l } 24 times
... /
n n n l /
n n n L <- 97'th leap year every 400 years
*/
// Re-bias from 1970 to 1601:
// 1970 - 1601 = 369 = 3*100 + 17*4 + 1 years (incl. 89 leap days) =
// (3*100*(365+24/100) + 17*4*(365+1/4) + 1*365)*24*3600 seconds
sec = UInt64(secondsSinceEpoch) + (11644473600 as UInt64)
wday = (uint)((sec / 86400 + 1) % 7); // day of week
// Remove multiples of 400 years (incl. 97 leap days)
quadricentennials = UInt32((UInt64(sec) / (12622780800 as UInt64))) // 400*365.2425*24*3600
sec %= 12622780800 as UInt64
// Remove multiples of 100 years (incl. 24 leap days), can't be more than 3
// (because multiples of 4*100=400 years (incl. leap days) have been removed)
centennials = UInt32(UInt64(sec) / (3155673600 as UInt64)) // 100*(365+24/100)*24*3600
if centennials > 3 {
centennials = 3
}
sec -= UInt64(centennials) * (3155673600 as UInt64)
// Remove multiples of 4 years (incl. 1 leap day), can't be more than 24
// (because multiples of 25*4=100 years (incl. leap days) have been removed)
quadrennials = UInt32((UInt64(sec) / (126230400 as UInt64))) // 4*(365+1/4)*24*3600
if quadrennials > 24 {
quadrennials = 24
}
sec -= UInt64(quadrennials) * (126230400 as UInt64)
// Remove multiples of years (incl. 0 leap days), can't be more than 3
// (because multiples of 4 years (incl. leap days) have been removed)
annuals = UInt32(sec / (31536000 as UInt64)) // 365*24*3600
if annuals > 3 {
annuals = 3
}
sec -= UInt64(annuals) * (31536000 as UInt64)
// Calculate the year and find out if it's leap
year = 1601 + quadricentennials * 400 + centennials * 100 + quadrennials * 4 + annuals;
leap = (!(year % UInt32(4) != 0) && ((year % UInt32(100) != 0) || !(year % UInt32(400) != 0))) ? 1 : 0
// Calculate the day of the year and the time
yday = UInt32(sec / (86400 as UInt64))
sec %= 86400;
hour = UInt32(sec / 3600);
sec %= 3600;
min = UInt32(sec / 60);
sec %= 60;
mday = 1
month = 1
while month < 13 {
if (yday < daysSinceJan1st[Int(leap)][Int(month)]) {
mday += yday - daysSinceJan1st[Int(leap)][Int(month - 1)]
break
}
month += 1
}
return DateTime(seconds: Int32(sec), minutes: Int32(min), hours: Int32(hour), dayOfMonth: Int32(mday), month: Int32(month - 1), year: Int32(year - 1900), dayOfWeek: Int32(wday), dayOfYear: Int32(yday))
}

View File

@ -127,7 +127,7 @@ extension Api.Chat {
extension Api.User {
var peerId: PeerId {
switch self {
case .user(_, let id, _, _, _, _, _, _, _, _, _, _):
case .user(_, let id, _, _, _, _, _, _, _, _, _, _, _):
return PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
case let .userEmpty(id):
return PeerId(namespace: Namespaces.Peer.CloudUser, id: id)