no message

This commit is contained in:
Peter 2016-12-27 14:40:30 +03:00
parent 59411a3c2e
commit c2768b07b3
17 changed files with 930 additions and 335 deletions

View File

@ -7,7 +7,26 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CFF1D62255C00955575 /* ChannelState.swift */; };
D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; };
D001F3EA1E128A1C007A8C60 /* TelegramPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */; };
D001F3EB1E128A1C007A8C60 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; };
D001F3EC1E128A1C007A8C60 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; };
D001F3ED1E128A1C007A8C60 /* SendUnsentMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D021D62255C00955575 /* SendUnsentMessage.swift */; };
D001F3EE1E128A1C007A8C60 /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; };
D001F3EF1E128A1C007A8C60 /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; };
D001F3F01E128A1C007A8C60 /* AccountStateManagementUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */; };
D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; };
D001F3F21E128A1C007A8C60 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; };
D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; };
D001F3F41E128A1C007A8C60 /* UpdatesApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */; };
D001F3F51E128A1C007A8C60 /* PendingMessageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */; };
D001F3F61E128A1C007A8C60 /* PendingMessageUploadedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */; };
D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9221DD5E9A200E8160F /* ApplyUpdateMessage.swift */; };
D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; }; D003702B1DA42586004308D3 /* PhoneNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = D003702A1DA42586004308D3 /* PhoneNumber.swift */; };
D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01749581E1092BC0057C89A /* RequestStartBot.swift */; };
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495D1E118F790057C89A /* AccountStateManager.swift */; };
D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D017495F1E118FC30057C89A /* AccountIntermediateState.swift */; };
D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; }; D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */; };
D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */; }; D01AC91D1DD5DA5E00E8160F /* RequestMessageActionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */; };
D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */; }; D01AC9211DD5E7E500E8160F /* RequestEditMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */; };
@ -41,7 +60,7 @@
D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; }; D03B0D091D62255C00955575 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; };
D03B0D0A1D62255C00955575 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; }; D03B0D0A1D62255C00955575 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; };
D03B0D0B1D62255C00955575 /* SendUnsentMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D021D62255C00955575 /* SendUnsentMessage.swift */; }; D03B0D0B1D62255C00955575 /* SendUnsentMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D021D62255C00955575 /* SendUnsentMessage.swift */; };
D03B0D0C1D62255C00955575 /* StateManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* StateManagement.swift */; }; D03B0D0C1D62255C00955575 /* AccountStateManagementUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */; };
D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; }; D03B0D0D1D62255C00955575 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; };
D03B0D0E1D62255C00955575 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; }; D03B0D0E1D62255C00955575 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; };
D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; }; D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; };
@ -91,8 +110,6 @@
D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */; }; D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5C1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift */; };
D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */; }; D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE5F1DCB9D14007511FD /* OutgoingMessageInfoAttribute.swift */; };
D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0DE1DB539FC00C6B04F /* StickerPack.swift */; }; D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0DE1DB539FC00C6B04F /* StickerPack.swift */; };
D073CEA21DCBF3E1007511FD /* PendingMessageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B31DB02C2B00A905C0 /* PendingMessageManager.swift */; };
D073CEA31DCBF3E1007511FD /* PendingMessageUploadedContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09BB6B51DB0428000A905C0 /* PendingMessageUploadedContent.swift */; };
D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; }; D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; };
D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E11DB5401A00C6B04F /* StickerManagement.swift */; }; D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D021E0E11DB5401A00C6B04F /* StickerManagement.swift */; };
D07827BB1E00451F00071108 /* SearchPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827BA1E00451F00071108 /* SearchPeers.swift */; }; D07827BB1E00451F00071108 /* SearchPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827BA1E00451F00071108 /* SearchPeers.swift */; };
@ -191,16 +208,6 @@
D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */; }; D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AD1DA7FF30005F29E1 /* NBPhoneNumberDefines.m */; };
D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */; }; D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843AF1DA7FF30005F29E1 /* NBPhoneNumberDesc.m */; };
D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */; }; D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = D0B843B11DA7FF30005F29E1 /* NBPhoneNumberUtil.m */; };
D0B844381DAB91EF005F29E1 /* ChannelState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CFF1D62255C00955575 /* ChannelState.swift */; };
D0B844391DAB91EF005F29E1 /* TelegramPeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */; };
D0B8443A1DAB91EF005F29E1 /* EnqueueMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D001D62255C00955575 /* EnqueueMessage.swift */; };
D0B8443B1DAB91EF005F29E1 /* Holes.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D011D62255C00955575 /* Holes.swift */; };
D0B8443C1DAB91EF005F29E1 /* SendUnsentMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D021D62255C00955575 /* SendUnsentMessage.swift */; };
D0B8443D1DAB91EF005F29E1 /* StateManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D031D62255C00955575 /* StateManagement.swift */; };
D0B8443E1DAB91EF005F29E1 /* SynchronizePeerReadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */; };
D0B8443F1DAB91EF005F29E1 /* UpdateGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D051D62255C00955575 /* UpdateGroup.swift */; };
D0B844401DAB91EF005F29E1 /* UpdateMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D061D62255C00955575 /* UpdateMessageService.swift */; };
D0B844411DAB91EF005F29E1 /* UpdatesApiUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D071D62255C00955575 /* UpdatesApiUtils.swift */; };
D0B844431DAB91FD005F29E1 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D611D631A8B00955575 /* Account.swift */; }; D0B844431DAB91FD005F29E1 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D611D631A8B00955575 /* Account.swift */; };
D0B844441DAB91FD005F29E1 /* AccountSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D621D631A8B00955575 /* AccountSettings.swift */; }; D0B844441DAB91FD005F29E1 /* AccountSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D621D631A8B00955575 /* AccountSettings.swift */; };
D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D631D631A8B00955575 /* AccountViewTracker.swift */; }; D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0D631D631A8B00955575 /* AccountViewTracker.swift */; };
@ -256,6 +263,9 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = "<group>"; }; D003702A1DA42586004308D3 /* PhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhoneNumber.swift; sourceTree = "<group>"; };
D01749581E1092BC0057C89A /* RequestStartBot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestStartBot.swift; sourceTree = "<group>"; };
D017495D1E118F790057C89A /* AccountStateManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManager.swift; sourceTree = "<group>"; };
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountIntermediateState.swift; sourceTree = "<group>"; };
D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatState.swift; sourceTree = "<group>"; }; D0177B7A1DF8A16C00A5083A /* SecretChatState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretChatState.swift; sourceTree = "<group>"; };
D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestMessageActionCallback.swift; sourceTree = "<group>"; }; D01AC91C1DD5DA5E00E8160F /* RequestMessageActionCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestMessageActionCallback.swift; sourceTree = "<group>"; };
D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestEditMessage.swift; sourceTree = "<group>"; }; D01AC9201DD5E7E500E8160F /* RequestEditMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestEditMessage.swift; sourceTree = "<group>"; };
@ -289,7 +299,7 @@
D03B0D001D62255C00955575 /* EnqueueMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnqueueMessage.swift; sourceTree = "<group>"; }; D03B0D001D62255C00955575 /* EnqueueMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnqueueMessage.swift; sourceTree = "<group>"; };
D03B0D011D62255C00955575 /* Holes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Holes.swift; sourceTree = "<group>"; }; D03B0D011D62255C00955575 /* Holes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Holes.swift; sourceTree = "<group>"; };
D03B0D021D62255C00955575 /* SendUnsentMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendUnsentMessage.swift; sourceTree = "<group>"; }; D03B0D021D62255C00955575 /* SendUnsentMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SendUnsentMessage.swift; sourceTree = "<group>"; };
D03B0D031D62255C00955575 /* StateManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StateManagement.swift; sourceTree = "<group>"; }; D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountStateManagementUtils.swift; sourceTree = "<group>"; };
D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadState.swift; sourceTree = "<group>"; }; D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizePeerReadState.swift; sourceTree = "<group>"; };
D03B0D051D62255C00955575 /* UpdateGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateGroup.swift; sourceTree = "<group>"; }; D03B0D051D62255C00955575 /* UpdateGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateGroup.swift; sourceTree = "<group>"; };
D03B0D061D62255C00955575 /* UpdateMessageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateMessageService.swift; sourceTree = "<group>"; }; D03B0D061D62255C00955575 /* UpdateMessageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateMessageService.swift; sourceTree = "<group>"; };
@ -594,7 +604,9 @@
D03B0D001D62255C00955575 /* EnqueueMessage.swift */, D03B0D001D62255C00955575 /* EnqueueMessage.swift */,
D03B0D011D62255C00955575 /* Holes.swift */, D03B0D011D62255C00955575 /* Holes.swift */,
D03B0D021D62255C00955575 /* SendUnsentMessage.swift */, D03B0D021D62255C00955575 /* SendUnsentMessage.swift */,
D03B0D031D62255C00955575 /* StateManagement.swift */, D017495D1E118F790057C89A /* AccountStateManager.swift */,
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */,
D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */,
D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */, D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */,
D03B0D051D62255C00955575 /* UpdateGroup.swift */, D03B0D051D62255C00955575 /* UpdateGroup.swift */,
D03B0D061D62255C00955575 /* UpdateMessageService.swift */, D03B0D061D62255C00955575 /* UpdateMessageService.swift */,
@ -672,6 +684,7 @@
D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */, D0DC354D1DE368F7000195EB /* RequestChatContextResults.swift */,
D0DC354F1DE36900000195EB /* ChatContextResult.swift */, D0DC354F1DE36900000195EB /* ChatContextResult.swift */,
D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */, D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */,
D01749581E1092BC0057C89A /* RequestStartBot.swift */,
); );
name = Messages; name = Messages;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1029,12 +1042,14 @@
D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */, D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */,
D03B0CF61D62250800955575 /* TelegramMediaFile.swift in Sources */, D03B0CF61D62250800955575 /* TelegramMediaFile.swift in Sources */,
D03B0CE81D6224AD00955575 /* ViewCountMessageAttribute.swift in Sources */, D03B0CE81D6224AD00955575 /* ViewCountMessageAttribute.swift in Sources */,
D03B0D0C1D62255C00955575 /* StateManagement.swift in Sources */, D03B0D0C1D62255C00955575 /* AccountStateManagementUtils.swift in Sources */,
D073CE5D1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift in Sources */, D073CE5D1DCB97F6007511FD /* ForwardSourceInfoAttribute.swift in Sources */,
D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */, D03B0D721D631ABA00955575 /* SearchMessages.swift in Sources */,
D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */, D0DC35501DE36900000195EB /* ChatContextResult.swift in Sources */,
D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */, D0177B7B1DF8A16C00A5083A /* SecretChatState.swift in Sources */,
D03B0D5C1D631A6900955575 /* Download.swift in Sources */, D03B0D5C1D631A6900955575 /* Download.swift in Sources */,
D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */,
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */,
D0B843C71DA7FF30005F29E1 /* NBPhoneNumberDefines.m in Sources */, D0B843C71DA7FF30005F29E1 /* NBPhoneNumberDefines.m in Sources */,
D03B0D5D1D631A6900955575 /* MultipartFetch.swift in Sources */, D03B0D5D1D631A6900955575 /* MultipartFetch.swift in Sources */,
D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */, D0AB0B961D662F0B002C78E7 /* ManagedChatListHoles.swift in Sources */,
@ -1051,6 +1066,7 @@
D03B0CC11D62235000955575 /* StringFormat.swift in Sources */, D03B0CC11D62235000955575 /* StringFormat.swift in Sources */,
D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */, D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */,
D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */, D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */,
D01749601E118FC30057C89A /* AccountIntermediateState.swift in Sources */,
D03B0D651D631A8B00955575 /* Account.swift in Sources */, D03B0D651D631A8B00955575 /* Account.swift in Sources */,
D0AB0B941D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift in Sources */, D0AB0B941D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift in Sources */,
D03B0CF41D62250800955575 /* TelegramMediaAction.swift in Sources */, D03B0CF41D62250800955575 /* TelegramMediaAction.swift in Sources */,
@ -1075,7 +1091,6 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D0B8443D1DAB91EF005F29E1 /* StateManagement.swift in Sources */,
D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */, D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */,
D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */, D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */,
D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */, D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */,
@ -1083,38 +1098,42 @@
D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */, D0B844311DAB91E0005F29E1 /* NBPhoneMetaData.m in Sources */,
D0B418AC1D7E0597004562A4 /* Network.swift in Sources */, D0B418AC1D7E0597004562A4 /* Network.swift in Sources */,
D0B844141DAB91CD005F29E1 /* PhoneNumbers.swift in Sources */, D0B844141DAB91CD005F29E1 /* PhoneNumbers.swift in Sources */,
D0B844391DAB91EF005F29E1 /* TelegramPeerNotificationSettings.swift in Sources */,
D0B844491DAB91FD005F29E1 /* ManagedChatListHoles.swift in Sources */, D0B844491DAB91FD005F29E1 /* ManagedChatListHoles.swift in Sources */,
D03C53711DAD5CA9004C17B3 /* CachedGroupParticipants.swift in Sources */, D03C53711DAD5CA9004C17B3 /* CachedGroupParticipants.swift in Sources */,
D03C53671DAD5CA9004C17B3 /* ApiUtils.swift in Sources */, D03C53671DAD5CA9004C17B3 /* ApiUtils.swift in Sources */,
D001F3F21E128A1C007A8C60 /* UpdateGroup.swift in Sources */,
D0F7B1EB1E045C87007EB8A5 /* ResolvePeerByName.swift in Sources */, D0F7B1EB1E045C87007EB8A5 /* ResolvePeerByName.swift in Sources */,
D001F3EE1E128A1C007A8C60 /* AccountStateManager.swift in Sources */,
D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */, D0B844351DAB91E0005F29E1 /* NBPhoneNumberDesc.m in Sources */,
D0B8442F1DAB91E0005F29E1 /* NBMetadataHelper.m in Sources */, D0B8442F1DAB91E0005F29E1 /* NBMetadataHelper.m in Sources */,
D0B8444C1DAB91FD005F29E1 /* UpdateCachedPeerData.swift in Sources */, D0B8444C1DAB91FD005F29E1 /* UpdateCachedPeerData.swift in Sources */,
D0B418A81D7E0597004562A4 /* Api.swift in Sources */, D0B418A81D7E0597004562A4 /* Api.swift in Sources */,
D03C536C1DAD5CA9004C17B3 /* TelegramChannel.swift in Sources */, D03C536C1DAD5CA9004C17B3 /* TelegramChannel.swift in Sources */,
D0B418951D7E0580004562A4 /* TelegramMediaContact.swift in Sources */, D0B418951D7E0580004562A4 /* TelegramMediaContact.swift in Sources */,
D0B8443B1DAB91EF005F29E1 /* Holes.swift in Sources */,
D0F3CC7A1DDE2859008148FA /* RequestMessageActionCallback.swift in Sources */, D0F3CC7A1DDE2859008148FA /* RequestMessageActionCallback.swift in Sources */,
D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */, D073CEA11DCBF3D3007511FD /* StickerPack.swift in Sources */,
D0E35A141DE4C69C00BC6096 /* FetchHttpResource.swift in Sources */, D0E35A141DE4C69C00BC6096 /* FetchHttpResource.swift in Sources */,
D0B8443E1DAB91EF005F29E1 /* SynchronizePeerReadState.swift in Sources */,
D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */, D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */,
D03C536A1DAD5CA9004C17B3 /* TelegramUser.swift in Sources */, D03C536A1DAD5CA9004C17B3 /* TelegramUser.swift in Sources */,
D001F3EA1E128A1C007A8C60 /* TelegramPeerNotificationSettings.swift in Sources */,
D001F3EB1E128A1C007A8C60 /* EnqueueMessage.swift in Sources */,
D0B844481DAB91FD005F29E1 /* ManagedMessageHistoryHoles.swift in Sources */, D0B844481DAB91FD005F29E1 /* ManagedMessageHistoryHoles.swift in Sources */,
D0F3CC7B1DDE2859008148FA /* RequestEditMessage.swift in Sources */, D0F3CC7B1DDE2859008148FA /* RequestEditMessage.swift in Sources */,
D0B844441DAB91FD005F29E1 /* AccountSettings.swift in Sources */, D0B844441DAB91FD005F29E1 /* AccountSettings.swift in Sources */,
D001F3F01E128A1C007A8C60 /* AccountStateManagementUtils.swift in Sources */,
D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */, D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */,
D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */, D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */,
D001F3F31E128A1C007A8C60 /* UpdateMessageService.swift in Sources */,
D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */, D0B8442D1DAB91E0005F29E1 /* NBMetadataCoreTest.m in Sources */,
D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */, D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */,
D0B844401DAB91EF005F29E1 /* UpdateMessageService.swift in Sources */,
D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */, D0E35A131DE4C69100BC6096 /* OutgoingChatContextResultMessageAttribute.swift in Sources */,
D0B418961D7E0580004562A4 /* TelegramMediaFile.swift in Sources */, D0B418961D7E0580004562A4 /* TelegramMediaFile.swift in Sources */,
D001F3EC1E128A1C007A8C60 /* Holes.swift in Sources */,
D0B4189B1D7E0580004562A4 /* TelegramMediaWebpage.swift in Sources */, D0B4189B1D7E0580004562A4 /* TelegramMediaWebpage.swift in Sources */,
D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */, D0B844341DAB91E0005F29E1 /* NBPhoneNumberDefines.m in Sources */,
D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */, D0B8442A1DAB91E0005F29E1 /* NBAsYouTypeFormatter.m in Sources */,
D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */, D073CE6E1DCBCF17007511FD /* ForwardSourceInfoAttribute.swift in Sources */,
D001F3E81E128A1C007A8C60 /* ChannelState.swift in Sources */,
D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */, D0B844451DAB91FD005F29E1 /* AccountViewTracker.swift in Sources */,
D0B418A61D7E0592004562A4 /* CloudFileMediaResource.swift in Sources */, D0B418A61D7E0592004562A4 /* CloudFileMediaResource.swift in Sources */,
D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */, D073CEA51DCBF3F5007511FD /* StickerManagement.swift in Sources */,
@ -1122,12 +1141,12 @@
D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */, D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */,
D0B418A91D7E0597004562A4 /* Buffer.swift in Sources */, D0B418A91D7E0597004562A4 /* Buffer.swift in Sources */,
D0B8442E1DAB91E0005F29E1 /* NBMetadataCoreTestMapper.m in Sources */, D0B8442E1DAB91E0005F29E1 /* NBMetadataCoreTestMapper.m in Sources */,
D0B8443F1DAB91EF005F29E1 /* UpdateGroup.swift in Sources */,
D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */, D03C53731DAD5CA9004C17B3 /* CachedGroupData.swift in Sources */,
D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */, D0F7AB2D1DCE889D009AD9A1 /* EditedMessageAttribute.swift in Sources */,
D0B844121DAB91CD005F29E1 /* Log.swift in Sources */, D0B844121DAB91CD005F29E1 /* Log.swift in Sources */,
D03C53721DAD5CA9004C17B3 /* CachedUserData.swift in Sources */, D03C53721DAD5CA9004C17B3 /* CachedUserData.swift in Sources */,
D073CE6B1DCBCF17007511FD /* ReplyMessageAttribute.swift in Sources */, D073CE6B1DCBCF17007511FD /* ReplyMessageAttribute.swift in Sources */,
D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */,
D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */, D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */,
D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */, D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */,
D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */, D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */,
@ -1137,14 +1156,15 @@
D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */, D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */,
D0DC35511DE36908000195EB /* RequestChatContextResults.swift in Sources */, D0DC35511DE36908000195EB /* RequestChatContextResults.swift in Sources */,
D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */, D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */,
D001F3EF1E128A1C007A8C60 /* AccountIntermediateState.swift in Sources */,
D03C536E1DAD5CA9004C17B3 /* PhoneNumber.swift in Sources */, D03C536E1DAD5CA9004C17B3 /* PhoneNumber.swift in Sources */,
D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */, D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */,
D0B8443C1DAB91EF005F29E1 /* SendUnsentMessage.swift in Sources */,
D0B844321DAB91E0005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */, D0B844321DAB91E0005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */,
D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */, D073CEA41DCBF3EA007511FD /* MultipartUpload.swift in Sources */,
D03C53701DAD5CA9004C17B3 /* ExportedInvitation.swift in Sources */, D03C53701DAD5CA9004C17B3 /* ExportedInvitation.swift in Sources */,
D0F7B1E31E045C7B007EB8A5 /* RichText.swift in Sources */, D0F7B1E31E045C7B007EB8A5 /* RichText.swift in Sources */,
D0B418AA1D7E0597004562A4 /* Download.swift in Sources */, D0B418AA1D7E0597004562A4 /* Download.swift in Sources */,
D001F3F41E128A1C007A8C60 /* UpdatesApiUtils.swift in Sources */,
D0B4188E1D7E0578004562A4 /* StoreMessage_Telegram.swift in Sources */, D0B4188E1D7E0578004562A4 /* StoreMessage_Telegram.swift in Sources */,
D0B844461DAB91FD005F29E1 /* RecentPeers.swift in Sources */, D0B844461DAB91FD005F29E1 /* RecentPeers.swift in Sources */,
D03C53681DAD5CA9004C17B3 /* PeerUtils.swift in Sources */, D03C53681DAD5CA9004C17B3 /* PeerUtils.swift in Sources */,
@ -1155,25 +1175,25 @@
D0B418BA1D7E05BB004562A4 /* NetworkLogging.m in Sources */, D0B418BA1D7E05BB004562A4 /* NetworkLogging.m in Sources */,
D03C536B1DAD5CA9004C17B3 /* TelegramGroup.swift in Sources */, D03C536B1DAD5CA9004C17B3 /* TelegramGroup.swift in Sources */,
D0B418941D7E0580004562A4 /* TelegramMediaAction.swift in Sources */, D0B418941D7E0580004562A4 /* TelegramMediaAction.swift in Sources */,
D0B844411DAB91EF005F29E1 /* UpdatesApiUtils.swift in Sources */,
D0B844381DAB91EF005F29E1 /* ChannelState.swift in Sources */,
D0B8442C1DAB91E0005F29E1 /* NBMetadataCoreMapper.m in Sources */, D0B8442C1DAB91E0005F29E1 /* NBMetadataCoreMapper.m in Sources */,
D0B8443A1DAB91EF005F29E1 /* EnqueueMessage.swift in Sources */, D001F3ED1E128A1C007A8C60 /* SendUnsentMessage.swift in Sources */,
D073CE6A1DCBCF17007511FD /* ViewCountMessageAttribute.swift in Sources */, D073CE6A1DCBCF17007511FD /* ViewCountMessageAttribute.swift in Sources */,
D0B418AB1D7E0597004562A4 /* MultipartFetch.swift in Sources */, D0B418AB1D7E0597004562A4 /* MultipartFetch.swift in Sources */,
D0B418B71D7E05A6004562A4 /* Phonebook.swift in Sources */, D0B418B71D7E05A6004562A4 /* Phonebook.swift in Sources */,
D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */, D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */,
D073CEA31DCBF3E1007511FD /* PendingMessageUploadedContent.swift in Sources */,
D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */, D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */,
D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */, D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */,
D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */, D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */,
D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */, D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */,
D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */, D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */,
D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */,
D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */, D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */,
D0B844331DAB91E0005F29E1 /* NBPhoneNumber.m in Sources */, D0B844331DAB91E0005F29E1 /* NBPhoneNumber.m in Sources */,
D001F3F51E128A1C007A8C60 /* PendingMessageManager.swift in Sources */,
D001F3F61E128A1C007A8C60 /* PendingMessageUploadedContent.swift in Sources */,
D0F7B1E71E045C87007EB8A5 /* JoinChannel.swift in Sources */, D0F7B1E71E045C87007EB8A5 /* JoinChannel.swift in Sources */,
D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */, D0B844301DAB91E0005F29E1 /* NBNumberFormat.m in Sources */,
D073CEA21DCBF3E1007511FD /* PendingMessageManager.swift in Sources */, D001F3F71E128A1C007A8C60 /* ApplyUpdateMessage.swift in Sources */,
D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */, D0B418971D7E0580004562A4 /* TelegramMediaImage.swift in Sources */,
D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */, D0B844361DAB91E0005F29E1 /* NBPhoneNumberUtil.m in Sources */,
D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */, D073CE6F1DCBCF17007511FD /* OutgoingMessageInfoAttribute.swift in Sources */,

View File

@ -353,6 +353,13 @@ public enum AccountServiceTaskMasterMode {
case never case never
} }
public enum AccountNetworkState {
case waitingForNetwork
case connecting
case updating
case online
}
public class Account { public class Account {
public let id: AccountId public let id: AccountId
public let basePath: String public let basePath: String
@ -360,7 +367,7 @@ public class Account {
public let network: Network public let network: Network
public let peerId: PeerId public let peerId: PeerId
public private(set) var stateManager: StateManager! public private(set) var stateManager: AccountStateManager!
public private(set) var viewTracker: AccountViewTracker! public private(set) var viewTracker: AccountViewTracker!
public private(set) var pendingMessageManager: PendingMessageManager! public private(set) var pendingMessageManager: PendingMessageManager!
fileprivate let managedContactsDisposable = MetaDisposable() fileprivate let managedContactsDisposable = MetaDisposable()
@ -384,6 +391,11 @@ public class Account {
public let shouldBeServiceTaskMaster = Promise<AccountServiceTaskMasterMode>() public let shouldBeServiceTaskMaster = Promise<AccountServiceTaskMasterMode>()
public let shouldKeepOnlinePresence = Promise<Bool>() public let shouldKeepOnlinePresence = Promise<Bool>()
private let networkStateValue = Promise<AccountNetworkState>(.connecting)
public var networkState: Signal<AccountNetworkState, NoError> {
return self.networkStateValue.get()
}
public init(id: AccountId, basePath: String, postbox: Postbox, network: Network, peerId: PeerId) { public init(id: AccountId, basePath: String, postbox: Postbox, network: Network, peerId: PeerId) {
self.id = id self.id = id
self.basePath = basePath self.basePath = basePath
@ -391,10 +403,29 @@ public class Account {
self.network = network self.network = network
self.peerId = peerId self.peerId = peerId
self.stateManager = StateManager(account: self) self.stateManager = AccountStateManager(account: self)
self.viewTracker = AccountViewTracker(account: self) self.viewTracker = AccountViewTracker(account: self)
self.pendingMessageManager = PendingMessageManager(network: network, postbox: postbox, stateManager: self.stateManager) self.pendingMessageManager = PendingMessageManager(network: network, postbox: postbox, stateManager: self.stateManager)
let networkStateSignal = combineLatest(self.stateManager.isUpdating, network.connectionStatus)
|> map { isUpdating, connectionStatus -> AccountNetworkState in
switch connectionStatus {
case .WaitingForNetwork:
return .waitingForNetwork
case .Connecting:
return .connecting
case .Updating:
return .updating
case .Online:
if isUpdating {
return .updating
} else {
return .online
}
}
}
self.networkStateValue.set(networkStateSignal |> distinctUntilChanged)
let appliedNotificationToken = self.notificationToken.get() let appliedNotificationToken = self.notificationToken.get()
|> distinctUntilChanged |> distinctUntilChanged
|> mapToSignal { token -> Signal<Void, NoError> in |> mapToSignal { token -> Signal<Void, NoError> in

View File

@ -0,0 +1,292 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
final class AccountInitialState {
let state: AuthorizedAccountState.State
let peerIds: Set<PeerId>
let messageIds: Set<MessageId>
let channelStates: [PeerId: ChannelState]
let peerNotificationSettings: [PeerId: PeerNotificationSettings]
let peerIdsWithNewMessages: Set<PeerId>
let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]
init(state: AuthorizedAccountState.State, peerIds: Set<PeerId>, messageIds: Set<MessageId>, peerIdsWithNewMessages: Set<PeerId>, channelStates: [PeerId: ChannelState], peerNotificationSettings: [PeerId: PeerNotificationSettings], locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) {
self.state = state
self.peerIds = peerIds
self.messageIds = messageIds
self.channelStates = channelStates
self.peerIdsWithNewMessages = peerIdsWithNewMessages
self.peerNotificationSettings = peerNotificationSettings
self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps
}
}
enum AccountStateMutationOperation {
case AddMessages([StoreMessage], AddMessagesLocation)
case DeleteMessagesWithGlobalIds([Int32])
case DeleteMessages([MessageId])
case EditMessage(MessageId, StoreMessage)
case UpdateMedia(MediaId, Media?)
case ReadInbox(MessageId)
case ReadOutbox(MessageId)
case ResetReadState(PeerId, MessageId.Namespace, MessageId.Id, MessageId.Id, MessageId.Id, Int32)
case UpdateState(AuthorizedAccountState.State)
case UpdateChannelState(PeerId, ChannelState)
case UpdatePeerNotificationSettings(PeerId, PeerNotificationSettings)
case AddHole(MessageId)
case MergeApiChats([Api.Chat])
case UpdatePeer(PeerId, (Peer) -> Peer)
case MergeApiUsers([Api.User])
case MergePeerPresences([PeerId: PeerPresence])
}
struct AccountMutableState {
let initialState: AccountInitialState
let branchOperationIndex: Int
var operations: [AccountStateMutationOperation] = []
var state: AuthorizedAccountState.State
var peers: [PeerId: Peer]
var channelStates: [PeerId: ChannelState]
var peerNotificationSettings: [PeerId: PeerNotificationSettings]
var storedMessages: Set<MessageId>
var readInboxMaxIds: [PeerId: MessageId]
var storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]
var insertedPeers: [PeerId: Peer] = [:]
var preCachedResources: [(MediaResource, Data)] = []
init(initialState: AccountInitialState, initialPeers: [PeerId: Peer], initialStoredMessages: Set<MessageId>, initialReadInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]) {
self.initialState = initialState
self.state = initialState.state
self.peers = initialPeers
self.storedMessages = initialStoredMessages
self.readInboxMaxIds = initialReadInboxMaxIds
self.channelStates = initialState.channelStates
self.peerNotificationSettings = initialState.peerNotificationSettings
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
self.branchOperationIndex = 0
}
init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: ChannelState], peerNotificationSettings: [PeerId: PeerNotificationSettings], storedMessages: Set<MessageId>, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], branchOperationIndex: Int) {
self.initialState = initialState
self.operations = operations
self.state = state
self.peers = peers
self.channelStates = channelStates
self.storedMessages = storedMessages
self.peerNotificationSettings = peerNotificationSettings
self.readInboxMaxIds = readInboxMaxIds
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
self.branchOperationIndex = branchOperationIndex
}
func branch() -> AccountMutableState {
return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerNotificationSettings: self.peerNotificationSettings, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, branchOperationIndex: self.operations.count)
}
mutating func merge(_ other: AccountMutableState) {
for i in other.branchOperationIndex ..< other.operations.count {
self.addOperation(other.operations[i])
}
for (_, peer) in other.insertedPeers {
self.peers[peer.id] = peer
}
self.preCachedResources.append(contentsOf: other.preCachedResources)
}
mutating func addPreCachedResource(_ resource: MediaResource, data: Data) {
self.preCachedResources.append((resource, data))
}
mutating func addMessages(_ messages: [StoreMessage], location: AddMessagesLocation) {
self.addOperation(.AddMessages(messages, location))
}
mutating func deleteMessagesWithGlobalIds(_ globalIds: [Int32]) {
self.addOperation(.DeleteMessagesWithGlobalIds(globalIds))
}
mutating func deleteMessages(_ messageIds: [MessageId]) {
self.addOperation(.DeleteMessages(messageIds))
}
mutating func editMessage(_ id: MessageId, message: StoreMessage) {
self.addOperation(.EditMessage(id, message))
}
mutating func updateMedia(_ id: MediaId, media: Media?) {
self.addOperation(.UpdateMedia(id, media))
}
mutating func readInbox(_ messageId: MessageId) {
self.addOperation(.ReadInbox(messageId))
}
mutating func readOutbox(_ messageId: MessageId) {
self.addOperation(.ReadOutbox(messageId))
}
mutating func resetReadState(_ peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32) {
self.addOperation(.ResetReadState(peerId, namespace, maxIncomingReadId, maxOutgoingReadId, maxKnownId, count))
}
mutating func updateState(_ state: AuthorizedAccountState.State) {
self.addOperation(.UpdateState(state))
}
mutating func updateChannelState(_ peerId: PeerId, state: ChannelState) {
self.addOperation(.UpdateChannelState(peerId, state))
}
mutating func updatePeerNotificationSettings(_ peerId: PeerId, notificationSettings: PeerNotificationSettings) {
self.addOperation(.UpdatePeerNotificationSettings(peerId, notificationSettings))
}
mutating func addHole(_ messageId: MessageId) {
self.addOperation(.AddHole(messageId))
}
mutating func mergeChats(_ chats: [Api.Chat]) {
self.addOperation(.MergeApiChats(chats))
}
mutating func updatePeer(_ id: PeerId, _ f: @escaping (Peer) -> Peer) {
self.addOperation(.UpdatePeer(id, f))
}
mutating func mergeUsers(_ users: [Api.User]) {
self.addOperation(.MergeApiUsers(users))
var presences: [PeerId: PeerPresence] = [:]
for user in users {
switch user {
case let .user(_, id, _, _, _, _, _, _, status, _, _, _):
if let status = status {
presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] = TelegramUserPresence(apiStatus: status)
}
break
case .userEmpty:
break
}
}
if !presences.isEmpty {
self.addOperation(.MergePeerPresences(presences))
}
}
mutating func mergePeerPresences(_ presences: [PeerId: PeerPresence]) {
self.addOperation(.MergePeerPresences(presences))
}
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .MergePeerPresences:
break
case let .AddMessages(messages, _):
for message in messages {
if case let .Id(id) = message.id {
self.storedMessages.insert(id)
}
}
case let .UpdateState(state):
self.state = state
case let .UpdateChannelState(peerId, channelState):
self.channelStates[peerId] = channelState
case let .UpdatePeerNotificationSettings(peerId, notificationSettings):
self.peerNotificationSettings[peerId] = notificationSettings
case let .MergeApiChats(chats):
for chat in chats {
if let groupOrChannel = mergeGroupOrChannel(lhs: peers[chat.peerId], rhs: chat) {
peers[groupOrChannel.id] = groupOrChannel
insertedPeers[groupOrChannel.id] = groupOrChannel
}
}
case let .MergeApiUsers(users):
for apiUser in users {
if let user = TelegramUser.merge(peers[apiUser.peerId] as? TelegramUser, rhs: apiUser) {
peers[user.id] = user
insertedPeers[user.id] = user
}
}
case let .UpdatePeer(id, f):
if let peer = self.peers[id] {
let updatedPeer = f(peer)
peers[id] = updatedPeer
insertedPeers[id] = updatedPeer
}
case let .ReadInbox(messageId):
let current = self.readInboxMaxIds[messageId.peerId]
if current == nil || current! < messageId {
self.readInboxMaxIds[messageId.peerId] = messageId
}
//namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32
case let .ResetReadState(peerId, namespace, maxIncomingReadId, _, _, _):
let current = self.readInboxMaxIds[peerId]
if namespace == Namespaces.Message.Cloud {
if current == nil || current!.id < maxIncomingReadId {
self.readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: namespace, id: maxIncomingReadId)
}
}
}
self.operations.append(operation)
}
}
struct AccountFinalState {
let state: AccountMutableState
let shouldPoll: Bool
let incomplete: Bool
}
struct AccountFinalStateEvents {
let addedIncomingMessageIds: [MessageId]
var isEmpty: Bool {
return self.addedIncomingMessageIds.isEmpty
}
init() {
self.addedIncomingMessageIds = []
}
init(addedIncomingMessageIds: [MessageId]) {
self.addedIncomingMessageIds = addedIncomingMessageIds
}
init(state: AccountMutableState) {
var addedIncomingMessageIds: [MessageId] = []
for operation in state.operations {
switch operation {
case let .AddMessages(messages, location):
if case .UpperHistoryBlock = location {
for message in messages {
if case let .Id(id) = message.id, message.flags.contains(.Incoming) {
addedIncomingMessageIds.append(id)
}
}
}
default:
break
}
}
self.addedIncomingMessageIds = addedIncomingMessageIds
}
func union(with other: AccountFinalStateEvents) -> AccountFinalStateEvents {
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds)
}
}

View File

@ -15,232 +15,6 @@ private enum Event<T, E> {
case Completion case Completion
} }
private final class InitialState {
let state: AuthorizedAccountState.State
let peerIds: Set<PeerId>
let messageIds: Set<MessageId>
let channelStates: [PeerId: ChannelState]
let peerNotificationSettings: [PeerId: PeerNotificationSettings]
let peerIdsWithNewMessages: Set<PeerId>
let locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]
init(state: AuthorizedAccountState.State, peerIds: Set<PeerId>, messageIds: Set<MessageId>, peerIdsWithNewMessages: Set<PeerId>, channelStates: [PeerId: ChannelState], peerNotificationSettings: [PeerId: PeerNotificationSettings], locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) {
self.state = state
self.peerIds = peerIds
self.messageIds = messageIds
self.channelStates = channelStates
self.peerIdsWithNewMessages = peerIdsWithNewMessages
self.peerNotificationSettings = peerNotificationSettings
self.locallyGeneratedMessageTimestamps = locallyGeneratedMessageTimestamps
}
}
private enum MutationOperation {
case AddMessages([StoreMessage], AddMessagesLocation)
case DeleteMessagesWithGlobalIds([Int32])
case DeleteMessages([MessageId])
case EditMessage(MessageId, StoreMessage)
case UpdateMedia(MediaId, Media?)
case ReadInbox(MessageId)
case ReadOutbox(MessageId)
case ResetReadState(PeerId, MessageId.Namespace, MessageId.Id, MessageId.Id, MessageId.Id, Int32)
case UpdateState(AuthorizedAccountState.State)
case UpdateChannelState(PeerId, ChannelState)
case UpdatePeerNotificationSettings(PeerId, PeerNotificationSettings)
case AddHole(MessageId)
case MergeApiChats([Api.Chat])
case UpdatePeer(PeerId, (Peer) -> Peer)
case MergeApiUsers([Api.User])
case MergePeerPresences([PeerId: PeerPresence])
}
private struct MutableState {
let initialState: InitialState
let branchOperationIndex: Int
fileprivate var operations: [MutationOperation] = []
fileprivate var state: AuthorizedAccountState.State
fileprivate var peers: [PeerId: Peer]
fileprivate var channelStates: [PeerId: ChannelState]
fileprivate var peerNotificationSettings: [PeerId: PeerNotificationSettings]
fileprivate var storedMessages: Set<MessageId>
fileprivate var storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]
fileprivate var insertedPeers: [PeerId: Peer] = [:]
fileprivate var preCachedResources: [(MediaResource, Data)] = []
init(initialState: InitialState, initialPeers: [PeerId: Peer], initialStoredMessages: Set<MessageId>, storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>]) {
self.initialState = initialState
self.state = initialState.state
self.peers = initialPeers
self.storedMessages = initialStoredMessages
self.channelStates = initialState.channelStates
self.peerNotificationSettings = initialState.peerNotificationSettings
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
self.branchOperationIndex = 0
}
init(initialState: InitialState, operations: [MutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: ChannelState], peerNotificationSettings: [PeerId: PeerNotificationSettings], storedMessages: Set<MessageId>, storedMessagesByPeerIdAndTimestamp: [PeerId: Set<MessageIndex>], branchOperationIndex: Int) {
self.initialState = initialState
self.operations = operations
self.state = state
self.peers = peers
self.channelStates = channelStates
self.storedMessages = storedMessages
self.peerNotificationSettings = peerNotificationSettings
self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp
self.branchOperationIndex = branchOperationIndex
}
func branch() -> MutableState {
return MutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerNotificationSettings: self.peerNotificationSettings, storedMessages: self.storedMessages, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, branchOperationIndex: self.operations.count)
}
mutating func merge(_ other: MutableState) {
for i in other.branchOperationIndex ..< other.operations.count {
self.addOperation(other.operations[i])
}
for (_, peer) in other.insertedPeers {
self.peers[peer.id] = peer
}
self.preCachedResources.append(contentsOf: other.preCachedResources)
}
mutating func addPreCachedResource(_ resource: MediaResource, data: Data) {
self.preCachedResources.append((resource, data))
}
mutating func addMessages(_ messages: [StoreMessage], location: AddMessagesLocation) {
self.addOperation(.AddMessages(messages, location))
}
mutating func deleteMessagesWithGlobalIds(_ globalIds: [Int32]) {
self.addOperation(.DeleteMessagesWithGlobalIds(globalIds))
}
mutating func deleteMessages(_ messageIds: [MessageId]) {
self.addOperation(.DeleteMessages(messageIds))
}
mutating func editMessage(_ id: MessageId, message: StoreMessage) {
self.addOperation(.EditMessage(id, message))
}
mutating func updateMedia(_ id: MediaId, media: Media?) {
self.addOperation(.UpdateMedia(id, media))
}
mutating func readInbox(_ messageId: MessageId) {
self.addOperation(.ReadInbox(messageId))
}
mutating func readOutbox(_ messageId: MessageId) {
self.addOperation(.ReadOutbox(messageId))
}
mutating func resetReadState(_ peerId: PeerId, namespace: MessageId.Namespace, maxIncomingReadId: MessageId.Id, maxOutgoingReadId: MessageId.Id, maxKnownId: MessageId.Id, count: Int32) {
self.addOperation(.ResetReadState(peerId, namespace, maxIncomingReadId, maxOutgoingReadId, maxKnownId, count))
}
mutating func updateState(_ state: AuthorizedAccountState.State) {
self.addOperation(.UpdateState(state))
}
mutating func updateChannelState(_ peerId: PeerId, state: ChannelState) {
self.addOperation(.UpdateChannelState(peerId, state))
}
mutating func updatePeerNotificationSettings(_ peerId: PeerId, notificationSettings: PeerNotificationSettings) {
self.addOperation(.UpdatePeerNotificationSettings(peerId, notificationSettings))
}
mutating func addHole(_ messageId: MessageId) {
self.addOperation(.AddHole(messageId))
}
mutating func mergeChats(_ chats: [Api.Chat]) {
self.addOperation(.MergeApiChats(chats))
}
mutating func updatePeer(_ id: PeerId, _ f: @escaping (Peer) -> Peer) {
self.addOperation(.UpdatePeer(id, f))
}
mutating func mergeUsers(_ users: [Api.User]) {
self.addOperation(.MergeApiUsers(users))
var presences: [PeerId: PeerPresence] = [:]
for user in users {
switch user {
case let .user(_, id, _, _, _, _, _, _, status, _, _, _):
if let status = status {
presences[PeerId(namespace: Namespaces.Peer.CloudUser, id: id)] = TelegramUserPresence(apiStatus: status)
}
break
case .userEmpty:
break
}
}
if !presences.isEmpty {
self.addOperation(.MergePeerPresences(presences))
}
}
mutating func mergePeerPresences(_ presences: [PeerId: PeerPresence]) {
self.addOperation(.MergePeerPresences(presences))
}
mutating func addOperation(_ operation: MutationOperation) {
switch operation {
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadInbox, .ReadOutbox, .ResetReadState, .MergePeerPresences:
break
case let .AddMessages(messages, _):
for message in messages {
if case let .Id(id) = message.id {
self.storedMessages.insert(id)
}
}
case let .UpdateState(state):
self.state = state
case let .UpdateChannelState(peerId, channelState):
self.channelStates[peerId] = channelState
case let .UpdatePeerNotificationSettings(peerId, notificationSettings):
self.peerNotificationSettings[peerId] = notificationSettings
case let .MergeApiChats(chats):
for chat in chats {
if let groupOrChannel = mergeGroupOrChannel(lhs: peers[chat.peerId], rhs: chat) {
peers[groupOrChannel.id] = groupOrChannel
insertedPeers[groupOrChannel.id] = groupOrChannel
}
}
case let .MergeApiUsers(users):
for apiUser in users {
if let user = TelegramUser.merge(peers[apiUser.peerId] as? TelegramUser, rhs: apiUser) {
peers[user.id] = user
insertedPeers[user.id] = user
}
}
case let .UpdatePeer(id, f):
if let peer = self.peers[id] {
let updatedPeer = f(peer)
peers[id] = updatedPeer
insertedPeers[id] = updatedPeer
}
}
self.operations.append(operation)
}
}
private struct FinalState {
let state: MutableState
let shouldPoll: Bool
let incomplete: Bool
}
private func peerIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<PeerId> { private func peerIdsFromUpdateGroups(_ groups: [UpdateGroup]) -> Set<PeerId> {
var peerIds = Set<PeerId>() var peerIds = Set<PeerId>()
@ -279,6 +53,13 @@ private func peersWithNewMessagesFromUpdateGroups(_ groups: [UpdateGroup]) -> Se
if let messageId = update.messageId { if let messageId = update.messageId {
peerIds.insert(messageId.peerId) peerIds.insert(messageId.peerId)
} }
switch update {
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
peerIds.insert(peerId)
default:
break
}
} }
} }
@ -403,6 +184,13 @@ private func peersWithNewMessagesFromDifference(_ difference: Api.updates.Differ
if let messageId = update.messageId { if let messageId = update.messageId {
peerIds.insert(messageId.peerId) peerIds.insert(messageId.peerId)
} }
switch update {
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
peerIds.insert(peerId)
default:
break
}
} }
case .differenceEmpty: case .differenceEmpty:
break break
@ -417,6 +205,13 @@ private func peersWithNewMessagesFromDifference(_ difference: Api.updates.Differ
if let messageId = update.messageId { if let messageId = update.messageId {
peerIds.insert(messageId.peerId) peerIds.insert(messageId.peerId)
} }
switch update {
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
peerIds.insert(peerId)
default:
break
}
} }
case .differenceTooLong: case .differenceTooLong:
break break
@ -461,7 +256,7 @@ private func locallyGeneratedMessageTimestampsFromDifference(_ difference: Api.u
return messageTimestamps return messageTimestamps
} }
private func initialStateWithPeerIds(_ modifier: Modifier, peerIds: Set<PeerId>, associatedMessageIds: Set<MessageId>, peerIdsWithNewMessages: Set<PeerId>, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> MutableState { private func initialStateWithPeerIds(_ modifier: Modifier, peerIds: Set<PeerId>, associatedMessageIds: Set<MessageId>, peerIdsWithNewMessages: Set<PeerId>, locallyGeneratedMessageTimestamps: [PeerId: [(MessageId.Namespace, Int32)]]) -> AccountMutableState {
var peers: [PeerId: Peer] = [:] var peers: [PeerId: Peer] = [:]
var channelStates: [PeerId: ChannelState] = [:] var channelStates: [PeerId: ChannelState] = [:]
@ -494,17 +289,27 @@ private func initialStateWithPeerIds(_ modifier: Modifier, peerIds: Set<PeerId>,
} }
var peerNotificationSettings: [PeerId: PeerNotificationSettings] = [:] var peerNotificationSettings: [PeerId: PeerNotificationSettings] = [:]
var readInboxMaxIds: [PeerId: MessageId] = [:]
for peerId in peerIdsWithNewMessages { for peerId in peerIdsWithNewMessages {
if let notificationSettings = modifier.getPeerNotificationSettings(peerId) { if let notificationSettings = modifier.getPeerNotificationSettings(peerId) {
peerNotificationSettings[peerId] = notificationSettings peerNotificationSettings[peerId] = notificationSettings
} }
if let readStates = modifier.getPeerReadStates(peerId) {
for (namespace, state) in readStates {
if namespace == Namespaces.Message.Cloud {
readInboxMaxIds[peerId] = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: state.maxIncomingReadId)
break
}
}
}
} }
return MutableState(initialState: InitialState(state: (modifier.getState() as? AuthorizedAccountState)!.state!, peerIds: peerIds, messageIds: associatedMessageIds, peerIdsWithNewMessages: peerIdsWithNewMessages, channelStates: channelStates, peerNotificationSettings: peerNotificationSettings, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestamps), initialPeers: peers, initialStoredMessages: storedMessages, storedMessagesByPeerIdAndTimestamp: storedMessagesByPeerIdAndTimestamp) return AccountMutableState(initialState: AccountInitialState(state: (modifier.getState() as? AuthorizedAccountState)!.state!, peerIds: peerIds, messageIds: associatedMessageIds, peerIdsWithNewMessages: peerIdsWithNewMessages, channelStates: channelStates, peerNotificationSettings: peerNotificationSettings, locallyGeneratedMessageTimestamps: locallyGeneratedMessageTimestamps), initialPeers: peers, initialStoredMessages: storedMessages, initialReadInboxMaxIds: readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: storedMessagesByPeerIdAndTimestamp)
} }
private func initialStateWithUpdateGroups(_ account: Account, groups: [UpdateGroup]) -> Signal<MutableState, NoError> { func initialStateWithUpdateGroups(_ account: Account, groups: [UpdateGroup]) -> Signal<AccountMutableState, NoError> {
return account.postbox.modify { modifier -> MutableState in return account.postbox.modify { modifier -> AccountMutableState in
let peerIds = peerIdsFromUpdateGroups(groups) let peerIds = peerIdsFromUpdateGroups(groups)
let associatedMessageIds = associatedMessageIdsFromUpdateGroups(groups) let associatedMessageIds = associatedMessageIdsFromUpdateGroups(groups)
let peerIdsWithNewMessages = peersWithNewMessagesFromUpdateGroups(groups) let peerIdsWithNewMessages = peersWithNewMessagesFromUpdateGroups(groups)
@ -513,8 +318,8 @@ private func initialStateWithUpdateGroups(_ account: Account, groups: [UpdateGro
} }
} }
private func initialStateWithDifference(_ account: Account, difference: Api.updates.Difference) -> Signal<MutableState, NoError> { func initialStateWithDifference(_ account: Account, difference: Api.updates.Difference) -> Signal<AccountMutableState, NoError> {
return account.postbox.modify { modifier -> MutableState in return account.postbox.modify { modifier -> AccountMutableState in
let peerIds = peerIdsFromDifference(difference) let peerIds = peerIdsFromDifference(difference)
let associatedMessageIds = associatedMessageIdsFromDifference(difference) let associatedMessageIds = associatedMessageIdsFromDifference(difference)
let peerIdsWithNewMessages = peersWithNewMessagesFromDifference(difference) let peerIdsWithNewMessages = peersWithNewMessagesFromDifference(difference)
@ -522,7 +327,7 @@ private func initialStateWithDifference(_ account: Account, difference: Api.upda
} }
} }
private func finalStateWithUpdateGroups(_ account: Account, state: MutableState, groups: [UpdateGroup]) -> Signal<FinalState, NoError> { func finalStateWithUpdateGroups(_ account: Account, state: AccountMutableState, groups: [UpdateGroup]) -> Signal<AccountFinalState, NoError> {
var updatedState = state var updatedState = state
var hadReset = false var hadReset = false
@ -640,7 +445,7 @@ private func finalStateWithUpdateGroups(_ account: Account, state: MutableState,
return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty) return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty)
} }
private func finalStateWithDifference(account: Account, state: MutableState, difference: Api.updates.Difference) -> Signal<FinalState, NoError> { func finalStateWithDifference(account: Account, state: AccountMutableState, difference: Api.updates.Difference) -> Signal<AccountFinalState, NoError> {
var updatedState = state var updatedState = state
var messages: [Api.Message] = [] var messages: [Api.Message] = []
@ -764,7 +569,7 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
return result return result
} }
private func finalStateWithUpdates(account: Account, state: MutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool) -> Signal<FinalState, NoError> { private func finalStateWithUpdates(account: Account, state: AccountMutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool) -> Signal<AccountFinalState, NoError> {
var updatedState = state var updatedState = state
var channelsToPoll = Set<PeerId>() var channelsToPoll = Set<PeerId>()
@ -979,7 +784,7 @@ private func finalStateWithUpdates(account: Account, state: MutableState, update
} }
} }
var pollChannelSignals: [Signal<MutableState, NoError>] = [] var pollChannelSignals: [Signal<AccountMutableState, NoError>] = []
for peerId in channelsToPoll { for peerId in channelsToPoll {
if let peer = updatedState.peers[peerId] { if let peer = updatedState.peers[peerId] {
pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch())) pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch()))
@ -988,16 +793,16 @@ private func finalStateWithUpdates(account: Account, state: MutableState, update
} }
} }
return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal<FinalState, NoError> in return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal<AccountFinalState, NoError> in
var finalState = updatedState var finalState = updatedState
for state in states { for state in states {
finalState.merge(state) finalState.merge(state)
} }
return resolveAssociatedMessages(account: account, state: finalState) return resolveAssociatedMessages(account: account, state: finalState)
|> mapToSignal { resultingState -> Signal<FinalState, NoError> in |> mapToSignal { resultingState -> Signal<AccountFinalState, NoError> in
return resolveMissingPeerNotificationSettings(account: account, state: resultingState) return resolveMissingPeerNotificationSettings(account: account, state: resultingState)
|> map { resultingState -> FinalState in |> map { resultingState -> AccountFinalState in
return FinalState(state: resultingState, shouldPoll: shouldPoll || missingUpdates, incomplete: missingUpdates) return AccountFinalState(state: resultingState, shouldPoll: shouldPoll, incomplete: missingUpdates)
} }
} }
} }
@ -1018,7 +823,7 @@ private func messagesIdsGroupedByPeerId(_ ids: Set<MessageId>) -> [PeerId: [Mess
return dict return dict
} }
private func resolveAssociatedMessages(account: Account, state: MutableState) -> Signal<MutableState, NoError> { private func resolveAssociatedMessages(account: Account, state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
let missingMessageIds = state.initialState.messageIds.subtracting(state.storedMessages) let missingMessageIds = state.initialState.messageIds.subtracting(state.storedMessages)
if missingMessageIds.isEmpty { if missingMessageIds.isEmpty {
return .single(state) return .single(state)
@ -1084,7 +889,7 @@ private func resolveAssociatedMessages(account: Account, state: MutableState) ->
} }
} }
private func resolveMissingPeerNotificationSettings(account: Account, state: MutableState) -> Signal<MutableState, NoError> { private func resolveMissingPeerNotificationSettings(account: Account, state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
var missingPeers: [PeerId: Api.InputPeer] = [:] var missingPeers: [PeerId: Api.InputPeer] = [:]
for peerId in state.initialState.peerIdsWithNewMessages { for peerId in state.initialState.peerIdsWithNewMessages {
@ -1113,7 +918,7 @@ private func resolveMissingPeerNotificationSettings(account: Account, state: Mut
signals.append(fetchSettings) signals.append(fetchSettings)
} }
return combineLatest(signals) return combineLatest(signals)
|> map { peersAndSettings -> MutableState in |> map { peersAndSettings -> AccountMutableState in
var updatedState = state var updatedState = state
for pair in peersAndSettings { for pair in peersAndSettings {
if let (peerId, settings) = pair { if let (peerId, settings) = pair {
@ -1127,11 +932,11 @@ private func resolveMissingPeerNotificationSettings(account: Account, state: Mut
return .single(state) return .single(state)
} }
private func pollChannel(_ account: Account, peer: Peer, state: MutableState) -> Signal<MutableState, NoError> { private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
if let inputChannel = apiInputChannel(peer) { if let inputChannel = apiInputChannel(peer) {
return account.network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: state.channelStates[peer.id]?.pts ?? 1, limit: 20)) return account.network.request(Api.functions.updates.getChannelDifference(flags: 0, channel: inputChannel, filter: .channelMessagesFilterEmpty, pts: state.channelStates[peer.id]?.pts ?? 1, limit: 20))
|> retryRequest |> retryRequest
|> map { difference -> MutableState in |> map { difference -> AccountMutableState in
var updatedState = state var updatedState = state
switch difference { switch difference {
case let .channelDifference(_, pts, _, newMessages, otherUpdates, chats, users): case let .channelDifference(_, pts, _, newMessages, otherUpdates, chats, users):
@ -1215,7 +1020,7 @@ private func pollChannel(_ account: Account, peer: Peer, state: MutableState) ->
} }
} }
private func verifyTransaction(_ modifier: Modifier, finalState: MutableState) -> Bool { private func verifyTransaction(_ modifier: Modifier, finalState: AccountMutableState) -> Bool {
var hadUpdateState = false var hadUpdateState = false
var channelsWithUpdatedStates = Set<PeerId>() var channelsWithUpdatedStates = Set<PeerId>()
@ -1300,8 +1105,8 @@ private final class OptimizeAddMessagesState {
} }
} }
private func optimizedOperations(_ operations: [MutationOperation]) -> [MutationOperation] { private func optimizedOperations(_ operations: [AccountStateMutationOperation]) -> [AccountStateMutationOperation] {
var result: [MutationOperation] = [] var result: [AccountStateMutationOperation] = []
var updatedState: AuthorizedAccountState.State? var updatedState: AuthorizedAccountState.State?
var updatedChannelStates: [PeerId: ChannelState] = [:] var updatedChannelStates: [PeerId: ChannelState] = [:]
@ -1345,7 +1150,7 @@ private func optimizedOperations(_ operations: [MutationOperation]) -> [Mutation
return result return result
} }
private func replayFinalState(_ modifier: Modifier, finalState: MutableState) -> Bool { func replayFinalState(_ modifier: Modifier, finalState: AccountMutableState) -> Bool {
let verified = verifyTransaction(modifier, finalState: finalState) let verified = verifyTransaction(modifier, finalState: finalState)
if !verified { if !verified {
return false return false
@ -1476,28 +1281,14 @@ private func pollDifference(_ account: Account) -> Signal<Void, NoError> {
return signal return signal
} }
#if os(macOS)
/*#if os(macOS)
private typealias SignalKitTimer = SwiftSignalKitMac.Timer private typealias SignalKitTimer = SwiftSignalKitMac.Timer
#else #else
private typealias SignalKitTimer = SwiftSignalKit.Timer private typealias SignalKitTimer = SwiftSignalKit.Timer
#endif #endif
private enum StateManagerState {
case none
case pollingDifference
}
private final class StateManagerInternal {
private let queue = Queue()
private let account: Account
init(account: Account) {
self.account = account
}
}
public final class StateManager { public final class StateManager {
private let stateQueue = Queue() private let stateQueue = Queue()
@ -1674,4 +1465,4 @@ public final class StateManager {
} }
} }
} }
} }*/

View File

@ -0,0 +1,393 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
private enum AccountStateManagerOperation {
case pollDifference(AccountFinalStateEvents)
case collectUpdateGroups([UpdateGroup], Double)
case processUpdateGroups([UpdateGroup])
case custom(Signal<Void, NoError>)
}
#if os(macOS)
private typealias SignalKitTimer = SwiftSignalKitMac.Timer
#else
private typealias SignalKitTimer = SwiftSignalKit.Timer
#endif
private enum CustomOperationEvent<T, E> {
case Next(T)
case Error(E)
case Completion
}
public final class AccountStateManager {
private let queue = Queue()
private let account: Account
private var updateService: UpdateMessageService?
private let updateServiceDisposable = MetaDisposable()
private var operations: [AccountStateManagerOperation] = []
private let operationDisposable = MetaDisposable()
private var operationTimer: SignalKitTimer?
private let isUpdatingValue = ValuePromise<Bool>(false)
private var currentIsUpdatingValue = false {
didSet {
if self.currentIsUpdatingValue != oldValue {
self.isUpdatingValue.set(self.currentIsUpdatingValue)
}
}
}
public var isUpdating: Signal<Bool, NoError> {
return self.isUpdatingValue.get()
}
private let notificationMessagesPipe = ValuePipe<[Message]>()
public var notificationMessages: Signal<[Message], NoError> {
return self.notificationMessagesPipe.signal()
}
init(account: Account) {
self.account = account
}
deinit {
self.updateServiceDisposable.dispose()
self.operationDisposable.dispose()
}
public func reset() {
self.queue.async {
if self.updateService == nil {
self.updateService = UpdateMessageService(peerId: self.account.peerId)
self.updateServiceDisposable.set(self.updateService!.pipe.signal().start(next: { [weak self] groups in
if let strongSelf = self {
strongSelf.addUpdateGroups(groups)
}
}))
self.account.network.mtProto.add(self.updateService)
}
self.operationDisposable.set(nil)
self.operations.removeAll()
self.addOperation(.pollDifference(AccountFinalStateEvents()))
}
}
func addUpdates(_ updates: Api.Updates) {
self.queue.async {
self.updateService?.addUpdates(updates)
}
}
func addUpdateGroups(_ groups: [UpdateGroup]) {
self.queue.async {
if let last = self.operations.last {
switch last {
case .pollDifference, .processUpdateGroups, .custom:
self.operations.append(.collectUpdateGroups(groups, 0.0))
case let .collectUpdateGroups(currentGroups, timestamp):
if timestamp.isEqual(to: 0.0) {
self.operations[self.operations.count - 1] = .collectUpdateGroups(currentGroups + groups, timestamp)
} else {
self.operations[self.operations.count - 1] = .processUpdateGroups(currentGroups + groups)
self.startFirstOperation()
}
}
} else {
self.operations.append(.collectUpdateGroups(groups, 0.0))
self.startFirstOperation()
}
}
}
func addCustomOperation<T, E>(_ f: Signal<T, E>) -> Signal<T, E> {
let pipe = ValuePipe<CustomOperationEvent<T, E>>()
return Signal<T, E> { subscriber in
let disposable = pipe.signal().start(next: { event in
switch event {
case let .Next(next):
subscriber.putNext(next)
case let .Error(error):
subscriber.putError(error)
case .Completion:
subscriber.putCompletion()
}
})
let signal = Signal<Void, NoError> { subscriber in
return f.start(next: { next in
pipe.putNext(.Next(next))
}, error: { error in
pipe.putNext(.Error(error))
subscriber.putCompletion()
}, completed: {
pipe.putNext(.Completion)
subscriber.putCompletion()
})
}
self.addOperation(.custom(signal))
return disposable
} |> runOn(self.queue)
}
private func addOperation(_ operation: AccountStateManagerOperation) {
self.queue.async {
let begin = self.operations.isEmpty
self.operations.append(operation)
if begin {
self.startFirstOperation()
}
}
}
private func startFirstOperation() {
guard let operation = self.operations.first else {
return
}
switch operation {
case let .pollDifference(currentEvents):
self.currentIsUpdatingValue = true
let account = self.account
let queue = self.queue
let signal = account.postbox.state()
|> filter { state in
if let _ = state as? AuthorizedAccountState {
return true
} else {
return false
}
}
|> take(1)
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountFinalState?), NoError> in
if let authorizedState = (state as! AuthorizedAccountState).state {
let request = account.network.request(Api.functions.updates.getDifference(flags: 0, pts: authorizedState.pts, ptsTotalLimit: nil, date: authorizedState.date, qts: authorizedState.qts))
|> retryRequest
return request |> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountFinalState?), NoError> in
return initialStateWithDifference(account, difference: difference)
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountFinalState?), NoError> in
if state.initialState.state != authorizedState {
trace("State", what: "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)")
return .single((nil, nil))
} else {
return finalStateWithDifference(account: account, state: state, difference: difference)
|> mapToSignal { finalState -> Signal<(Api.updates.Difference?, AccountFinalState?), NoError> in
if !finalState.state.preCachedResources.isEmpty {
for (resource, data) in finalState.state.preCachedResources {
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
}
}
return account.postbox.modify { modifier -> (Api.updates.Difference?, AccountFinalState?) in
if replayFinalState(modifier, finalState: finalState.state) {
return (difference, finalState)
} else {
return (nil, nil)
}
}
}
}
}
}
} else {
let appliedState = account.network.request(Api.functions.updates.getState())
|> retryRequest
|> mapToSignal { state in
return account.postbox.modify { modifier -> (Api.updates.Difference?, AccountFinalState?) in
if let currentState = modifier.getState() as? AuthorizedAccountState {
switch state {
case let .state(pts, qts, date, seq, _):
modifier.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: qts, date: date, seq: seq)))
}
}
return (nil, nil)
}
}
return appliedState
}
}
signal.start(next: { [weak self] difference, finalState in
if let strongSelf = self {
if case let .pollDifference = strongSelf.operations.removeFirst() {
let events: AccountFinalStateEvents
if let finalState = finalState {
events = currentEvents.union(with: AccountFinalStateEvents(state: finalState.state))
} else {
events = currentEvents
}
if let difference = difference {
switch difference {
case .differenceSlice:
strongSelf.operations.insert(.pollDifference(events), at: 0)
default:
if !events.isEmpty {
strongSelf.addEvents(events)
}
strongSelf.currentIsUpdatingValue = false
}
} else {
if !events.isEmpty {
strongSelf.addEvents(events)
}
strongSelf.operations.removeAll()
strongSelf.operations.append(.pollDifference(AccountFinalStateEvents()))
}
strongSelf.startFirstOperation()
} else {
assertionFailure()
}
}
}, error: { _ in
assertionFailure()
trace("AccountStateManager", what: "processUpdateGroups signal completed with error")
})
case let .collectUpdateGroups(groups, timeout):
self.operationTimer?.invalidate()
let operationTimer = SignalKitTimer(timeout: timeout, repeat: false, completion: { [weak self] in
if let strongSelf = self {
if case let .collectUpdateGroups(groups, _) = strongSelf.operations[0] {
if timeout.isEqual(to: 0.0) {
strongSelf.operations[0] = .processUpdateGroups(groups)
} else {
trace("AccountStateManager", what: "timeout while waiting for updates")
strongSelf.operations.removeAll()
strongSelf.operations.append(.pollDifference(AccountFinalStateEvents()))
}
strongSelf.startFirstOperation()
} else {
assertionFailure()
}
}
}, queue: self.queue)
self.operationTimer = operationTimer
operationTimer.start()
case let .processUpdateGroups(groups):
let account = self.account
let queue = self.queue
let signal = initialStateWithUpdateGroups(account, groups: groups)
|> mapToSignal { [weak self] state -> Signal<(Bool, AccountFinalState), NoError> in
return finalStateWithUpdateGroups(account, state: state, groups: groups)
|> mapToSignal { finalState in
if !finalState.state.preCachedResources.isEmpty {
for (resource, data) in finalState.state.preCachedResources {
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
}
}
return account.postbox.modify { modifier -> Bool in
return replayFinalState(modifier, finalState: finalState.state)
}
|> map({ ($0, finalState) })
|> deliverOn(queue)
}
}
signal.start(next: { [weak self] result, finalState in
if let strongSelf = self {
if case let .processUpdateGroups(groups) = strongSelf.operations.removeFirst() {
if result && !finalState.shouldPoll {
let events = AccountFinalStateEvents(state: finalState.state)
if !events.isEmpty {
strongSelf.addEvents(events)
}
if finalState.incomplete {
strongSelf.operations.insert(.collectUpdateGroups(groups, 2.0), at: 0)
}
} else {
strongSelf.operations.removeAll()
strongSelf.operations.append(.pollDifference(AccountFinalStateEvents()))
}
strongSelf.startFirstOperation()
} else {
assertionFailure()
}
}
}, error: { _ in
assertionFailure()
trace("AccountStateManager", what: "processUpdateGroups signal completed with error")
})
case let .custom(signal):
let completed: () -> Void = { [weak self] in
if let strongSelf = self {
if case .custom = strongSelf.operations.removeFirst() {
strongSelf.startFirstOperation()
} else {
assertionFailure()
}
}
}
signal.start(error: { _ in
completed()
}, completed: {
completed()
})
}
}
private func addEvents(_ events: AccountFinalStateEvents) {
if !events.addedIncomingMessageIds.isEmpty {
(self.account.postbox.modify { modifier -> [Message] in
let timestamp = Int32(self.account.network.context.globalTime())
var messages: [Message] = []
for id in events.addedIncomingMessageIds {
var notify = true
if let notificationSettings = modifier.getPeerNotificationSettings(id.peerId) as? TelegramPeerNotificationSettings {
switch notificationSettings.muteState {
case let .muted(until):
if until >= timestamp {
notify = false
}
case .unmuted:
break
}
} else {
trace("AccountStateManager", what: "notification settings for \(id.peerId) are undefined")
}
var foundReadState = false
if let readStates = modifier.getPeerReadStates(id.peerId) {
for (namespace, readState) in readStates {
if namespace == id.namespace {
if id.id <= readState.maxIncomingReadId {
notify = false
}
foundReadState = true
break
}
}
}
if !foundReadState {
trace("AccountStateManager", what: "read state for \(id.peerId) is undefined")
}
if notify {
if let message = modifier.getMessage(id) {
messages.append(message)
} else {
trace("AccountStateManager", what: "notification message doesn't exist")
}
}
}
return messages
}).start(next: { [weak self] messages in
if let strongSelf = self {
for message in messages {
print("notify: \(message.peers[message.id.peerId]?.displayTitle): \(message.text)")
}
strongSelf.notificationMessagesPipe.putNext(messages)
}
})
}
}
}

View File

@ -261,27 +261,27 @@ public final class AccountViewTracker {
}) })
} }
public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { public func aroundUnreadMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account { if let account = self.account {
let signal = account.postbox.aroundUnreadMessageHistoryViewForPeerId(peerId, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask) let signal = account.postbox.aroundUnreadMessageHistoryViewForPeerId(peerId, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
return wrappedMessageHistorySignal(signal) return wrappedMessageHistorySignal(signal)
} else { } else {
return .never() return .never()
} }
} }
public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account { if let account = self.account {
let signal = account.postbox.aroundIdMessageHistoryViewForPeerId(peerId, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask) let signal = account.postbox.aroundIdMessageHistoryViewForPeerId(peerId, count: count, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
return wrappedMessageHistorySignal(signal) return wrappedMessageHistorySignal(signal)
} else { } else {
return .never() return .never()
} }
} }
public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, tagMask: MessageTags? = nil, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account { if let account = self.account {
let signal = account.postbox.aroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: anchorIndex, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask) let signal = account.postbox.aroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: anchorIndex, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, additionalData: additionalData)
return wrappedMessageHistorySignal(signal) return wrappedMessageHistorySignal(signal)
} else { } else {
return .never() return .never()

View File

@ -23,7 +23,7 @@ private func applyMediaResourceChanges(from: Media, to: Media, postbox: Postbox)
} }
} }
func applyUpdateMessage(postbox: Postbox, stateManager: StateManager, message: Message, result: Api.Updates) -> Signal<Void, NoError> { func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, message: Message, result: Api.Updates) -> Signal<Void, NoError> {
let messageId = result.rawMessageIds.first let messageId = result.rawMessageIds.first
let apiMessage = result.messages.first let apiMessage = result.messages.first

View File

@ -7,7 +7,7 @@ import Foundation
import SwiftSignalKit import SwiftSignalKit
#endif #endif
func managedServiceViews(network: Network, postbox: Postbox, stateManager: StateManager, pendingMessageManager: PendingMessageManager) -> Signal<Void, NoError> { func managedServiceViews(network: Network, postbox: Postbox, stateManager: AccountStateManager, pendingMessageManager: PendingMessageManager) -> Signal<Void, NoError> {
return Signal { _ in return Signal { _ in
let disposable = DisposableSet() let disposable = DisposableSet()
disposable.add(managedMessageHistoryHoles(network: network, postbox: postbox).start()) disposable.add(managedMessageHistoryHoles(network: network, postbox: postbox).start())

View File

@ -39,7 +39,7 @@ private final class ManagedSynchronizePeerReadStatesState {
} }
} }
func managedSynchronizePeerReadStates(network: Network, postbox: Postbox, stateManager: StateManager) -> Signal<Void, NoError> { func managedSynchronizePeerReadStates(network: Network, postbox: Postbox, stateManager: AccountStateManager) -> Signal<Void, NoError> {
return Signal { _ in return Signal { _ in
let state = Atomic(value: ManagedSynchronizePeerReadStatesState()) let state = Atomic(value: ManagedSynchronizePeerReadStatesState())

View File

@ -133,6 +133,13 @@ func initializedNetwork(datacenterId: Int, keychain: Keychain, networkUsageInfoP
let requestService = MTRequestMessageService(context: context)! let requestService = MTRequestMessageService(context: context)!
let connectionStatusDelegate = MTProtoConnectionStatusDelegate() let connectionStatusDelegate = MTProtoConnectionStatusDelegate()
connectionStatusDelegate.action = { [weak connectionStatus] flags in connectionStatusDelegate.action = { [weak connectionStatus] flags in
if flags.contains(.Connected) {
if !flags.intersection([.UpdatingConnectionContext, .PerformingServiceTasks]).isEmpty {
connectionStatus?.set(single(ConnectionStatus.Updating, NoError.self))
} else {
connectionStatus?.set(single(ConnectionStatus.Online, NoError.self))
}
} else {
if !flags.contains(.NetworkAvailable) { if !flags.contains(.NetworkAvailable) {
connectionStatus?.set(single(ConnectionStatus.WaitingForNetwork, NoError.self)) connectionStatus?.set(single(ConnectionStatus.WaitingForNetwork, NoError.self))
} else if !flags.contains(.Connected) { } else if !flags.contains(.Connected) {
@ -143,6 +150,7 @@ func initializedNetwork(datacenterId: Int, keychain: Keychain, networkUsageInfoP
connectionStatus?.set(single(ConnectionStatus.Online, NoError.self)) connectionStatus?.set(single(ConnectionStatus.Online, NoError.self))
} }
} }
}
mtProto.delegate = connectionStatusDelegate mtProto.delegate = connectionStatusDelegate
mtProto.add(requestService) mtProto.add(requestService)

View File

@ -47,7 +47,7 @@ private final class PendingMessageRequestDependencyTag: NetworkRequestDependency
public final class PendingMessageManager { public final class PendingMessageManager {
private let network: Network private let network: Network
private let postbox: Postbox private let postbox: Postbox
private let stateManager: StateManager private let stateManager: AccountStateManager
private let queue = Queue() private let queue = Queue()
@ -57,7 +57,7 @@ public final class PendingMessageManager {
private var peerSummaryContexts: [PeerId: PeerPendingMessagesSummaryContext] = [:] private var peerSummaryContexts: [PeerId: PeerPendingMessagesSummaryContext] = [:]
init(network: Network, postbox: Postbox, stateManager: StateManager) { init(network: Network, postbox: Postbox, stateManager: AccountStateManager) {
self.network = network self.network = network
self.postbox = postbox self.postbox = postbox
self.stateManager = stateManager self.stateManager = stateManager
@ -219,7 +219,7 @@ public final class PendingMessageManager {
})) }))
} }
private func sendMessageContent(network: Network, postbox: Postbox, stateManager: StateManager, message: Message, content: PendingMessageUploadedContent) -> Signal<Void, NoError> { private func sendMessageContent(network: Network, postbox: Postbox, stateManager: AccountStateManager, message: Message, content: PendingMessageUploadedContent) -> Signal<Void, NoError> {
return postbox.modify { [weak self] modifier -> Signal<Void, NoError> in return postbox.modify { [weak self] modifier -> Signal<Void, NoError> in
if let peer = modifier.getPeer(message.id.peerId), let inputPeer = apiInputPeer(peer) { if let peer = modifier.getPeer(message.id.peerId), let inputPeer = apiInputPeer(peer) {
var uniqueId: Int64 = 0 var uniqueId: Int64 = 0
@ -301,7 +301,7 @@ public final class PendingMessageManager {
} |> switchToLatest } |> switchToLatest
} }
private func applySentMessage(postbox: Postbox, stateManager: StateManager, message: Message, result: Api.Updates) -> Signal<Void, NoError> { private func applySentMessage(postbox: Postbox, stateManager: AccountStateManager, message: Message, result: Api.Updates) -> Signal<Void, NoError> {
let messageId = result.rawMessageIds.first let messageId = result.rawMessageIds.first
let apiMessage = result.messages.first let apiMessage = result.messages.first

View File

@ -0,0 +1,36 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
public func requestStartBot(account: Account, botPeerId: PeerId, payload: String?) -> Signal<Void, NoError> {
if let payload = payload, !payload.isEmpty {
return account.postbox.loadedPeerWithId(botPeerId)
|> mapToSignal { botPeer -> Signal<Void, NoError> in
if let inputUser = apiInputUser(botPeer) {
var randomId: Int64 = 0
arc4random_buf(&randomId, 8)
let r = account.network.request(Api.functions.messages.startBot(bot: inputUser, peer: .inputPeerEmpty, randomId: randomId, startParam: payload ?? ""))
|> mapToSignal { result -> Signal<Void, MTRpcError> in
account.stateManager.addUpdates(result)
return .complete()
}
|> `catch` { _ -> Signal<Void, MTRpcError> in
return .complete()
}
return r
|> retryRequest
} else {
return .complete()
}
}
} else {
return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], media: nil, replyToMessageId: nil)])
}
}

View File

@ -46,12 +46,18 @@ final class CachedResolvedByNamePeer: Coding {
private let resolvedByNamePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200) private let resolvedByNamePeersCollectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 150, highWaterItemCount: 200)
public enum ResolvePeerByNameCachedPolicy { public enum ResolvePeerByNameOptionCached {
case remoteIfEarlierThan(timestamp: Int32) case none
case remote case cached
case cachedIfLaterThan(timestamp: Int32)
} }
public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = 60 * 60) -> Signal<PeerId?, NoError> { public enum ResolvePeerByNameOptionRemote {
case updateIfEarlierThan(timestamp: Int32)
case update
}
public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal<PeerId?, NoError> {
var normalizedName = name var normalizedName = name
if normalizedName.hasPrefix("@") { if normalizedName.hasPrefix("@") {
normalizedName = normalizedName.substring(from: name.index(after: name.startIndex)) normalizedName = normalizedName.substring(from: name.index(after: name.startIndex))

View File

@ -31,9 +31,22 @@ private func locallyRenderedMessage(message: StoreMessage, peers: [PeerId: Peer]
return Message(stableId: 0, stableVersion: 0, id: id, timestamp: message.timestamp, flags: MessageFlags(message.flags), tags: message.tags, forwardInfo: nil, author: author, text: message.text, attributes: message.attributes, media: message.media, peers: messagePeers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) return Message(stableId: 0, stableVersion: 0, id: id, timestamp: message.timestamp, flags: MessageFlags(message.flags), tags: message.tags, forwardInfo: nil, author: author, text: message.text, attributes: message.attributes, media: message.media, peers: messagePeers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
} }
public func searchMessages(account: Account, query: String) -> Signal<[Message], NoError> { public func searchMessages(account: Account, peerId: PeerId?, query: String) -> Signal<[Message], NoError> {
let searchResult = account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64)) let searchResult: Signal<Api.messages.Messages, NoError>
if let peerId = peerId {
searchResult = account.postbox.loadedPeerWithId(peerId)
|> mapToSignal { peer -> Signal<Api.messages.Messages, NoError> in
if let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.search(flags: 0, peer: inputPeer, q: query, filter: .inputMessagesFilterEmpty, minDate: 0, maxDate: Int32.max - 1, offset: 0, maxId: Int32.max - 1, limit: 64))
|> retryRequest |> retryRequest
} else {
return .never()
}
}
} else {
searchResult = account.network.request(Api.functions.messages.searchGlobal(q: query, offsetDate: 0, offsetPeer: Api.InputPeer.inputPeerEmpty, offsetId: 0, limit: 64))
|> retryRequest
}
let processedSearchResult = searchResult let processedSearchResult = searchResult
|> mapToSignal { result -> Signal<[Message], NoError> in |> mapToSignal { result -> Signal<[Message], NoError> in

View File

@ -39,7 +39,7 @@ private func applyMediaResourceChanges(from: Media, to: Media, postbox: Postbox)
} }
} }
func sendUnsentMessage(network: Network, postbox: Postbox, stateManager: StateManager, message: Message) -> Signal<Void, NoError> { func sendUnsentMessage(network: Network, postbox: Postbox, stateManager: AccountStateManager, message: Message) -> Signal<Void, NoError> {
return postbox.loadedPeerWithId(message.id.peerId) return postbox.loadedPeerWithId(message.id.peerId)
|> take(1) |> take(1)
|> mapToSignal { peer -> Signal<Void, NoError> in |> mapToSignal { peer -> Signal<Void, NoError> in

View File

@ -149,7 +149,7 @@ private func localReadStateMarker(network: Network, postbox: Postbox, peerId: Pe
} }
} }
private func validatePeerReadState(network: Network, postbox: Postbox, stateManager: StateManager, peerId: PeerId) -> Signal<Void, NoError> { private func validatePeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Signal<Void, NoError> {
let readStateWithInitialState = localReadStateMarker(network: network, postbox: postbox, peerId: peerId) let readStateWithInitialState = localReadStateMarker(network: network, postbox: postbox, peerId: peerId)
|> mapToSignal { marker -> Signal<(PeerReadState, PeerReadStateMarker, PeerReadStateMarker), VerifyReadStateError> in |> mapToSignal { marker -> Signal<(PeerReadState, PeerReadStateMarker, PeerReadStateMarker), VerifyReadStateError> in
return dialogReadState(network: network, postbox: postbox, peerId: peerId) return dialogReadState(network: network, postbox: postbox, peerId: peerId)
@ -157,7 +157,7 @@ private func validatePeerReadState(network: Network, postbox: Postbox, stateMana
} }
let maybeAppliedReadState = readStateWithInitialState |> mapToSignal { (readState, initialMarker, finalMarker) -> Signal<Void, VerifyReadStateError> in let maybeAppliedReadState = readStateWithInitialState |> mapToSignal { (readState, initialMarker, finalMarker) -> Signal<Void, VerifyReadStateError> in
return stateManager.injectedStateModification(postbox.modify { modifier -> VerifyReadStateError? in return stateManager.addCustomOperation(postbox.modify { modifier -> VerifyReadStateError? in
if initialMarker == finalMarker { if initialMarker == finalMarker {
modifier.resetIncomingReadStates([peerId: [Namespaces.Message.Cloud: readState]]) modifier.resetIncomingReadStates([peerId: [Namespaces.Message.Cloud: readState]])
return nil return nil
@ -186,7 +186,7 @@ private func validatePeerReadState(network: Network, postbox: Postbox, stateMana
|> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) |> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue())
} }
private func pushPeerReadState(network: Network, postbox: Postbox, peerId: PeerId, readState: PeerReadState) -> Signal<PeerReadState, VerifyReadStateError> { private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId, readState: PeerReadState) -> Signal<PeerReadState, VerifyReadStateError> {
return inputPeer(postbox: postbox, peerId: peerId) return inputPeer(postbox: postbox, peerId: peerId)
|> mapToSignal { inputPeer -> Signal<PeerReadState, VerifyReadStateError> in |> mapToSignal { inputPeer -> Signal<PeerReadState, VerifyReadStateError> in
switch inputPeer { switch inputPeer {
@ -199,14 +199,19 @@ private func pushPeerReadState(network: Network, postbox: Postbox, peerId: PeerI
default: default:
return network.request(Api.functions.messages.readHistory(peer: inputPeer, maxId: readState.maxIncomingReadId)) return network.request(Api.functions.messages.readHistory(peer: inputPeer, maxId: readState.maxIncomingReadId))
|> retryRequest |> retryRequest
|> mapToSignalPromotingError { _ -> Signal<PeerReadState, VerifyReadStateError> in |> mapToSignalPromotingError { result -> Signal<PeerReadState, VerifyReadStateError>
in
switch result {
case let .affectedMessages(pts, ptsCount):
stateManager.addUpdateGroups([.updatePts(pts: pts, ptsCount: ptsCount)])
}
return .single(readState) return .single(readState)
} }
} }
} }
} }
private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: StateManager, peerId: PeerId) -> Signal<Void, NoError> { private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId) -> Signal<Void, NoError> {
let currentReadState = postbox.modify { modifier -> PeerReadState? in let currentReadState = postbox.modify { modifier -> PeerReadState? in
if let readStates = modifier.getPeerReadStates(peerId) { if let readStates = modifier.getPeerReadStates(peerId) {
for (namespace, readState) in readStates { for (namespace, readState) in readStates {
@ -221,7 +226,7 @@ private func pushPeerReadState(network: Network, postbox: Postbox, stateManager:
let pushedState = currentReadState let pushedState = currentReadState
|> mapToSignalPromotingError { readState -> Signal<PeerReadState, VerifyReadStateError> in |> mapToSignalPromotingError { readState -> Signal<PeerReadState, VerifyReadStateError> in
if let readState = readState { if let readState = readState {
return pushPeerReadState(network: network, postbox: postbox, peerId: peerId, readState: readState) return pushPeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId, readState: readState)
} else { } else {
return .complete() return .complete()
} }
@ -229,7 +234,7 @@ private func pushPeerReadState(network: Network, postbox: Postbox, stateManager:
let verifiedState = pushedState let verifiedState = pushedState
|> mapToSignal { readState -> Signal<Void, VerifyReadStateError> in |> mapToSignal { readState -> Signal<Void, VerifyReadStateError> in
return stateManager.injectedStateModification(postbox.modify { modifier -> VerifyReadStateError? in return stateManager.addCustomOperation(postbox.modify { modifier -> VerifyReadStateError? in
if let readStates = modifier.getPeerReadStates(peerId) { if let readStates = modifier.getPeerReadStates(peerId) {
for (namespace, currentReadState) in readStates where namespace == Namespaces.Message.Cloud { for (namespace, currentReadState) in readStates where namespace == Namespaces.Message.Cloud {
if currentReadState == readState { if currentReadState == readState {
@ -264,7 +269,7 @@ private func pushPeerReadState(network: Network, postbox: Postbox, stateManager:
|> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue()) |> retry(0.1, maxDelay: 5.0, onQueue: Queue.concurrentDefaultQueue())
} }
func synchronizePeerReadState(network: Network, postbox: Postbox, stateManager: StateManager, peerId: PeerId, push: Bool, validate: Bool) -> Signal<Void, NoError> { func synchronizePeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId, push: Bool, validate: Bool) -> Signal<Void, NoError> {
var signal: Signal<Void, NoError> = .complete() var signal: Signal<Void, NoError> = .complete()
if push { if push {
signal = signal |> then(pushPeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId)) signal = signal |> then(pushPeerReadState(network: network, postbox: postbox, stateManager: stateManager, peerId: peerId))

View File

@ -101,7 +101,7 @@ public struct MessageTextEntity: Coding, Equatable {
public let range: Range<Int> public let range: Range<Int>
public let type: MessageTextEntityType public let type: MessageTextEntityType
init(range: Range<Int>, type: MessageTextEntityType) { public init(range: Range<Int>, type: MessageTextEntityType) {
self.range = range self.range = range
self.type = type self.type = type
} }
@ -191,7 +191,7 @@ public class TextEntitiesMessageAttribute: MessageAttribute, Equatable {
return result return result
} }
init(entities: [MessageTextEntity]) { public init(entities: [MessageTextEntity]) {
self.entities = entities self.entities = entities
} }