diff --git a/CHANGES.rst b/CHANGES.rst index 7631da19c2..c9cba85347 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,18 @@ +Changes in Matrix iOS SDK in 0.11.2 (2018-08-24) +=============================================== + +Improvements: + * MXSession: Add the supportedMatrixVersions method getting versions of the specification supported by the homeserver. + * MXRestClient: Add testUserRegistration to check earlier if a username can be registered. + * MXSession: Add MXSessionStateSyncError state and MXSession.syncError to manage homeserver resource quota on /sync requests (vector-im/riot-ios/issues/1937). + * MXError: Add kMXErrCodeStringResourceLimitExceeded to manage homeserver resource quota (vector-im/riot-ios/issues/1937). + * MXError: Define constant strings for keys and values that can be found in a Matrix JSON dictionary error. + * Tests: MXHTTPClient_Private.h: Add method to set fake delay in HTTP requests. + +Bug fix: + * People tab is empty in the share extension (vector-im/riot-ios/issues/1988). + * MXError: MXError lost NSError.userInfo information. + Changes in Matrix iOS SDK in 0.11.1 (2018-08-17) =============================================== diff --git a/MatrixSDK.podspec b/MatrixSDK.podspec index e83b0f5d46..0008457d18 100644 --- a/MatrixSDK.podspec +++ b/MatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "MatrixSDK" - s.version = "0.11.1" + s.version = "0.11.2" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC @@ -54,29 +54,11 @@ Pod::Spec.new do |s| # Use WebRTC build at https://github.com/Anakros/WebRTC instead ss.ios.dependency 'WebRTC', '63.11.20455' end - - s.subspec 'GoogleAnalytics' do |ss| - ss.ios.deployment_target = "8.0" - - ss.source_files = "MatrixSDKExtensions/MXAnalyticsDelegate/GoogleAnalytics/**/*.{h,m}" - - ss.dependency 'MatrixSDK/Core' - - ss.ios.dependency 'GoogleAnalytics' - end -# -# This podspec has been disabled because it prevents from publishing the whole pod. -# pod lint returns: -# -# - ERROR | [iOS] [MatrixSDK/SwiftSupport] unknown: Encountered an unknown error (The following Swift pods cannot yet be integrated as static libraries: -# -# The Swift pod `MatrixSDK` depends upon `AFNetworking`, `GZIP`, `OLMKit`, and `Realm`, which do not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set `use_modular_headers!` globally in your Podfile, or specify `:modular_headers => true` for particular dependencies.) during validation. -# -# s.subspec 'SwiftSupport' do |ss| -# ss.source_files = "MatrixSDK", "MatrixSDK/**/*.{swift}" -# -# ss.dependency 'MatrixSDK/Core' -# end + s.subspec 'SwiftSupport' do |ss| + ss.source_files = "MatrixSDK", "MatrixSDK/**/*.{swift}" + + ss.dependency 'MatrixSDK/Core' + end end diff --git a/MatrixSDK.xcodeproj/project.pbxproj b/MatrixSDK.xcodeproj/project.pbxproj index 787abfa779..e3050c424a 100644 --- a/MatrixSDK.xcodeproj/project.pbxproj +++ b/MatrixSDK.xcodeproj/project.pbxproj @@ -59,6 +59,8 @@ 323EF7471C7CB4C7000DC98C /* MXEventTimelineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 323EF7461C7CB4C7000DC98C /* MXEventTimelineTests.m */; }; 323F3F9320D3F0C700D26D6A /* MXRoomEventFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 323F3F9120D3F0C700D26D6A /* MXRoomEventFilter.m */; }; 323F3F9420D3F0C700D26D6A /* MXRoomEventFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F3F9220D3F0C700D26D6A /* MXRoomEventFilter.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 323F8864212D4E470001C73C /* MXMatrixVersions.h in Headers */ = {isa = PBXBuildFile; fileRef = 323F8862212D4E470001C73C /* MXMatrixVersions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 323F8865212D4E480001C73C /* MXMatrixVersions.m in Sources */ = {isa = PBXBuildFile; fileRef = 323F8863212D4E470001C73C /* MXMatrixVersions.m */; }; 324095221AFA432F00D81C97 /* MXCallStackCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3240951E1AFA432F00D81C97 /* MXCallStackCall.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3240969D1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 3240969B1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.h */; }; 3240969E1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m in Sources */ = {isa = PBXBuildFile; fileRef = 3240969C1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m */; }; @@ -337,6 +339,7 @@ 322A51C51D9BBD3C00C8536D /* MXOlmDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXOlmDevice.h; sourceTree = ""; }; 322A51C61D9BBD3C00C8536D /* MXOlmDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXOlmDevice.m; sourceTree = ""; }; 322A51D71D9E846800C8536D /* MXCryptoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXCryptoTests.m; sourceTree = ""; }; + 322DB456212EB8E600F4EFE9 /* MXHTTPClient_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXHTTPClient_Private.h; sourceTree = ""; }; 32322A471E57264E005DD155 /* MXSelfSignedHomeserverTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXSelfSignedHomeserverTests.m; sourceTree = ""; }; 32322A491E575F65005DD155 /* MXAllowedCertificates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXAllowedCertificates.h; sourceTree = ""; }; 32322A4A1E575F65005DD155 /* MXAllowedCertificates.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXAllowedCertificates.m; sourceTree = ""; }; @@ -348,6 +351,8 @@ 323EF7461C7CB4C7000DC98C /* MXEventTimelineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXEventTimelineTests.m; sourceTree = ""; }; 323F3F9120D3F0C700D26D6A /* MXRoomEventFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MXRoomEventFilter.m; sourceTree = ""; }; 323F3F9220D3F0C700D26D6A /* MXRoomEventFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXRoomEventFilter.h; sourceTree = ""; }; + 323F8862212D4E470001C73C /* MXMatrixVersions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXMatrixVersions.h; sourceTree = ""; }; + 323F8863212D4E470001C73C /* MXMatrixVersions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXMatrixVersions.m; sourceTree = ""; }; 3240951E1AFA432F00D81C97 /* MXCallStackCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MXCallStackCall.h; sourceTree = ""; }; 3240969B1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MXPushRuleSenderNotificationPermissionConditionChecker.h; sourceTree = ""; }; 3240969C1F9F751600DBA607 /* MXPushRuleSenderNotificationPermissionConditionChecker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MXPushRuleSenderNotificationPermissionConditionChecker.m; sourceTree = ""; }; @@ -676,6 +681,7 @@ F03EF5021DF01596009DF592 /* MXLRUCache.h */, F03EF5031DF01596009DF592 /* MXLRUCache.m */, 320DFDD719DD99B60068622A /* MXHTTPClient.h */, + 322DB456212EB8E600F4EFE9 /* MXHTTPClient_Private.h */, 320DFDD819DD99B60068622A /* MXHTTPClient.m */, 32CAB1091A925B41008C5BB9 /* MXHTTPOperation.h */, 32CAB10A1A925B41008C5BB9 /* MXHTTPOperation.m */, @@ -847,6 +853,8 @@ B17982F22119E4A1001FD722 /* MXRoomCreateContent.m */, B17982EF2119E49F001FD722 /* MXRoomPredecessorInfo.h */, B17982F32119E4A1001FD722 /* MXRoomPredecessorInfo.m */, + 323F8862212D4E470001C73C /* MXMatrixVersions.h */, + 323F8863212D4E470001C73C /* MXMatrixVersions.m */, ); path = JSONModels; sourceTree = ""; @@ -1223,6 +1231,7 @@ 3245A7521AF7B2930001D8A7 /* MXCallManager.h in Headers */, C6FE1EF01E65C4F7008587E4 /* MXAnalyticsDelegate.h in Headers */, 92634B7F1EF2A37A00DB9F60 /* MXCallAudioSessionConfigurator.h in Headers */, + 323F8864212D4E470001C73C /* MXMatrixVersions.h in Headers */, 3291D4D41A68FFEB00C3BA41 /* MXFileRoomStore.h in Headers */, 320BBF431D6C81550079890E /* MXEventsEnumeratorOnArray.h in Headers */, 32B76EA320FDE2BE00B095F6 /* MXRoomMembersCount.h in Headers */, @@ -1536,6 +1545,7 @@ F0C34CBB1C18C93700C36F09 /* MXSDKOptions.m in Sources */, 320BBF441D6C81550079890E /* MXEventsEnumeratorOnArray.m in Sources */, 32618E7220ED2DF500E1D2EA /* MXFilterJSONModel.m in Sources */, + 323F8865212D4E480001C73C /* MXMatrixVersions.m in Sources */, 320DFDDC19DD99B60068622A /* MXRoom.m in Sources */, F08B8D5D1E014711006171A8 /* NSData+MatrixSDK.m in Sources */, 3291D4D51A68FFEB00C3BA41 /* MXFileRoomStore.m in Sources */, diff --git a/MatrixSDK/Data/MXRoom.m b/MatrixSDK/Data/MXRoom.m index c4ba5da232..e6a0b597ef 100644 --- a/MatrixSDK/Data/MXRoom.m +++ b/MatrixSDK/Data/MXRoom.m @@ -233,10 +233,41 @@ - (MXHTTPOperation*)members:(void (^)(MXRoomMembers *members))success self->pendingMembersRequesters = [NSMutableArray array]; // Else get them from the homeserver + NSDictionary *parameters; + if (self.mxSession.store.eventStreamToken) + { + parameters = @{ + kMXMembersOfRoomParametersAt: self.mxSession.store.eventStreamToken + }; + } + MXWeakify(self); - MXHTTPOperation *operation2 = [self.mxSession.matrixRestClient membersOfRoom:self.roomId success:^(NSArray *roomMemberEvents) { + MXHTTPOperation *operation2 = [self.mxSession.matrixRestClient membersOfRoom:self.roomId + withParameters:parameters + success:^(NSArray *roomMemberEvents) + { MXStrongifyAndReturnIfNil(self); + // Manage the possible race condition where we could have received + // update of members from the events stream (/sync) while the /members + // request was pending. + // In that case, the response of /members is not up-to-date. We must not + // use this response as is. + // To fix that: + // - we consider that all lazy-loaded members are up-to-date + // - we ignore in the /member response all member events corresponding + // to these already lazy-loaded members + NSMutableArray *updatedRoomMemberEvents = [NSMutableArray array]; + for (MXEvent *roomMemberEvent in roomMemberEvents) + { + if (![liveTimeline.state.members memberWithUserId:roomMemberEvent.stateKey]) + { + // User not lazy loaded yet, keep their member event from /members response + [updatedRoomMemberEvents addObject:roomMemberEvent]; + } + } + roomMemberEvents = updatedRoomMemberEvents; + [liveTimeline handleLazyLoadedStateEvents:roomMemberEvents]; [self.mxSession.store storeHasLoadedAllRoomMembersForRoom:self.roomId andValue:YES]; @@ -2820,20 +2851,8 @@ - (BOOL)isDirect - (NSString *)directUserId { - NSString *directUserId; - // Get the information from the user account data that is managed by MXSession - NSDictionary*> *directRooms = self.mxSession.directRooms; - for (NSString *userId in directRooms) - { - if ([directRooms[userId] containsObject:_roomId]) - { - directUserId = userId; - break; - } - } - - return directUserId; + return [self.mxSession directUserIdInRoom:_roomId]; } - (MXHTTPOperation*)setIsDirect:(BOOL)isDirect diff --git a/MatrixSDK/Data/MXRoomSummary.h b/MatrixSDK/Data/MXRoomSummary.h index 5abe21adbc..600827dc3b 100644 --- a/MatrixSDK/Data/MXRoomSummary.h +++ b/MatrixSDK/Data/MXRoomSummary.h @@ -267,7 +267,7 @@ FOUNDATION_EXPORT NSString *const kMXRoomSummaryDidChangeNotification; The user identifier for whom this room is tagged as direct (if any). nil if the room is not a direct chat. */ -@property (nonatomic, readonly) NSString *directUserId; +@property (nonatomic) NSString *directUserId; /** Placeholder to store more information in the room summary. diff --git a/MatrixSDK/Data/MXRoomSummary.m b/MatrixSDK/Data/MXRoomSummary.m index 0c048377f8..b3be4538e3 100644 --- a/MatrixSDK/Data/MXRoomSummary.m +++ b/MatrixSDK/Data/MXRoomSummary.m @@ -374,11 +374,6 @@ - (NSUInteger)localUnreadEventCount return [_mxSession.store localUnreadEventCount:_roomId withTypeIn:_mxSession.unreadEventTypes]; } -- (NSString *)directUserId -{ - return self.room.directUserId; -} - - (BOOL)isDirect { return (self.directUserId != nil); @@ -545,6 +540,7 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder _isEncrypted = [aDecoder decodeBoolForKey:@"isEncrypted"]; _notificationCount = (NSUInteger)[aDecoder decodeIntegerForKey:@"notificationCount"]; _highlightCount = (NSUInteger)[aDecoder decodeIntegerForKey:@"highlightCount"]; + _directUserId = [aDecoder decodeObjectForKey:@"directUserId"]; _lastMessageEventId = [aDecoder decodeObjectForKey:@"lastMessageEventId"]; _lastMessageOriginServerTs = [aDecoder decodeInt64ForKey:@"lastMessageOriginServerTs"]; @@ -586,6 +582,7 @@ - (void)encodeWithCoder:(NSCoder *)aCoder [aCoder encodeBool:_isEncrypted forKey:@"isEncrypted"]; [aCoder encodeInteger:(NSInteger)_notificationCount forKey:@"notificationCount"]; [aCoder encodeInteger:(NSInteger)_highlightCount forKey:@"highlightCount"]; + [aCoder encodeObject:_directUserId forKey:@"directUserId"]; // Store last message metadata [aCoder encodeObject:_lastMessageEventId forKey:@"lastMessageEventId"]; diff --git a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m index 62f2391bb4..bef1550dae 100644 --- a/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m +++ b/MatrixSDK/Data/Store/MXFileStore/MXFileStore.m @@ -25,7 +25,7 @@ #import "MXSDKOptions.h" #import "MXTools.h" -static NSUInteger const kMXFileVersion = 57; +static NSUInteger const kMXFileVersion = 58; static NSString *const kMXFileStoreFolder = @"MXFileStore"; static NSString *const kMXFileStoreMedaDataFile = @"MXFileStore"; diff --git a/MatrixSDK/JSONModels/MXJSONModels.h b/MatrixSDK/JSONModels/MXJSONModels.h index 6c568bbf3c..23b0b5f050 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.h +++ b/MatrixSDK/JSONModels/MXJSONModels.h @@ -416,6 +416,7 @@ FOUNDATION_EXPORT NSString *const kMXLoginIdentifierTypePhone; */ FOUNDATION_EXPORT NSString *const kMXRoomTagFavourite; FOUNDATION_EXPORT NSString *const kMXRoomTagLowPriority; +FOUNDATION_EXPORT NSString *const kMXRoomTagServerNotice; /** `MXRoomTag` represents a room tag. diff --git a/MatrixSDK/JSONModels/MXJSONModels.m b/MatrixSDK/JSONModels/MXJSONModels.m index dab65c073b..60bafd3225 100644 --- a/MatrixSDK/JSONModels/MXJSONModels.m +++ b/MatrixSDK/JSONModels/MXJSONModels.m @@ -343,6 +343,7 @@ + (id)modelFromJSON:(NSDictionary *)JSONDictionary NSString *const kMXRoomTagFavourite = @"m.favourite"; NSString *const kMXRoomTagLowPriority = @"m.lowpriority"; +NSString *const kMXRoomTagServerNotice = @"m.server_notice"; @interface MXRoomTag() { diff --git a/MatrixSDK/JSONModels/MXMatrixVersions.h b/MatrixSDK/JSONModels/MXMatrixVersions.h new file mode 100644 index 0000000000..d75b1c9513 --- /dev/null +++ b/MatrixSDK/JSONModels/MXMatrixVersions.h @@ -0,0 +1,53 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import +#import "MXJSONModel.h" + +/** + Features declared in the matrix specification. + */ +struct MXMatrixVersionsFeatureStruct +{ + // Room members lazy loading + __unsafe_unretained NSString * const lazyLoadMembers; +}; +extern const struct MXMatrixVersionsFeatureStruct MXMatrixVersionsFeature; + +/** + `MXMatrixVersions` represents the versions of the Matrix specification supported + by the home server. + It is returned by the /versions API. + */ +@interface MXMatrixVersions : MXJSONModel + +/** + The versions supported by the server. + */ +@property (nonatomic) NSArray *versions; + +/** + The unstable features supported by the server. + + */ +@property (nonatomic) NSDictionary *unstableFeatures; + +/** + Check whether the server supports the room members lazy loading. + */ +@property (nonatomic, readonly) BOOL supportLazyLoadMembers; + +@end diff --git a/MatrixSDK/JSONModels/MXMatrixVersions.m b/MatrixSDK/JSONModels/MXMatrixVersions.m new file mode 100644 index 0000000000..0592196aa0 --- /dev/null +++ b/MatrixSDK/JSONModels/MXMatrixVersions.m @@ -0,0 +1,41 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXMatrixVersions.h" + +const struct MXMatrixVersionsFeatureStruct MXMatrixVersionsFeature = { + .lazyLoadMembers = @"m.lazy_load_members" +}; + +@implementation MXMatrixVersions + ++ (id)modelFromJSON:(NSDictionary *)JSONDictionary +{ + MXMatrixVersions *matrixVersions = [[MXMatrixVersions alloc] init]; + if (matrixVersions) + { + MXJSONModelSetArray(matrixVersions.versions, JSONDictionary[@"versions"]); + MXJSONModelSetDictionary(matrixVersions.unstableFeatures, JSONDictionary[@"unstable_features"]); + } + return matrixVersions; +} + +- (BOOL)supportLazyLoadMembers +{ + return [self.unstableFeatures[MXMatrixVersionsFeature.lazyLoadMembers] boolValue]; +} + +@end diff --git a/MatrixSDK/MXError.h b/MatrixSDK/MXError.h index 96d784163e..2f2fb8563d 100644 --- a/MatrixSDK/MXError.h +++ b/MatrixSDK/MXError.h @@ -43,6 +43,7 @@ FOUNDATION_EXPORT NSString *const kMXErrCodeStringThreePIDNotFound; FOUNDATION_EXPORT NSString *const kMXErrCodeStringServerNotTrusted; FOUNDATION_EXPORT NSString *const kMXErrCodeStringGuestAccessForbidden; FOUNDATION_EXPORT NSString *const kMXErrCodeStringConsentNotGiven; +FOUNDATION_EXPORT NSString *const kMXErrCodeStringResourceLimitExceeded; FOUNDATION_EXPORT NSString *const kMXErrorStringInvalidToken; @@ -51,6 +52,16 @@ FOUNDATION_EXPORT NSString *const kMXErrorStringInvalidToken; */ FOUNDATION_EXPORT NSString *const kMXSDKErrCodeStringMissingParameters; +/** + Keys and values that can be found in a Matrix error JSON dictionary. + */ +FOUNDATION_EXPORT NSString *const kMXErrorCodeKey; +FOUNDATION_EXPORT NSString *const kMXErrorMessageKey; +FOUNDATION_EXPORT NSString *const kMXErrorConsentNotGivenConsentURIKey; +FOUNDATION_EXPORT NSString *const kMXErrorResourceLimitExceededLimitTypeKey; +FOUNDATION_EXPORT NSString *const kMXErrorResourceLimitExceededAdminContactKey; +FOUNDATION_EXPORT NSString *const kMXErrorResourceLimitExceededLimitTypeMonthlyActiveUserValue; + /** `MXError` represents an error sent by the home server. MXErrors are encapsulated in NSError. This class is an helper to create NSError or extract MXError from NSError. diff --git a/MatrixSDK/MXError.m b/MatrixSDK/MXError.m index 89c123b609..aaafd05f61 100644 --- a/MatrixSDK/MXError.m +++ b/MatrixSDK/MXError.m @@ -20,31 +20,39 @@ NSString *const kMXNSErrorDomain = @"org.matrix.sdk"; -NSString *const kMXErrCodeStringForbidden = @"M_FORBIDDEN"; -NSString *const kMXErrCodeStringUnknown = @"M_UNKNOWN"; -NSString *const kMXErrCodeStringUnknownToken = @"M_UNKNOWN_TOKEN"; -NSString *const kMXErrCodeStringBadJSON = @"M_BAD_JSON"; -NSString *const kMXErrCodeStringNotJSON = @"M_NOT_JSON"; -NSString *const kMXErrCodeStringNotFound = @"M_NOT_FOUND"; -NSString *const kMXErrCodeStringLimitExceeded = @"M_LIMIT_EXCEEDED"; -NSString *const kMXErrCodeStringUserInUse = @"M_USER_IN_USE"; -NSString *const kMXErrCodeStringRoomInUse = @"M_ROOM_IN_USE"; -NSString *const kMXErrCodeStringBadPagination = @"M_BAD_PAGINATION"; -NSString *const kMXErrCodeStringUnauthorized = @"M_UNAUTHORIZED"; -NSString *const kMXErrCodeStringOldVersion = @"M_OLD_VERSION"; -NSString *const kMXErrCodeStringUnrecognized = @"M_UNRECOGNIZED"; -NSString *const kMXErrCodeStringLoginEmailURLNotYet = @"M_LOGIN_EMAIL_URL_NOT_YET"; -NSString *const kMXErrCodeStringThreePIDAuthFailed = @"M_THREEPID_AUTH_FAILED"; -NSString *const kMXErrCodeStringThreePIDInUse = @"M_THREEPID_IN_USE"; -NSString *const kMXErrCodeStringThreePIDNotFound = @"M_THREEPID_NOT_FOUND"; -NSString *const kMXErrCodeStringServerNotTrusted = @"M_SERVER_NOT_TRUSTED"; -NSString *const kMXErrCodeStringGuestAccessForbidden= @"M_GUEST_ACCESS_FORBIDDEN"; -NSString *const kMXErrCodeStringConsentNotGiven = @"M_CONSENT_NOT_GIVEN"; +NSString *const kMXErrCodeStringForbidden = @"M_FORBIDDEN"; +NSString *const kMXErrCodeStringUnknown = @"M_UNKNOWN"; +NSString *const kMXErrCodeStringUnknownToken = @"M_UNKNOWN_TOKEN"; +NSString *const kMXErrCodeStringBadJSON = @"M_BAD_JSON"; +NSString *const kMXErrCodeStringNotJSON = @"M_NOT_JSON"; +NSString *const kMXErrCodeStringNotFound = @"M_NOT_FOUND"; +NSString *const kMXErrCodeStringLimitExceeded = @"M_LIMIT_EXCEEDED"; +NSString *const kMXErrCodeStringUserInUse = @"M_USER_IN_USE"; +NSString *const kMXErrCodeStringRoomInUse = @"M_ROOM_IN_USE"; +NSString *const kMXErrCodeStringBadPagination = @"M_BAD_PAGINATION"; +NSString *const kMXErrCodeStringUnauthorized = @"M_UNAUTHORIZED"; +NSString *const kMXErrCodeStringOldVersion = @"M_OLD_VERSION"; +NSString *const kMXErrCodeStringUnrecognized = @"M_UNRECOGNIZED"; +NSString *const kMXErrCodeStringLoginEmailURLNotYet = @"M_LOGIN_EMAIL_URL_NOT_YET"; +NSString *const kMXErrCodeStringThreePIDAuthFailed = @"M_THREEPID_AUTH_FAILED"; +NSString *const kMXErrCodeStringThreePIDInUse = @"M_THREEPID_IN_USE"; +NSString *const kMXErrCodeStringThreePIDNotFound = @"M_THREEPID_NOT_FOUND"; +NSString *const kMXErrCodeStringServerNotTrusted = @"M_SERVER_NOT_TRUSTED"; +NSString *const kMXErrCodeStringGuestAccessForbidden = @"M_GUEST_ACCESS_FORBIDDEN"; +NSString *const kMXErrCodeStringConsentNotGiven = @"M_CONSENT_NOT_GIVEN"; +NSString *const kMXErrCodeStringResourceLimitExceeded = @"M_RESOURCE_LIMIT_EXCEEDED"; NSString *const kMXErrorStringInvalidToken = @"Invalid token"; NSString *const kMXSDKErrCodeStringMissingParameters = @"org.matrix.sdk.missing_parameters"; +NSString *const kMXErrorCodeKey = @"errcode"; +NSString *const kMXErrorMessageKey = @"error"; +NSString *const kMXErrorConsentNotGivenConsentURIKey = @"consent_uri"; +NSString *const kMXErrorResourceLimitExceededLimitTypeKey = @"limit_type"; +NSString *const kMXErrorResourceLimitExceededLimitTypeMonthlyActiveUserValue= @"monthly_active_user"; +NSString *const kMXErrorResourceLimitExceededAdminContactKey = @"admin_contact"; + // Random NSError code // Matrix does not use integer but string for error code @@ -81,6 +89,10 @@ -(id)initWithNSError:(NSError*)nsError { self = [self initWithErrorCode:nsError.userInfo[@"errcode"] error:nsError.userInfo[@"error"]]; + if (self) + { + _userInfo = nsError.userInfo; + } } else { @@ -92,7 +104,7 @@ -(id)initWithNSError:(NSError*)nsError - (NSError *)createNSError { - NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + NSMutableDictionary *userInfo = _userInfo ? [NSMutableDictionary dictionaryWithDictionary:_userInfo] : [NSMutableDictionary dictionary]; if (self.errcode) { diff --git a/MatrixSDK/MXRestClient.h b/MatrixSDK/MXRestClient.h index 4f2793f682..92b01106a2 100644 --- a/MatrixSDK/MXRestClient.h +++ b/MatrixSDK/MXRestClient.h @@ -26,12 +26,13 @@ #import "MXHTTPClient.h" #import "MXEvent.h" +#import "MXError.h" #import "MXRoomEventFilter.h" #import "MXInvite3PID.h" #import "MXEventTimeline.h" #import "MXJSONModels.h" #import "MXFilterJSONModel.h" - +#import "MXMatrixVersions.h" #pragma mark - Constants definitions /** @@ -76,6 +77,12 @@ FOUNDATION_EXPORT NSString *const kMXAccountDataKeyIgnoredUser; */ FOUNDATION_EXPORT NSString *const kMXRestClientErrorDomain; +/** + Parameters that can be used in [MXRestClient membersOfRoom:withParameters:...]. + */ +FOUNDATION_EXPORT NSString *const kMXMembersOfRoomParametersAt; +FOUNDATION_EXPORT NSString *const kMXMembersOfRoomParametersMembership; +FOUNDATION_EXPORT NSString *const kMXMembersOfRoomParametersNotMembership; /** Methods of thumnailing supported by the Matrix content repository. @@ -173,7 +180,34 @@ typedef enum : NSUInteger - (void)close; + +#pragma mark - Server administration +/** + Gets the versions of the specification supported by the server. + + @param success A block object called when the operation succeeds. It provides + the supported spec versions. + @param failure A block object called when the operation fails. + + @return a MXHTTPOperation instance. + */ +- (MXHTTPOperation*)supportedMatrixVersions:(void (^)(MXMatrixVersions *matrixVersions))success + failure:(void (^)(NSError *error))failure; + + #pragma mark - Registration operations +/** + Make a ping to the registration endpoint to detect a possible registration problem earlier. + + @param username the user name to test (This value must not be nil). + @param callback A block object called when the operation is completed. + It provides a MXError to check to verify if the user can be registered. + + @return a MXHTTPOperation instance. + */ +- (MXHTTPOperation*)testUserRegistration:(NSString*)username + callback:(void (^)(MXError *mxError))callback; + /** Check whether a username is already in use. @@ -1184,6 +1218,23 @@ typedef enum : NSUInteger success:(void (^)(NSArray *roomMemberEvents))success failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT; +/** + Get a list of members for this room. + + @param roomId the id of the room. + @param parameters additional parameters for the request. Check kMXMembersOfRoomParameters*. + + @param success A block object called when the operation succeeds. It provides an array of `MXEvent` + objects which type is m.room.member. + @param failure A block object called when the operation fails. + + @return a MXHTTPOperation instance. + */ +- (MXHTTPOperation*)membersOfRoom:(NSString*)roomId + withParameters:(NSDictionary*)parameters + success:(void (^)(NSArray *roomMemberEvents))success + failure:(void (^)(NSError *error))failure ; + /** Get a list of all the current state events for this room. diff --git a/MatrixSDK/MXRestClient.m b/MatrixSDK/MXRestClient.m index ad05cc3ac0..14fa02616e 100644 --- a/MatrixSDK/MXRestClient.m +++ b/MatrixSDK/MXRestClient.m @@ -67,6 +67,13 @@ */ NSString *const kMXRestClientErrorDomain = @"kMXRestClientErrorDomain"; +/** + Parameters that can be used in [MXRestClient membersOfRoom:withParameters:...]. + */ +NSString *const kMXMembersOfRoomParametersAt = @"at"; +NSString *const kMXMembersOfRoomParametersMembership = @"membership"; +NSString *const kMXMembersOfRoomParametersNotMembership = @"not_membership"; + /** Authentication flow: register or login */ @@ -249,21 +256,61 @@ - (NSData*)allowedCertificate return httpClient.allowedCertificate; } + +#pragma mark - Server administration + +- (MXHTTPOperation*)supportedMatrixVersions:(void (^)(MXMatrixVersions *matrixVersions))success + failure:(void (^)(NSError *error))failure +{ + // There is no versioning in the path of this API + NSString *path = @"_matrix/client/versions"; + + MXWeakify(self); + return [httpClient requestWithMethod:@"GET" + path:path + parameters:nil + success:^(NSDictionary *JSONResponse) { + MXStrongifyAndReturnIfNil(self); + + if (success) + { + __block MXMatrixVersions *matrixVersions; + [self dispatchProcessing:^{ + MXJSONModelSetMXJSONModel(matrixVersions, MXMatrixVersions, JSONResponse); + } andCompletion:^{ + success(matrixVersions); + }]; + } + } + failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self dispatchFailure:error inBlock:failure]; + }]; +} + + #pragma mark - Registration operations +- (MXHTTPOperation *)testUserRegistration:(NSString *)username callback:(void (^)(MXError *mxError))callback +{ + // Trigger a fake registration to know whether the user name can be registered + return [self registerWithParameters:@{@"username": username} + success:nil + failure:^(NSError *error) + { + // Retrieve the matrix error back + MXError *mxError = [[MXError alloc] initWithNSError:error]; + callback(mxError); + }]; +} + - (MXHTTPOperation*)isUserNameInUse:(NSString*)username callback:(void (^)(BOOL isUserNameInUse))callback { - // Trigger a fake registration to know whether the user name is available or not. - return [self registerOrLogin:MXAuthActionRegister - parameters:@{@"username": username} - success:nil - failure:^(NSError *error) { - - NSDictionary* dict = error.userInfo; - BOOL isUserNameInUse = ([[dict valueForKey:@"errcode"] isEqualToString:kMXErrCodeStringUserInUse]); - - callback(isUserNameInUse); - }]; + return [self testUserRegistration:username callback:^(MXError *mxError) { + + BOOL isUserNameInUse = ([mxError.errcode isEqualToString:kMXErrCodeStringUserInUse]); + callback(isUserNameInUse); + }]; } - (MXHTTPOperation*)getRegisterSession:(void (^)(MXAuthenticationSession *authSession))success @@ -2108,13 +2155,21 @@ - (MXHTTPOperation*)messagesForRoom:(NSString*)roomId - (MXHTTPOperation*)membersOfRoom:(NSString*)roomId success:(void (^)(NSArray *roomMemberEvents))success failure:(void (^)(NSError *error))failure +{ + return [self membersOfRoom:roomId withParameters:nil success:success failure:failure]; +} + +- (MXHTTPOperation*)membersOfRoom:(NSString*)roomId + withParameters:(NSDictionary*)parameters + success:(void (^)(NSArray *roomMemberEvents))success + failure:(void (^)(NSError *error))failure { NSString *path = [NSString stringWithFormat:@"%@/rooms/%@/members", apiPathPrefix, roomId]; MXWeakify(self); return [httpClient requestWithMethod:@"GET" path:path - parameters:nil + parameters:parameters success:^(NSDictionary *JSONResponse) { MXStrongifyAndReturnIfNil(self); diff --git a/MatrixSDK/MXSession.h b/MatrixSDK/MXSession.h index 190c9cc60a..a237b065a9 100644 --- a/MatrixSDK/MXSession.h +++ b/MatrixSDK/MXSession.h @@ -30,6 +30,7 @@ #import "MXCallManager.h" #import "MXCrypto.h" #import "MXGroup.h" +#import "MXError.h" /** `MXSessionState` represents the states in the life cycle of a MXSession instance. @@ -81,6 +82,15 @@ typedef enum : NSUInteger */ MXSessionStateHomeserverNotReachable, + /** + The homeserver returned a temporary error when trying to sync. + Check `MXSession.syncError` to get this error. + + @discussion + The Matrix session will automatically go back MXSessionStateRunning once possible. + */ + MXSessionStateSyncError, + /** The session has been paused. */ @@ -332,6 +342,11 @@ FOUNDATION_EXPORT NSString *const kMXSessionNoRoomTag; */ @property (nonatomic, readonly) MXSessionState state; +/** + The current state of the session. + */ +@property (nonatomic, readonly) MXError *syncError; + /** The flag indicating whether the initial sync has been done. */ @@ -606,6 +621,17 @@ typedef void (^MXOnBackgroundSyncFail)(NSError *error); */ - (void)enableCrypto:(BOOL)enableCrypto success:(void (^)(void))success failure:(void (^)(NSError *error))failure NS_REFINED_FOR_SWIFT; +/** + Get the versions of the specification supported by the server. + + @param success A block object called when the operation succeeds. It provides + the supported spec versions. + @param failure A block object called when the operation fails. + + @return a MXHTTPOperation instance. + */ +- (MXHTTPOperation*)supportedMatrixVersions:(void (^)(MXMatrixVersions *matrixVersions))success failure:(void (^)(NSError *error))failure; + #pragma mark - Rooms operations /** @@ -764,6 +790,14 @@ typedef void (^MXOnBackgroundSyncFail)(NSError *error); */ - (MXRoom *)directJoinedRoomWithUserId:(NSString*)userId; +/** + Get the direct user id of a room. + + @param roomId the id of the room. + @return the id of user with whom the room is direct to. + */ +- (NSString *)directUserIdInRoom:(NSString*)roomId; + /** Set a room as direct with a user. @@ -781,18 +815,29 @@ typedef void (^MXOnBackgroundSyncFail)(NSError *error); failure:(void (^)(NSError *error))failure; /** - Update the direct rooms list on homeserver side. + Use this method to run or queue any other actions on the direct rooms to avoid race conditions. + Run only one HTTP request in a block. If there is a pending action, the change will be applied + on the updated direct rooms data. + + @param directRoomOperation A block object (use `[uploadDirectRoomsInOperationsQueue:success:failure:]` + in this block if you need to upload the direct rooms dictionary). + */ +- (void)runOrQueueDirectRoomOperation:(dispatch_block_t)directRoomOperation; +/** + Update the direct rooms list on homeserver side. + This method must be called in a block run by using `[runOrQueueDirectRoomOperation:]` + @param directRooms the new direct rooms list (user id -> [room ids]). - + @param success A block object called when the operation succeeds. @param failure A block object called when the operation fails. @return a MXHTTPOperation instance. */ -- (MXHTTPOperation*)uploadDirectRooms:(NSDictionary*> *)directRooms - success:(void (^)(void))success - failure:(void (^)(NSError *error))failure; +- (MXHTTPOperation*)uploadDirectRoomsInOperationsQueue:(NSDictionary *> *)directRooms + success:(void (^)(void))success + failure:(void (^)(NSError *))failure; /** Make sure that the `MXRoom` internal data for a list of rooms is preloaded. diff --git a/MatrixSDK/MXSession.m b/MatrixSDK/MXSession.m index 48254cf31b..76d6afc94e 100644 --- a/MatrixSDK/MXSession.m +++ b/MatrixSDK/MXSession.m @@ -42,7 +42,7 @@ #pragma mark - Constants definitions -const NSString *MatrixSDKVersion = @"0.11.1"; +const NSString *MatrixSDKVersion = @"0.11.2"; NSString *const kMXSessionStateDidChangeNotification = @"kMXSessionStateDidChangeNotification"; NSString *const kMXSessionNewRoomNotification = @"kMXSessionNewRoomNotification"; NSString *const kMXSessionWillLeaveRoomNotification = @"kMXSessionWillLeaveRoomNotification"; @@ -78,6 +78,11 @@ #define SERVER_TIMEOUT_MS 30000 #define CLIENT_TIMEOUT_MS 120000 +/** + Time before retrying in case of `MXSessionStateSyncError`. + */ +#define RETRY_SYNC_AFTER_MXERROR_MS 5000 + // Block called when MSSession resume is complete typedef void (^MXOnResumeDone)(void); @@ -241,6 +246,12 @@ - (void)setState:(MXSessionState)state if (_state != state) { _state = state; + + if (_state != MXSessionStateSyncError) + { + // Reset the sync error + _syncError = nil; + } NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter postNotificationName:kMXSessionStateDidChangeNotification object:self userInfo:nil]; @@ -373,6 +384,8 @@ - (void)startWithSyncFilter:(MXFilterJSONModel*)syncFilter onServerSyncDone:(void (^)(void))onServerSyncDone failure:(void (^)(NSError *error))failure; { + NSLog(@"[MXSession] startWithSyncFilter: %@", syncFilter); + if (syncFilter) { // Build or retrieve the filter before launching the event stream @@ -385,7 +398,7 @@ - (void)startWithSyncFilter:(MXFilterJSONModel*)syncFilter } failure:^(NSError *error) { MXStrongifyAndReturnIfNil(self); - NSLog(@"[MXSesssion] startWithSyncFilter: WARNING: Impossible to create the filter. Use no filter in /sync"); + NSLog(@"[MXSession] startWithSyncFilter: WARNING: Impossible to create the filter. Use no filter in /sync"); [self startWithSyncFilterId:nil onServerSyncDone:onServerSyncDone failure:failure]; }]; } @@ -1023,6 +1036,12 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout } } + if (isInitialSync) + { + // Update summaries direct user ids for retrieved rooms + [self updateSummaryDirectUserIdForRooms:[self directRoomIds]]; + } + // Handle invited groups for (NSString *groupId in syncResponse.groups.invite) { @@ -1178,96 +1197,121 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout }]; } failure:^(NSError *error) { - MXStrongifyAndReturnIfNil(self); - - // Make sure [MXSession close] or [MXSession pause] has not been called before the server response - if (!self->eventStreamRequest) - { - return; - } - - // Check whether the token is valid - if ([self isUnknownTokenError:error]) - { - // Do nothing more because without a valid access_token, the session is useless - return; - } - - // Handle failure during catch up first - if (self->onBackgroundSyncFail) + [self handleServerSyncError:error forRequestWithServerTimeout:serverTimeout success:success failure:failure]; + }]; +} + +- (void)handleServerSyncError:(NSError*)error forRequestWithServerTimeout:(NSUInteger)serverTimeout success:(void (^)(void))success failure:(void (^)(NSError *error))failure +{ + // Make sure [MXSession close] or [MXSession pause] has not been called before the server response + if (!self->eventStreamRequest) + { + return; + } + + // Check whether the token is valid + if ([self isUnknownTokenError:error]) + { + // Do nothing more because without a valid access_token, the session is useless + return; + } + + // Handle failure during catch up first + if (self->onBackgroundSyncFail) + { + NSLog(@"[MXSession] background Sync fails %@", error); + + // Operations on session may occur during this block. For example, [MXSession close] may be triggered. + // We run a copy of the block to prevent app from crashing if the block is released by one of these operations. + MXOnBackgroundSyncFail onBackgroundSyncFailCpy = [self->onBackgroundSyncFail copy]; + onBackgroundSyncFailCpy(error); + self->onBackgroundSyncFail = nil; + + // check that the application was not resumed while catching up in background + if (self.state == MXSessionStateBackgroundSyncInProgress) { - NSLog(@"[MXSession] background Sync fails %@", error); - - // Operations on session may occur during this block. For example, [MXSession close] may be triggered. - // We run a copy of the block to prevent app from crashing if the block is released by one of these operations. - MXOnBackgroundSyncFail onBackgroundSyncFailCpy = [self->onBackgroundSyncFail copy]; - onBackgroundSyncFailCpy(error); - self->onBackgroundSyncFail = nil; - - // check that the application was not resumed while catching up in background - if (self.state == MXSessionStateBackgroundSyncInProgress) + // Check that none required the session to keep running + if (self.preventPauseCount) { - // Check that none required the session to keep running - if (self.preventPauseCount) - { - // Delay the pause by calling the reliable `pause` method. - [self pause]; - } - else - { - NSLog(@"[MXSession] go to paused "); - self->eventStreamRequest = nil; - [self setState:MXSessionStatePaused]; - return; - } + // Delay the pause by calling the reliable `pause` method. + [self pause]; } else { - NSLog(@"[MXSession] resume after a background Sync"); + NSLog(@"[MXSession] go to paused "); + self->eventStreamRequest = nil; + [self setState:MXSessionStatePaused]; + return; } } - - // Check whether the caller wants to handle error himself - if (failure) + else { - failure(error); + NSLog(@"[MXSession] resume after a background Sync"); + } + } + + // Check whether the caller wants to handle error himself + if (failure) + { + failure(error); + } + else + { + // Handle error here + // on 64 bits devices, the error codes are huge integers. + int32_t code = (int32_t)error.code; + + if ([error.domain isEqualToString:NSURLErrorDomain] + && code == kCFURLErrorCancelled) + { + NSLog(@"[MXSession] The connection has been cancelled."); + } + else if ([error.domain isEqualToString:NSURLErrorDomain] + && code == kCFURLErrorTimedOut && serverTimeout == 0) + { + NSLog(@"[MXSession] The connection has been timeout."); + // The reconnection attempt failed on timeout: there is no data to retrieve from server + [self->eventStreamRequest cancel]; + self->eventStreamRequest = nil; + + // Notify the reconnection attempt has been done. + [[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionDidSyncNotification + object:self + userInfo:@{ + kMXSessionNotificationErrorKey: error + }]; + + // Switch back to the long poll management + [self serverSyncWithServerTimeout:SERVER_TIMEOUT_MS success:nil failure:nil clientTimeout:CLIENT_TIMEOUT_MS setPresence:nil]; } else { - // Handle error here - // on 64 bits devices, the error codes are huge integers. - int32_t code = (int32_t)error.code; - - if (code == kCFURLErrorCancelled) - { - NSLog(@"[MXSession] The connection has been cancelled."); - } - else if ((code == kCFURLErrorTimedOut) && serverTimeout == 0) + MXError *mxError = [[MXError alloc] initWithNSError:error]; + if (mxError) { - NSLog(@"[MXSession] The connection has been timeout."); - // The reconnection attempt failed on timeout: there is no data to retrieve from server - [self->eventStreamRequest cancel]; - self->eventStreamRequest = nil; - - // Notify the reconnection attempt has been done. - [[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionDidSyncNotification - object:self - userInfo:@{ - kMXSessionNotificationErrorKey: error - }]; - - // Switch back to the long poll management - [self serverSyncWithServerTimeout:SERVER_TIMEOUT_MS success:nil failure:nil clientTimeout:CLIENT_TIMEOUT_MS setPresence:nil]; + _syncError = mxError; + [self setState:MXSessionStateSyncError]; + + // Retry later + dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, RETRY_SYNC_AFTER_MXERROR_MS * NSEC_PER_MSEC); + dispatch_after(delayTime, dispatch_get_main_queue(), ^(void) { + + if (self->eventStreamRequest) + { + NSLog(@"[MXSession] Retry resuming events stream after error %@", mxError.errcode); + [self serverSyncWithServerTimeout:0 success:success failure:failure clientTimeout:CLIENT_TIMEOUT_MS setPresence:nil]; + } + }); } else { // Inform the app there is a problem with the connection to the homeserver [self setState:MXSessionStateHomeserverNotReachable]; - + // Check if it is a network connectivity issue AFNetworkReachabilityManager *networkReachabilityManager = [AFNetworkReachabilityManager sharedManager]; NSLog(@"[MXSession] events stream broken. Network reachability: %d", networkReachabilityManager.isReachable); - + if (networkReachabilityManager.isReachable) { // The problem is not the network @@ -1276,7 +1320,7 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout // if there is server side issue like server restart dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, [MXHTTPClient timeForRetry:self->eventStreamRequest] * NSEC_PER_MSEC); dispatch_after(delayTime, dispatch_get_main_queue(), ^(void) { - + if (self->eventStreamRequest) { NSLog(@"[MXSession] Retry resuming events stream"); @@ -1290,11 +1334,11 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout // The device is not connected to the internet, wait for the connection to be up again before retrying __block __weak id reachabilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingReachabilityDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - + if (networkReachabilityManager.isReachable && self->eventStreamRequest) { [[NSNotificationCenter defaultCenter] removeObserver:reachabilityObserver]; - + NSLog(@"[MXSession] Retry resuming events stream"); [self setState:MXSessionStateSyncInProgress]; [self serverSyncWithServerTimeout:0 success:success failure:nil clientTimeout:CLIENT_TIMEOUT_MS setPresence:nil]; @@ -1303,7 +1347,7 @@ - (void)serverSyncWithServerTimeout:(NSUInteger)serverTimeout } } } - }]; + } } - (void)handlePresenceEvent:(MXEvent *)event direction:(MXTimelineDirection)direction @@ -1379,8 +1423,18 @@ - (void)handleAccountData:(NSDictionary*)accountDataUpdate if (directRooms != _directRooms && ![directRooms isEqualToDictionary:_directRooms]) { + // Collect previous direct rooms ids + NSMutableSet *directRoomIds = [NSMutableSet set]; + [directRoomIds unionSet:[self directRoomIds]]; + _directRooms = directRooms; + // And collect current ones + [directRoomIds unionSet:[self directRoomIds]]; + + // In order to update room summaries + [self updateSummaryDirectUserIdForRooms:directRoomIds]; + // Update the information of the direct rooms. [[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionDirectRoomsDidChangeNotification object:self @@ -1396,6 +1450,30 @@ - (void)handleAccountData:(NSDictionary*)accountDataUpdate } } +- (void)updateSummaryDirectUserIdForRooms:(NSSet *)roomIds +{ + // If the initial sync response is not processed enough, rooms is not yet mounted. + // updateSummaryDirectUserIdForRooms will be called once the initial sync is done. + if (rooms.count) + { + for (NSString *roomId in roomIds) + { + MXRoomSummary *summary = [self roomSummaryWithRoomId:roomId]; + + NSString *directUserId = [self directUserIdInRoom:roomId]; + NSString *summaryDirectUserId = summary.directUserId; + + // Update the summary if necessary + if (directUserId != summaryDirectUserId + && ![directUserId isEqualToString:summaryDirectUserId]) + { + summary.directUserId = directUserId; + [summary save:YES]; + } + } + } +} + - (void)handleToDeviceEvent:(MXEvent *)event { // Decrypt event if necessary @@ -1483,6 +1561,11 @@ - (void)enableCrypto:(BOOL)enableCrypto success:(void (^)(void))success failure: } } +- (MXHTTPOperation*)supportedMatrixVersions:(void (^)(MXMatrixVersions *))success failure:(void (^)(NSError *))failure +{ + return [matrixRestClient supportedMatrixVersions:success failure:failure]; +} + #pragma mark - Rooms operations @@ -1834,6 +1917,33 @@ - (MXRoom *)directJoinedRoomWithUserId:(NSString*)userId return nil; } +// Return ids of all current direct rooms +- (NSSet *)directRoomIds +{ + NSMutableSet *roomIds = [NSMutableSet set]; + for (NSArray *array in _directRooms.allValues) + { + [roomIds addObjectsFromArray:array]; + } + + return roomIds; +} + +- (NSString *)directUserIdInRoom:(NSString*)roomId +{ + NSString *directUserId; + + for (NSString *userId in _directRooms) + { + if ([_directRooms[userId] containsObject:roomId]) + { + directUserId = userId; + break; + } + } + + return directUserId; +} - (MXHTTPOperation*)setRoom:(NSString*)roomId directWithUserId:(NSString*)userId @@ -1960,10 +2070,9 @@ - (MXHTTPOperation*)uploadDirectRoomsInOperationsQueue:(NSDictionary @@ -39,14 +41,6 @@ NSString* const kMXHTTPClientUserConsentNotGivenErrorNotification = @"kMXHTTPClientUserConsentNotGivenErrorNotification"; NSString* const kMXHTTPClientUserConsentNotGivenErrorNotificationConsentURIKey = @"kMXHTTPClientUserConsentNotGivenErrorNotificationConsentURIKey"; -/** - Matrix error API JSON Keys - */ -static NSString* const kMXErrorCodeJSONKey = @"errcode"; -static NSString* const kMXErrorMessageJSONKey = @"error"; - -static NSString* const kMXErrorConsentNotGivenConsentURIJSONKey = @"consent_uri"; - @interface MXHTTPClient () { @@ -255,7 +249,18 @@ - (void)tryRequest:(MXHTTPOperation*)mxHTTPOperation if (!error) { - success(JSONResponse); + NSUInteger responseDelayMS = [MXHTTPClient delayForRequest:request]; + if (responseDelayMS) + { + NSLog(@"[MXHTTPClient] Delay call of success for request %p", mxHTTPOperation); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, responseDelayMS * USEC_PER_SEC), dispatch_get_main_queue(), ^{ + success(JSONResponse); + }); + } + else + { + success(JSONResponse); + } } else { @@ -270,7 +275,7 @@ - (void)tryRequest:(MXHTTPOperation*)mxHTTPOperation { NSLog(@"[MXHTTPClient] Error JSONResponse: %@", JSONResponse); - if (JSONResponse[kMXErrorCodeJSONKey] || JSONResponse[kMXErrorMessageJSONKey]) + if (JSONResponse[kMXErrorCodeKey] || JSONResponse[kMXErrorMessageKey]) { // Extract values from the home server JSON response MXError *mxError = [self mxErrorFromJSON:JSONResponse]; @@ -311,7 +316,7 @@ - (void)tryRequest:(MXHTTPOperation*)mxHTTPOperation } else if ([mxError.errcode isEqualToString:kMXErrCodeStringConsentNotGiven]) { - NSString* consentURI = mxError.userInfo[kMXErrorConsentNotGivenConsentURIJSONKey]; + NSString* consentURI = mxError.userInfo[kMXErrorConsentNotGivenConsentURIKey]; if (consentURI.length > 0) { @@ -452,7 +457,18 @@ - (void)tryRequest:(MXHTTPOperation*)mxHTTPOperation if (error) { - failure(error); + NSUInteger responseDelayMS = [MXHTTPClient delayForRequest:request]; + if (responseDelayMS) + { + NSLog(@"[MXHTTPClient] Delay call of failure for request %p", mxHTTPOperation); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, responseDelayMS * USEC_PER_SEC), dispatch_get_main_queue(), ^{ + failure(error); + }); + } + else + { + failure(error); + } } // Delay the call of 'cleanupBackgroundTask' in order to let httpManager.tasks.count @@ -718,8 +734,8 @@ - (MXError*)mxErrorFromJSON:(NSDictionary*)json { // Add key/values other than error code and error message in user info NSMutableDictionary *userInfo = [json mutableCopy]; - [userInfo removeObjectForKey:kMXErrorCodeJSONKey]; - [userInfo removeObjectForKey:kMXErrorMessageJSONKey]; + [userInfo removeObjectForKey:kMXErrorCodeKey]; + [userInfo removeObjectForKey:kMXErrorMessageKey]; NSDictionary *mxErrorUserInfo = nil; @@ -727,8 +743,8 @@ - (MXError*)mxErrorFromJSON:(NSDictionary*)json mxErrorUserInfo = [NSDictionary dictionaryWithDictionary:userInfo]; } - return [[MXError alloc] initWithErrorCode:json[kMXErrorCodeJSONKey] - error:json[kMXErrorMessageJSONKey] + return [[MXError alloc] initWithErrorCode:json[kMXErrorCodeKey] + error:json[kMXErrorMessageKey] userInfo:mxErrorUserInfo]; } @@ -765,4 +781,58 @@ + (void)logRequestFailure:(MXHTTPOperation*)mxHTTPOperation #endif } + +#pragma mark - MXHTTPClient_Private +// See MXHTTPClient_Private.h for details ++ (NSMutableDictionary *)delayedRequests +{ + static NSMutableDictionary *delayedRequests; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + delayedRequests = [NSMutableDictionary dictionary]; + }); + return delayedRequests; +} + ++ (void)setDelay:(NSUInteger)delayMs toRequestsContainingString:(NSString *)string +{ + if (string) + { + if (delayMs) + { + [MXHTTPClient delayedRequests][string] = @(delayMs); + } + else + { + [[MXHTTPClient delayedRequests] removeObjectForKey:string]; + } + } +} + ++ (void)removeAllDelays +{ + [[MXHTTPClient delayedRequests] removeAllObjects]; +} + ++ (NSUInteger)delayForRequest:(NSURLRequest*)request +{ + NSUInteger delayMs = 0; + + NSMutableDictionary *delayedRequests = [MXHTTPClient delayedRequests]; + if (delayedRequests.count) + { + NSString *requestString = request.URL.absoluteString; + for (NSString *string in delayedRequests) + { + if ([requestString containsString:string]) + { + delayMs = [delayedRequests[string] unsignedIntegerValue]; + break; + } + } + } + + return delayMs; +} + @end diff --git a/MatrixSDK/Utils/MXHTTPClient_Private.h b/MatrixSDK/Utils/MXHTTPClient_Private.h new file mode 100644 index 0000000000..aa50a084c6 --- /dev/null +++ b/MatrixSDK/Utils/MXHTTPClient_Private.h @@ -0,0 +1,45 @@ +/* + Copyright 2018 New Vector Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "MXHTTPClient.h" + +/** + The `MXHTTPClient_Private` extension exposes internal operations like methods + required for testing. + + Note: These methods are too intrusive. We should implement our own NSURLProtocol + a la OHHTTPStubs and manage only a delay, not stub data. + The issue is that AFNetworking does not use the shared NSURLSessionConfiguration so + that [NSURLProtocol registerClass:] does not work which makes things longer to implement. + + FTR, OHHTTPStubs solves that by doing some swizzling (https://github.com/AliSoftware/OHHTTPStubs/blob/c7c96546db35d5bb15f027b42b9208e57f6c4289/OHHTTPStubs/Sources/NSURLSession/OHHTTPStubs%2BNSURLSessionConfiguration.m#L54). + */ +@interface MXHTTPClient () + +/** + Set a delay in the reponse of requests containing `string` in their path. + + @param delayMs the delay in milliseconds. 0 to remove it. + @param string a pattern in the request path. + */ ++ (void)setDelay:(NSUInteger)delayMs toRequestsContainingString:(NSString*)string; + +/** + Remove all created delays. + */ ++ (void)removeAllDelays; + +@end diff --git a/MatrixSDKTests/DirectRoomTests.m b/MatrixSDKTests/DirectRoomTests.m index 8a510a053b..1f169ac006 100644 --- a/MatrixSDKTests/DirectRoomTests.m +++ b/MatrixSDKTests/DirectRoomTests.m @@ -18,6 +18,7 @@ #import "MatrixSDKTestsData.h" #import "MXSDKOptions.h" +#import "MXFileStore.h" // Do not bother with retain cycles warnings in tests #pragma clang diagnostic push @@ -380,6 +381,130 @@ - (void)testDirectRoomsRaceConditions }]; } +// https://github.com/vector-im/riot-ios/issues/1988 +// - Bob & Alice in a room +// - Bob must have no direct rooms at first +// - Bob set the room as direct +// -> On success the room must be tagged as direct +// -> It must be stored as direct too +- (void)testSummaryStorage +{ + // - Bob & Alice in a room + MXFileStore *store = [[MXFileStore alloc] init]; + [matrixSDKTestsData doMXSessionTestWithBobAndAliceInARoom:self andStore:store readyToTest:^(MXSession *bobSession, MXRestClient *aliceRestClient, NSString *roomId, XCTestExpectation *expectation) { + + // - Bob must have no direct rooms at first + MXRoomSummary *summary = [bobSession roomSummaryWithRoomId:roomId]; + XCTAssertFalse(summary.isDirect); + + // - Bob set the room as direct + MXRoom *room = [bobSession roomWithRoomId:roomId]; + [room setIsDirect:YES withUserId:aliceRestClient.credentials.userId success:^{ + + // -> On success the room must be tagged as direct + XCTAssertEqualObjects(summary.directUserId, aliceRestClient.credentials.userId); + XCTAssertTrue(summary.isDirect); + + [bobSession close]; + + // Check content from the store + [store asyncRoomsSummaries:^(NSArray * _Nonnull roomsSummaries) { + + // Test for checking the test + XCTAssertEqual(roomsSummaries.count, 1); + + // -> It must be stored as direct too + MXRoomSummary *summaryFromStore = roomsSummaries.firstObject; + XCTAssertEqualObjects(summaryFromStore.directUserId, aliceRestClient.credentials.userId); + XCTAssertTrue(summaryFromStore.isDirect); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }]; +} + +// Another test case for https://github.com/vector-im/riot-ios/issues/1988 +// - Bob & Alice in a room +// - Bob set the room as direct +// - Bob does an initial /sync +// -> On success the room must be tagged as direct +// -> It must be stored as direct too +- (void)testSummaryAfterInitialSyncAndStorage +{ + // - Bob & Alice in a room + MXFileStore *store = [[MXFileStore alloc] init]; + [matrixSDKTestsData doMXSessionTestWithBobAndAliceInARoom:self andStore:store readyToTest:^(MXSession *bobSession, MXRestClient *aliceRestClient, NSString *roomId, XCTestExpectation *expectation) { + + // - Bob set the room as direct + MXRoom *room = [bobSession roomWithRoomId:roomId]; + [room setIsDirect:YES withUserId:aliceRestClient.credentials.userId success:^{ + + // - Bob does an initial /sync + MXSession *bobSession2 = [[MXSession alloc] initWithMatrixRestClient:bobSession.matrixRestClient]; + [matrixSDKTestsData retain:bobSession2]; + [bobSession close]; + [store deleteAllData]; + + MXFileStore *store2 = [[MXFileStore alloc] init]; + [bobSession2 setStore:store2 success:^{ + + [bobSession2 start:^{ + + // Test for checking the test + XCTAssertEqualObjects([bobSession2 roomWithRoomId:roomId].directUserId, aliceRestClient.credentials.userId); + + MXRoomSummary *summary = [bobSession2 roomSummaryWithRoomId:roomId]; + + // -> On success the room must be tagged as direct + XCTAssertEqualObjects(summary.directUserId, aliceRestClient.credentials.userId); + XCTAssertTrue(summary.isDirect); + + [bobSession2 close]; + + // Check content from the store + [store2 asyncRoomsSummaries:^(NSArray * _Nonnull roomsSummaries) { + + // Test for checking the test + XCTAssertEqual(roomsSummaries.count, 1); + + // -> It must be stored as direct too + MXRoomSummary *summaryFromStore = roomsSummaries.firstObject; + XCTAssertEqualObjects(summaryFromStore.directUserId, aliceRestClient.credentials.userId); + XCTAssertTrue(summaryFromStore.isDirect); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + }]; +} + @end #pragma clang diagnostic pop diff --git a/MatrixSDKTests/MXLazyLoadingTests.m b/MatrixSDKTests/MXLazyLoadingTests.m index fb9ff33b79..0de752a9c7 100644 --- a/MatrixSDKTests/MXLazyLoadingTests.m +++ b/MatrixSDKTests/MXLazyLoadingTests.m @@ -19,6 +19,8 @@ #import "MatrixSDKTestsData.h" #import "MXSDKOptions.h" +#import "MXHTTPClient_Private.h" + // Do not bother with retain cycles warnings in tests #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" @@ -47,6 +49,7 @@ - (void)setUp - (void)tearDown { [super tearDown]; + [MXHTTPClient removeAllDelays]; matrixSDKTestsData = nil; } @@ -437,6 +440,64 @@ - (void)testRoomMembersWithLazyLoadingOFF [self checkRoomMembersWithLazyLoading:NO]; } +// From the scenario: +// - Alice calls [MXRoom members:] with the underlying HTTP request that will be fakely delayed +// - Bob changes his name +// - [MXRoom members:] completes +// -> Bob name must be correct +- (void)checkRoomMembersRaceConditionsWithLazyLoading:(BOOL)lazyLoading +{ + [self createScenarioWithLazyLoading:lazyLoading readyToTest:^(MXSession *aliceSession, MXSession *bobSession, MXSession *charlieSession, NSString *roomId, XCTestExpectation *expectation) { + + MXRoom *room = [aliceSession roomWithRoomId:roomId]; + [room liveTimeline:^(MXEventTimeline *liveTimeline) { + + NSString *newBobName = @"NewBob"; + + // updatedFromSync is used to check the test itself + __block BOOL updatedFromSync = NO; + [liveTimeline listenToEventsOfTypes:@[kMXEventTypeStringRoomMember] onEvent:^(MXEvent *event, MXTimelineDirection direction, MXRoomState *roomState) { + + if (direction == MXTimelineDirectionForwards) + { + updatedFromSync = YES; + } + }]; + + // - Alice calls [MXRoom members:] with the underlying HTTP request that will be fakely delayed + [MXHTTPClient setDelay:2000 toRequestsContainingString:@"/members"]; + [room members:^(MXRoomMembers *roomMembers) { + + // - [MXRoom members:] completes + XCTAssertTrue(updatedFromSync); + + // -> Bob name must be correct + MXRoomMember *bob = [roomMembers memberWithUserId:bobSession.myUser.userId]; + XCTAssertEqualObjects(bob.displayname, newBobName); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The operation should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + [bobSession.myUser setDisplayName:newBobName success:nil failure:nil]; + }]; + }]; +} + +- (void)testRoomMembersRaceConditions +{ + [self checkRoomMembersRaceConditionsWithLazyLoading:YES]; +} + +// There cannot be race conditions without LL +//- (void)testRoomMembersRaceConditionsWithLazyLoadingOFF +//{ +// [self checkRoomMembersRaceConditionsWithLazyLoading:NO]; +//} + // [MXRoom members:] should make an HTTP request to fetch members only once - (void)checkSingleRoomMembersRequestWithLazyLoading:(BOOL)lazyLoading diff --git a/MatrixSDKTests/MXRestClientNoAuthAPITests.m b/MatrixSDKTests/MXRestClientNoAuthAPITests.m index 6186b3f126..af42fdddba 100644 --- a/MatrixSDKTests/MXRestClientNoAuthAPITests.m +++ b/MatrixSDKTests/MXRestClientNoAuthAPITests.m @@ -22,6 +22,7 @@ #import "MXError.h" #import "MXRestClient.h" +#import "MXHTTPClient_Private.h" #define MXTESTS_USER @"mxtest" #define MXTESTS_PWD @"password" @@ -49,10 +50,11 @@ - (void)setUp - (void)tearDown { + [super tearDown]; + + [MXHTTPClient removeAllDelays]; mxRestClient = nil; matrixSDKTestsData = nil; - - [super tearDown]; } // Make sure MXTESTS_USER exists on the HS @@ -84,6 +86,55 @@ - (void)testInit } +#pragma mark - Server administration +- (void)testSupportedMatrixVersions +{ + XCTestExpectation *expectation = [self expectationWithDescription:@"asyncTest"]; + + [mxRestClient supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) { + + XCTAssertNotNil(matrixVersions); + XCTAssertNotNil(matrixVersions.versions); + + // Check supported spec version at the time of writing this test + XCTAssert([matrixVersions.versions containsObject:@"r0.0.1"]); + XCTAssert([matrixVersions.versions containsObject:@"r0.1.0"]); + XCTAssert([matrixVersions.versions containsObject:@"r0.2.0"]); + XCTAssert([matrixVersions.versions containsObject:@"r0.3.0"]); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + +// At the time of introducing this test, MXMatrixVersions.supportLazyLoadMembers +// was stored in MXMatrixVersions.unstableFeatures. +// Make sure that, in future versions of the spec, supportLazyLoadMembers is still YES +// wherever it will be stored. +- (void)testSupportedMatrixVersionsSupportLazyLoadMembers +{ + XCTestExpectation *expectation = [self expectationWithDescription:@"asyncTest"]; + + [mxRestClient supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) { + + XCTAssert(matrixVersions.supportLazyLoadMembers); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + + #pragma mark - Registration operations - (void)testGetRegisterSession { @@ -461,5 +512,31 @@ - (void)testCompletionQueueOnError [self waitForExpectationsWithTimeout:10 handler:nil]; } +- (void)testMXHTTPClientPrivateSetDelay +{ + XCTestExpectation *expectation = [self expectationWithDescription:@"asyncTest"]; + + // Define a delay for all requests + [MXHTTPClient setDelay:2000 toRequestsContainingString:@"/"]; + + mxRestClient = [[MXRestClient alloc] initWithHomeServer:kMXTestsHomeServerURL + andOnUnrecognizedCertificateBlock:nil]; + + NSDate *date = [NSDate date]; + [mxRestClient supportedMatrixVersions:^(MXMatrixVersions *matrixVersions) { + + NSDate *now = [NSDate date]; + XCTAssertGreaterThanOrEqual([now timeIntervalSinceDate:date], 2); + + [expectation fulfill]; + + } failure:^(NSError *error) { + XCTFail(@"The request should not fail - NSError: %@", error); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:10 handler:nil]; +} + @end diff --git a/SwiftMatrixSDK.podspec b/SwiftMatrixSDK.podspec index 6c35eccb17..4d4704613e 100644 --- a/SwiftMatrixSDK.podspec +++ b/SwiftMatrixSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "SwiftMatrixSDK" - s.version = "0.11.1" + s.version = "0.11.2" s.summary = "The iOS SDK to build apps compatible with Matrix (https://www.matrix.org)" s.description = <<-DESC diff --git a/fastlane/Fastfile b/fastlane/Fastfile index db60e637dc..5b26481d52 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -24,7 +24,7 @@ platform :ios do desc "Lint MatrixSDK podspec" lane :lint_pod_MatrixSDK do - custom_pod_lib_lint(podspec: "../MatrixSDK.podspec", parameters: ['--use-libraries', '--allow-warnings']) + custom_pod_lib_lint(podspec: "../MatrixSDK.podspec", parameters: ['--allow-warnings']) end desc "Lint SwiftMatrixSDK podspec" @@ -40,7 +40,7 @@ platform :ios do desc "Push MatrixSDK pod" lane :push_pod_MatrixSDK do - pod_push(path: "MatrixSDK.podspec", use_libraries: true, allow_warnings: true) + pod_push(path: "MatrixSDK.podspec", allow_warnings: true) end desc "Push SwiftMatrixSDK pod" diff --git a/lint.sh b/lint.sh index d05bbca3cc..e767e981b1 100755 --- a/lint.sh +++ b/lint.sh @@ -9,6 +9,4 @@ pod update echo "4.1" > .swift-version # Run CocoaPod lint in order to check pod submission -# Note: --allow-warnings should be removed once we fix our warnings with CallKit stuff only available from iOS10 -pod lib lint MatrixSDK.podspec --use-libraries --allow-warnings -pod lib lint SwiftMatrixSDK.podspec --allow-warnings +bundle exec fastlane lint_pods