From 5802fb96a8bd05190b75116ff6fc4067f8f4f7aa Mon Sep 17 00:00:00 2001 From: Lawrence Forooghian Date: Mon, 14 Nov 2022 14:32:15 -0300 Subject: [PATCH] WIP implement ClientLibraryInfo class https://github.com/ably/specification/pull/113 TODO test TODO mention spec points TODO we need docstrings, what's the process for that? Asked Srushtika here: https://ably-real-time.slack.com/archives/C030C5YLY/p1668457571004079 Closes #1530. --- Ably.xcodeproj/project.pbxproj | 40 +++++-- Scripts/set-version.sh | 3 +- Source/ARTClientLibraryInfo+Private.h | 10 ++ Source/ARTClientLibraryInfo.h | 13 ++ Source/ARTClientLibraryInfo.m | 113 ++++++++++++++++++ Source/ARTClientOptions+Private.h | 1 - Source/ARTClientOptions.h | 1 + Source/ARTClientOptions.m | 20 ---- Source/ARTDefault.m | 58 +-------- Source/ARTRest.m | 3 +- Source/ARTWebSocketTransport.m | 3 +- Source/Ably.h | 1 + .../Ably/ARTClientLibraryInfo+Private.h | 1 + Source/include/Ably/ARTClientLibraryInfo.h | 1 + Spec/Test Utilities/TestUtilities.swift | 2 +- Spec/Tests/ClientLibraryInfoTests.swift | 42 +++++++ Spec/Tests/ClientOptionsTests.swift | 19 --- Spec/Tests/RestClientTests.swift | 2 +- 18 files changed, 226 insertions(+), 107 deletions(-) create mode 100644 Source/ARTClientLibraryInfo+Private.h create mode 100644 Source/ARTClientLibraryInfo.h create mode 100644 Source/ARTClientLibraryInfo.m create mode 120000 Source/PrivateHeaders/Ably/ARTClientLibraryInfo+Private.h create mode 120000 Source/include/Ably/ARTClientLibraryInfo.h create mode 100644 Spec/Tests/ClientLibraryInfoTests.swift delete mode 100644 Spec/Tests/ClientOptionsTests.swift diff --git a/Ably.xcodeproj/project.pbxproj b/Ably.xcodeproj/project.pbxproj index 35f5ab01c..a393e3d7b 100644 --- a/Ably.xcodeproj/project.pbxproj +++ b/Ably.xcodeproj/project.pbxproj @@ -21,6 +21,18 @@ 21447D3B254A2ECB00B3905A /* ARTSRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217D181B25421FED00DFF07E /* ARTSRWebSocket.h */; settings = {ATTRIBUTES = (Private, ); }; }; 21447D40254A2ECE00B3905A /* ARTSRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217D181B25421FED00DFF07E /* ARTSRWebSocket.h */; settings = {ATTRIBUTES = (Private, ); }; }; 21447D45254A2ED100B3905A /* ARTSRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217D181B25421FED00DFF07E /* ARTSRWebSocket.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 215F75F82922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F75F62922B1DB009E0E76 /* ARTClientLibraryInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 215F75F92922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F75F62922B1DB009E0E76 /* ARTClientLibraryInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 215F75FA2922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F75F62922B1DB009E0E76 /* ARTClientLibraryInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 215F75FB2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 215F75F72922B1DB009E0E76 /* ARTClientLibraryInfo.m */; }; + 215F75FC2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 215F75F72922B1DB009E0E76 /* ARTClientLibraryInfo.m */; }; + 215F75FD2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 215F75F72922B1DB009E0E76 /* ARTClientLibraryInfo.m */; }; + 215F75FF2922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215F75FE2922B30F009E0E76 /* ClientLibraryInfoTests.swift */; }; + 215F76002922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215F75FE2922B30F009E0E76 /* ClientLibraryInfoTests.swift */; }; + 215F76012922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215F75FE2922B30F009E0E76 /* ClientLibraryInfoTests.swift */; }; + 215F76032922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F76022922C76C009E0E76 /* ARTClientLibraryInfo+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 215F76042922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F76022922C76C009E0E76 /* ARTClientLibraryInfo+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 215F76052922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 215F76022922C76C009E0E76 /* ARTClientLibraryInfo+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 217D1829254222F500DFF07E /* ARTSRHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 217D180425421FED00DFF07E /* ARTSRHash.m */; }; 217D182A254222F500DFF07E /* ARTSRRandom.m in Sources */ = {isa = PBXBuildFile; fileRef = 217D180025421FED00DFF07E /* ARTSRRandom.m */; }; 217D182B254222F500DFF07E /* ARTSRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 217D181F25421FED00DFF07E /* ARTSRWebSocket.m */; }; @@ -100,9 +112,6 @@ 8412FDFE2661AC7B001FE9E6 /* Nimble.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8412FDF42661AC7B001FE9E6 /* Nimble.xcframework */; }; 8412FDFF2661AC7B001FE9E6 /* Nimble.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8412FDF42661AC7B001FE9E6 /* Nimble.xcframework */; }; 8412FE002661AC7B001FE9E6 /* Nimble.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8412FDF42661AC7B001FE9E6 /* Nimble.xcframework */; }; - 84569FA626B46F4E00457CF5 /* ClientOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84569FA226B46ADC00457CF5 /* ClientOptionsTests.swift */; }; - 84569FA726B46F4F00457CF5 /* ClientOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84569FA226B46ADC00457CF5 /* ClientOptionsTests.swift */; }; - 84569FA826B46F5100457CF5 /* ClientOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84569FA226B46ADC00457CF5 /* ClientOptionsTests.swift */; }; 848ED97326E50D0F0087E800 /* ObjcppTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 848ED97226E50D0F0087E800 /* ObjcppTest.mm */; settings = {COMPILER_FLAGS = "-fmodules"; }; }; 848ED97426E50D0F0087E800 /* ObjcppTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 848ED97226E50D0F0087E800 /* ObjcppTest.mm */; settings = {COMPILER_FLAGS = "-fmodules"; }; }; 848ED97526E50D0F0087E800 /* ObjcppTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 848ED97226E50D0F0087E800 /* ObjcppTest.mm */; settings = {COMPILER_FLAGS = "-fmodules"; }; }; @@ -962,6 +971,10 @@ 1C6C18A21ADFDAB100AB79E4 /* ARTLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTLog.m; sourceTree = ""; }; 1CD8DC9D1B1C7315007EAF36 /* ARTDefault.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTDefault.h; sourceTree = ""; }; 1CD8DC9E1B1C7315007EAF36 /* ARTDefault.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTDefault.m; sourceTree = ""; }; + 215F75F62922B1DB009E0E76 /* ARTClientLibraryInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARTClientLibraryInfo.h; sourceTree = ""; }; + 215F75F72922B1DB009E0E76 /* ARTClientLibraryInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTClientLibraryInfo.m; sourceTree = ""; }; + 215F75FE2922B30F009E0E76 /* ClientLibraryInfoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientLibraryInfoTests.swift; sourceTree = ""; }; + 215F76022922C76C009E0E76 /* ARTClientLibraryInfo+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ARTClientLibraryInfo+Private.h"; sourceTree = ""; }; 217D17F125421FED00DFF07E /* ARTSRProxyConnect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ARTSRProxyConnect.h; sourceTree = ""; }; 217D17F225421FED00DFF07E /* ARTSRProxyConnect.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTSRProxyConnect.m; sourceTree = ""; }; 217D17F425421FED00DFF07E /* ARTSRRunLoopThread.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ARTSRRunLoopThread.m; sourceTree = ""; }; @@ -1010,7 +1023,6 @@ 8412FDF12661AC7A001FE9E6 /* Aspects.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Aspects.xcframework; path = Carthage/Build/Aspects.xcframework; sourceTree = ""; }; 8412FDF22661AC7B001FE9E6 /* SwiftyJSON.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = SwiftyJSON.xcframework; path = Carthage/Build/SwiftyJSON.xcframework; sourceTree = ""; }; 8412FDF42661AC7B001FE9E6 /* Nimble.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = Nimble.xcframework; path = Carthage/Build/Nimble.xcframework; sourceTree = ""; }; - 84569FA226B46ADC00457CF5 /* ClientOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientOptionsTests.swift; sourceTree = ""; }; 848ED97226E50D0F0087E800 /* ObjcppTest.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ObjcppTest.mm; sourceTree = ""; }; 850BFB4A1B79323C009D0ADD /* ARTPaginatedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPaginatedResult.h; sourceTree = ""; }; 850BFB4B1B79323C009D0ADD /* ARTPaginatedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTPaginatedResult.m; sourceTree = ""; }; @@ -1466,7 +1478,6 @@ 841134772722205400CFA837 /* ARTArchiveTests.m */, 560579D824AF1BA900A4D03D /* ARTDefaultTests.swift */, D7C1B8761BBEA81A0087B55F /* AuthTests.swift */, - 84569FA226B46ADC00457CF5 /* ClientOptionsTests.swift */, EB7913A71C6E54C3000ABF9B /* CryptoTests.swift */, 56190953238C3D3200A862A6 /* CryptoTest.m */, D798554723EB96C000946BE2 /* DeltaCodecTests.swift */, @@ -1492,6 +1503,7 @@ 851674EE1B7BA5CD00D35169 /* StatsTests.swift */, D520C4DD2680A1E3000012B2 /* StringifiableTests.swift */, EB1AE0CD1C5C3A4900D62250 /* UtilitiesTests.swift */, + 215F75FE2922B30F009E0E76 /* ClientLibraryInfoTests.swift */, ); path = Tests; sourceTree = ""; @@ -1792,6 +1804,9 @@ D54C55A626957FDE00729EC4 /* ARTNSURL+ARTUtils.m */, D5BB213526AAA60500AA5F3E /* ARTNSError+ARTUtils.h */, D5BB213426AAA60500AA5F3E /* ARTNSError+ARTUtils.m */, + 215F75F62922B1DB009E0E76 /* ARTClientLibraryInfo.h */, + 215F75F72922B1DB009E0E76 /* ARTClientLibraryInfo.m */, + 215F76022922C76C009E0E76 /* ARTClientLibraryInfo+Private.h */, ); name = Utilities; sourceTree = ""; @@ -1913,6 +1928,7 @@ 961343D81A42E0B7006DC822 /* ARTClientOptions.h in Headers */, D7534C321D79E5C20054C182 /* Ably.h in Headers */, D777EEE0206285CF002EBA03 /* ARTDeviceIdentityTokenDetails.h in Headers */, + 215F76032922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */, 96BF615E1A35C1C8004CF2B3 /* ARTTypes.h in Headers */, EB503C881C7E4A090053AF00 /* ARTClientOptions+Private.h in Headers */, EB2D84F71CD75CCE00F23CDA /* ARTReachability.h in Headers */, @@ -2032,6 +2048,7 @@ D7D8F82B1BC2C706009718F2 /* ARTTokenRequest.h in Headers */, D5BB211126AA993E00AA5F3E /* ARTNSURL+ARTUtils.h in Headers */, EB1AE0CC1C5C1EB200D62250 /* ARTEventEmitter+Private.h in Headers */, + 215F75F82922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */, D7DF738A1EA645300013CD36 /* ARTLocalDeviceStorage.h in Headers */, 960D07931A45F1D800ED8C8C /* ARTCrypto.h in Headers */, D5BB20FC26A7F3FF00AA5F3E /* NSURLRequest+ARTSRWebSocket.h in Headers */, @@ -2131,6 +2148,7 @@ D76F153D23DB012100B5133C /* ARTRealtimeChannelOptions.h in Headers */, D5D83C0826AAED1A00AADC8E /* ARTStringifiable+Private.h in Headers */, D710D48021949A42008F54AD /* ARTDefault.h in Headers */, + 215F76042922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */, D710D58021949D28008F54AD /* ARTAuthDetails.h in Headers */, D710D54D21949C66008F54AD /* ARTLocalDevice+Private.h in Headers */, D710D4D421949BF9008F54AD /* ARTRealtime.h in Headers */, @@ -2176,6 +2194,7 @@ D710D4BF21949B6C008F54AD /* ARTNSMutableRequest+ARTRest.h in Headers */, D710D5BE21949D4F008F54AD /* ARTBaseMessage+Private.h in Headers */, D5BB20FE26A7F50000AA5F3E /* ARTSRPinningSecurityPolicy.h in Headers */, + 215F75F92922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */, D5BB210126A80A9C00AA5F3E /* NSRunLoop+ARTSRWebSocket.h in Headers */, D5C0CB3E268317B500C06521 /* NSURLQueryItem+Stringifiable.h in Headers */, D5BB210026A80A9000AA5F3E /* NSURLRequest+ARTSRWebSocket.h in Headers */, @@ -2273,6 +2292,7 @@ D710D52D21949C44008F54AD /* ARTDeviceIdentityTokenDetails.h in Headers */, D76F153E23DB012100B5133C /* ARTRealtimeChannelOptions.h in Headers */, D710D48221949A43008F54AD /* ARTDefault.h in Headers */, + 215F76052922C76C009E0E76 /* ARTClientLibraryInfo+Private.h in Headers */, D710D5A621949D2A008F54AD /* ARTAuthDetails.h in Headers */, D710D55321949C67008F54AD /* ARTLocalDevice+Private.h in Headers */, D710D4E421949BFB008F54AD /* ARTRealtime.h in Headers */, @@ -2318,6 +2338,7 @@ D710D4C121949B6D008F54AD /* ARTNSMutableRequest+ARTRest.h in Headers */, D710D5CE21949D50008F54AD /* ARTBaseMessage+Private.h in Headers */, D5BB20FF26A7F50800AA5F3E /* ARTSRPinningSecurityPolicy.h in Headers */, + 215F75FA2922B1DB009E0E76 /* ARTClientLibraryInfo.h in Headers */, D5BB210326A80AA700AA5F3E /* NSRunLoop+ARTSRWebSocket.h in Headers */, D54C554A268B31E500729EC4 /* ARTNSMutableDictionary+ARTDictionaryUtil.h in Headers */, D5BB210226A80AA400AA5F3E /* NSURLRequest+ARTSRWebSocket.h in Headers */, @@ -2636,7 +2657,6 @@ D72768211C9C19040022F8B2 /* RestClientPresenceTests.swift in Sources */, D780846E1C68B3E50083009D /* NSObject+TestSuite.m in Sources */, 21881E7A283BD08300CFD9E2 /* GCDTests.swift in Sources */, - 84569FA626B46F4E00457CF5 /* ClientOptionsTests.swift in Sources */, D7093CA9219EFA8A00723F17 /* MockDeviceStorage.swift in Sources */, D7CEF1321C8DD3BC004FB242 /* RealtimeClientPresenceTests.swift in Sources */, 853ED7C41B7A1A3C006F1C6F /* RestClientStatsTests.swift in Sources */, @@ -2644,6 +2664,7 @@ 851674EF1B7BA5CD00D35169 /* StatsTests.swift in Sources */, EB1AE0CE1C5C3A4900D62250 /* UtilitiesTests.swift in Sources */, 848ED97326E50D0F0087E800 /* ObjcppTest.mm in Sources */, + 215F75FF2922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */, D798554823EB96C000946BE2 /* DeltaCodecTests.swift in Sources */, D74CBC0B212EC22800D090E4 /* RestPaginatedTests.swift in Sources */, D72304701BB72CED00F1ABDA /* RealtimeClientTests.swift in Sources */, @@ -2696,6 +2717,7 @@ D7D8F82C1BC2C706009718F2 /* ARTTokenRequest.m in Sources */, D7D8F8261BC2C691009718F2 /* ARTTokenDetails.m in Sources */, D75A3F1C1DDE5B62002A4AAD /* ARTGCD.m in Sources */, + 215F75FB2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */, 1C2B0FFE1B136A6D00E3633C /* ARTPresenceMap.m in Sources */, 217D182A254222F500DFF07E /* ARTSRRandom.m in Sources */, 960D07941A45F1D800ED8C8C /* ARTCrypto.m in Sources */, @@ -2788,13 +2810,13 @@ D7093C24219E466E00723F17 /* RealtimeClientTests.swift in Sources */, D7093C1F219E466E00723F17 /* RestClientStatsTests.swift in Sources */, D7093C1A219E465C00723F17 /* NSObject+TestSuite.m in Sources */, + 215F76002922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */, D7093C1E219E466900723F17 /* RestClientTests.swift in Sources */, D7093C2B219E466E00723F17 /* CryptoTests.swift in Sources */, D7093C20219E466E00723F17 /* RestClientChannelTests.swift in Sources */, EB1B53FA22F85CE4006A59AC /* ObjectLifetimesTests.swift in Sources */, D7093C2A219E466E00723F17 /* UtilitiesTests.swift in Sources */, D798554923EB96C000946BE2 /* DeltaCodecTests.swift in Sources */, - 84569FA726B46F4F00457CF5 /* ClientOptionsTests.swift in Sources */, D7093C21219E466E00723F17 /* RestClientChannelsTests.swift in Sources */, D7093C26219E466E00723F17 /* RealtimeClientChannelTests.swift in Sources */, D7093C22219E466E00723F17 /* RestClientPresenceTests.swift in Sources */, @@ -2816,12 +2838,12 @@ 560579DB24AF1BA900A4D03D /* ARTDefaultTests.swift in Sources */, D7093C71219EE25800723F17 /* NSObject+TestSuite.m in Sources */, D7093C70219EE25400723F17 /* TestUtilities.swift in Sources */, - 84569FA826B46F5100457CF5 /* ClientOptionsTests.swift in Sources */, D7093C80219EE26400723F17 /* StatsTests.swift in Sources */, D7093C77219EE26400723F17 /* RestClientChannelTests.swift in Sources */, D520C4E32680A1FC000012B2 /* StringifiableTests.swift in Sources */, D7093C7E219EE26400723F17 /* RealtimeClientChannelsTests.swift in Sources */, D7093C79219EE26400723F17 /* RestClientPresenceTests.swift in Sources */, + 215F76012922B30F009E0E76 /* ClientLibraryInfoTests.swift in Sources */, D7093C78219EE26400723F17 /* RestClientChannelsTests.swift in Sources */, D7093C76219EE26400723F17 /* RestClientStatsTests.swift in Sources */, D7093C82219EE26400723F17 /* CryptoTests.swift in Sources */, @@ -2874,6 +2896,7 @@ D710D5E221949D78008F54AD /* ARTTypes.m in Sources */, D710D5DF21949D78008F54AD /* ARTDataEncoder.m in Sources */, D710D4EE21949C0D008F54AD /* ARTConnection.m in Sources */, + 215F75FC2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */, D710D4C921949BAA008F54AD /* ARTWebSocketTransport.m in Sources */, 217D1841254222F700DFF07E /* ARTSRRandom.m in Sources */, D710D5DD21949D78008F54AD /* ARTPresenceMessage.m in Sources */, @@ -2984,6 +3007,7 @@ D710D60821949D79008F54AD /* ARTTypes.m in Sources */, D710D60521949D79008F54AD /* ARTDataEncoder.m in Sources */, D710D4FE21949C0E008F54AD /* ARTConnection.m in Sources */, + 215F75FD2922B1DB009E0E76 /* ARTClientLibraryInfo.m in Sources */, D710D4CD21949BAB008F54AD /* ARTWebSocketTransport.m in Sources */, 217D1858254222F900DFF07E /* ARTSRRandom.m in Sources */, D710D60321949D79008F54AD /* ARTPresenceMessage.m in Sources */, diff --git a/Scripts/set-version.sh b/Scripts/set-version.sh index 269398011..9b682480c 100755 --- a/Scripts/set-version.sh +++ b/Scripts/set-version.sh @@ -29,8 +29,9 @@ git add Version.xcconfig other_files=( "README.md" "Scripts/jazzy.sh" - "Source/ARTDefault.m" + "Source/ARTClientLibraryInfo.m" "Spec/Tests/ARTDefaultTests.swift" + "Spec/Tests/ClientLibraryInfoTests.swift" "Spec/Tests/RealtimeClientConnectionTests.swift" "Spec/Tests/RestClientTests.swift" ) diff --git a/Source/ARTClientLibraryInfo+Private.h b/Source/ARTClientLibraryInfo+Private.h new file mode 100644 index 000000000..6ba354126 --- /dev/null +++ b/Source/ARTClientLibraryInfo+Private.h @@ -0,0 +1,10 @@ +#import + +extern NSString *const ARTClientLibraryInfo_libraryVersion; + +@interface ARTClientLibraryInfo (Private) + ++ (NSString *)libraryAgentIdentifier; ++ (NSString *)platformAgentIdentifier; + +@end diff --git a/Source/ARTClientLibraryInfo.h b/Source/ARTClientLibraryInfo.h new file mode 100644 index 000000000..0ebd2d224 --- /dev/null +++ b/Source/ARTClientLibraryInfo.h @@ -0,0 +1,13 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ARTClientLibraryInfo : NSObject + +// TODO mention the no version sentinel +@property (class, readonly) NSDictionary *agents; ++ (NSString *)agentIdentifierWithAdditionalAgents:(nullable NSDictionary *)additionalAgents; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Source/ARTClientLibraryInfo.m b/Source/ARTClientLibraryInfo.m new file mode 100644 index 000000000..026e5579c --- /dev/null +++ b/Source/ARTClientLibraryInfo.m @@ -0,0 +1,113 @@ +#import "ARTClientLibraryInfo.h" +#import "ARTClientLibraryInfo+Private.h" +#import "ARTDefault.h" +#import "ARTDefault+Private.h" +#import "ARTClientOptions.h" +#import + +NSString *const ARTClientLibraryInfo_libraryVersion = @"1.2.16"; +static NSString *const _libraryName = @"ably-cocoa"; + +// NSOperatingSystemVersion has NSInteger as version components for some reason, so mitigate it here. +static inline UInt32 conformVersionComponent(const NSInteger component) { + return (component < 0) ? 0 : (UInt32)component; +} + +@implementation ARTClientLibraryInfo + ++ (NSDictionary *)agents { + NSMutableDictionary *result = [NSMutableDictionary dictionary]; + + [result addEntriesFromDictionary:[self platformAgent]]; + [result addEntriesFromDictionary:[self libraryAgent]]; + + return result; +} + ++ (NSString *)agentIdentifierWithAdditionalAgents:(nullable NSDictionary *)additionalAgents { + NSMutableDictionary *agents = [self.agents mutableCopy]; + + for (NSString *const additionalAgentName in additionalAgents) { + agents[additionalAgentName] = additionalAgents[additionalAgentName]; + } + + return [self agentIdentifierForAgents:agents]; +} + ++ (NSString *)agentIdentifierForAgents:(NSDictionary *)agents { + NSMutableString *agentIdentifier = [NSMutableString string]; + + // We sort the agent names so that we have a predictable order when testing. + NSArray *sortedAgentNames = [agents.allKeys sortedArrayUsingSelector:@selector(compare:)]; + for (NSString *name in sortedAgentNames) { + NSString *const version = agents[name]; + if (version == ARTClientOptionsAgentNotVersioned) { + [agentIdentifier appendFormat:@"%@ ", name]; + } else { + [agentIdentifier appendFormat:@"%@/%@ ", name, version]; + } + } + + return agentIdentifier; +} + ++ (NSDictionary *)libraryAgent { + return @{ _libraryName: ARTClientLibraryInfo_libraryVersion }; +} + ++ (NSString *)libraryAgentIdentifier { + return [self agentIdentifierForAgents:[self libraryAgent]]; +} + ++ (NSDictionary *)platformAgent { + NSString *const osName = [self osName]; + + if (osName == nil) { + return @{}; + } + + return @{ osName: [self osVersionString] }; +} + ++ (NSString *)platformAgentIdentifier { + return [self agentIdentifierForAgents:[self platformAgent]]; +} + ++ (NSString *)osName { + return + #if TARGET_OS_IOS + @"iOS" + #elif TARGET_OS_TV + @"tvOS" + #elif TARGET_OS_WATCH + @"watchOS" + #elif TARGET_OS_OSX + @"macOS" + #else + nil + #endif + ; +} + ++ (NSString *)osVersionString { + static NSString *versionString; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; + versionString = [NSString stringWithFormat:@"%lu.%lu.%lu", + (unsigned long)conformVersionComponent(version.majorVersion), + (unsigned long)conformVersionComponent(version.minorVersion), + (unsigned long)conformVersionComponent(version.patchVersion)]; + }); + return versionString; +} + ++ (NSString *)deviceModel { + struct utsname systemInfo; + if (uname(&systemInfo) < 0) { + return nil; + } + return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; +} + +@end diff --git a/Source/ARTClientOptions+Private.h b/Source/ARTClientOptions+Private.h index 705fcae8d..08ba32e94 100644 --- a/Source/ARTClientOptions+Private.h +++ b/Source/ARTClientOptions+Private.h @@ -17,6 +17,5 @@ + (void)setDefaultEnvironment:(NSString *_Nullable)environment; + (BOOL)getDefaultIdempotentRestPublishingForVersion:(NSString *_Nonnull)version; - (NSURLComponents *_Nonnull)restUrlComponents; -- (NSString *_Nonnull)agentLibraryIdentifier; @end diff --git a/Source/ARTClientOptions.h b/Source/ARTClientOptions.h index 9369f7ccc..9b922a523 100644 --- a/Source/ARTClientOptions.h +++ b/Source/ARTClientOptions.h @@ -9,6 +9,7 @@ NS_ASSUME_NONNULL_BEGIN +// TODO correct place for this? /** * Use this pointer as a dictionary value in the `ARTClientOptions.agents` property to indicate that an agent does not have a version. */ diff --git a/Source/ARTClientOptions.m b/Source/ARTClientOptions.m index f0ef9bff8..0e904a2f6 100644 --- a/Source/ARTClientOptions.m +++ b/Source/ARTClientOptions.m @@ -222,24 +222,4 @@ - (NSString *)host:(NSString *)host forEnvironment:(NSString *)environment { return [NSString stringWithFormat:@"%@-%@", environment, host]; } -- (NSString *)agentLibraryIdentifier { - NSMutableString *agents = [NSMutableString string]; - [agents appendFormat:@"%@ ", [ARTDefault libraryAgent]]; - - // We sort the agent names so that we have a predictable order when testing. - NSArray *sortedAgentNames = [self.agents.allKeys sortedArrayUsingSelector:@selector(compare:)]; - for (NSString *name in sortedAgentNames) { - NSString *const version = self.agents[name]; - if (version == ARTClientOptionsAgentNotVersioned) { - [agents appendFormat:@"%@ ", name]; - } else { - [agents appendFormat:@"%@/%@ ", name, version]; - } - } - - [agents appendFormat:@"%@", [ARTDefault platformAgent]]; - - return agents; -} - @end diff --git a/Source/ARTDefault.m b/Source/ARTDefault.m index e81236e02..386d23afe 100644 --- a/Source/ARTDefault.m +++ b/Source/ARTDefault.m @@ -1,21 +1,14 @@ #import "Ably.h" #import "ARTDefault+Private.h" #import "ARTNSArray+ARTFunctional.h" -#import - -// NSOperatingSystemVersion has NSInteger as version components for some reason, so mitigate it here. -static inline UInt32 conformVersionComponent(const NSInteger component) { - return (component < 0) ? 0 : (UInt32)component; -} +#import "ARTClientLibraryInfo+Private.h" static NSString *const ARTDefault_apiVersion = @"1.2"; -static NSString *const ARTDefault_libraryVersion = @"1.2.16"; NSString *const ARTDefaultProduction = @"production"; static NSString *const ARTDefault_restHost = @"rest.ably.io"; static NSString *const ARTDefault_realtimeHost = @"realtime.ably.io"; -static NSString *const ARTDefault_libraryName = @"ably-cocoa"; static NSTimeInterval _realtimeRequestTimeout = 10.0; static NSTimeInterval _connectionStateTtl = 60.0; @@ -28,7 +21,7 @@ + (NSString *)apiVersion { } + (NSString *)libraryVersion { - return ARTDefault_libraryVersion; + return ARTClientLibraryInfo_libraryVersion; } + (NSArray*)fallbackHostsWithEnvironment:(NSString *)environment { @@ -99,55 +92,12 @@ + (void)setMaxMessageSize:(NSInteger)value { } } -+ (NSString *)osName { - return - #if TARGET_OS_IOS - @"iOS" - #elif TARGET_OS_TV - @"tvOS" - #elif TARGET_OS_WATCH - @"watchOS" - #elif TARGET_OS_OSX - @"macOS" - #else - nil - #endif - ; -} - -+ (NSString *)osVersionString { - static NSString *versionString; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion]; - versionString = [NSString stringWithFormat:@"%lu.%lu.%lu", - (unsigned long)conformVersionComponent(version.majorVersion), - (unsigned long)conformVersionComponent(version.minorVersion), - (unsigned long)conformVersionComponent(version.patchVersion)]; - }); - return versionString; -} - -+ (NSString *)deviceModel { - struct utsname systemInfo; - if (uname(&systemInfo) < 0) { - return nil; - } - return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; -} - + (NSString *)libraryAgent { - NSMutableString *agent = [NSMutableString stringWithFormat:@"%@/%@", ARTDefault_libraryName, ARTDefault_libraryVersion]; - return agent; + return [ARTClientLibraryInfo libraryAgentIdentifier]; } + (NSString *)platformAgent { - NSMutableString *agent = [NSMutableString string]; - NSString *osName = [self osName]; - if (osName != nil) { - [agent appendFormat:@"%@/%@", osName, [self osVersionString]]; - } - return agent; + return [ARTClientLibraryInfo platformAgentIdentifier]; } @end diff --git a/Source/ARTRest.m b/Source/ARTRest.m index 884d33eb2..98f37e35b 100644 --- a/Source/ARTRest.m +++ b/Source/ARTRest.m @@ -38,6 +38,7 @@ #import "ARTNSMutableURLRequest+ARTUtils.h" #import "ARTNSURL+ARTUtils.h" #import "ARTTime.h" +#import "ARTClientLibraryInfo.h" @implementation ARTRest { ARTQueuedDealloc *_dealloc; @@ -313,7 +314,7 @@ - (NSString *)description { [mutableRequest setAcceptHeader:self.defaultEncoder encoders:self.encoders]; [mutableRequest setTimeoutInterval:_options.httpRequestTimeout]; [mutableRequest setValue:[ARTDefault apiVersion] forHTTPHeaderField:@"X-Ably-Version"]; - [mutableRequest setValue:[_options agentLibraryIdentifier] forHTTPHeaderField:@"Ably-Agent"]; + [mutableRequest setValue:[ARTClientLibraryInfo agentIdentifierWithAdditionalAgents:_options.agents] forHTTPHeaderField:@"Ably-Agent"]; if (_options.clientId && !self.auth.isTokenAuth) { [mutableRequest setValue:encodeBase64(_options.clientId) forHTTPHeaderField:@"X-Ably-ClientId"]; } diff --git a/Source/ARTWebSocketTransport.m b/Source/ARTWebSocketTransport.m index 1f8a480d8..ea1857ce1 100644 --- a/Source/ARTWebSocketTransport.m +++ b/Source/ARTWebSocketTransport.m @@ -17,6 +17,7 @@ #import "NSURLQueryItem+Stringifiable.h" #import "ARTNSMutableDictionary+ARTDictionaryUtil.h" #import "ARTStringifiable.h" +#import "ARTClientLibraryInfo.h" enum { ARTWsNeverConnected = -1, @@ -178,7 +179,7 @@ - (NSURL *)setupWebSocket:(NSDictionary *)params w [queryItems addValueAsURLQueryItem:[ARTDefault apiVersion] forKey:@"v"]; // Lib - [queryItems addValueAsURLQueryItem:[options agentLibraryIdentifier] forKey:@"agent"]; + [queryItems addValueAsURLQueryItem:[ARTClientLibraryInfo agentIdentifierWithAdditionalAgents:options.agents] forKey:@"agent"]; // Transport Params if (options.transportParams != nil) { diff --git a/Source/Ably.h b/Source/Ably.h index b42054f84..7f39f2391 100644 --- a/Source/Ably.h +++ b/Source/Ably.h @@ -67,3 +67,4 @@ FOUNDATION_EXPORT const unsigned char ablyVersionString[]; #import #import #import +#import diff --git a/Source/PrivateHeaders/Ably/ARTClientLibraryInfo+Private.h b/Source/PrivateHeaders/Ably/ARTClientLibraryInfo+Private.h new file mode 120000 index 000000000..e0c221af6 --- /dev/null +++ b/Source/PrivateHeaders/Ably/ARTClientLibraryInfo+Private.h @@ -0,0 +1 @@ +../../../Source/ARTClientLibraryInfo+Private.h \ No newline at end of file diff --git a/Source/include/Ably/ARTClientLibraryInfo.h b/Source/include/Ably/ARTClientLibraryInfo.h new file mode 120000 index 000000000..6699cac5f --- /dev/null +++ b/Source/include/Ably/ARTClientLibraryInfo.h @@ -0,0 +1 @@ +../../../Source/ARTClientLibraryInfo.h \ No newline at end of file diff --git a/Spec/Test Utilities/TestUtilities.swift b/Spec/Test Utilities/TestUtilities.swift index 24f3c1ad1..5088ae69b 100644 --- a/Spec/Test Utilities/TestUtilities.swift +++ b/Spec/Test Utilities/TestUtilities.swift @@ -1820,7 +1820,7 @@ extension HTTPURLResponse { - Warning: Don't use 'allHeaderFields' property. See discussion. */ @available(*, deprecated, message: "Don't use 'allHeaderFields'. It's not case-insensitive. Please use 'value(forHTTPHeaderField:)' method") - open var _allHeaderFields: [AnyHashable : Any] { return [:] } + public var _allHeaderFields: [AnyHashable : Any] { return [:] } /** The value which corresponds to the given header diff --git a/Spec/Tests/ClientLibraryInfoTests.swift b/Spec/Tests/ClientLibraryInfoTests.swift new file mode 100644 index 000000000..0b6b25365 --- /dev/null +++ b/Spec/Tests/ClientLibraryInfoTests.swift @@ -0,0 +1,42 @@ +import XCTest +import Ably + +final class ClientLibraryInfoTests: XCTestCase { + + func testAgents() { + let agents = ARTClientLibraryInfo.agents + + XCTAssertEqual(agents.keys.count, 2) + + XCTAssertEqual(agents["ably-cocoa"], "1.2.16") + + #if os(iOS) + XCTAssertTrue(agents.keys.contains("iOS")) + #elseif os(tvOS) + XCTAssertTrue(agents.keys.contains("tvOS")) + #elseif os(watchOS) + XCTAssertTrue(agents.keys.contains("watchOS")) + #elseif os(macOS) + XCTAssertTrue(agents.keys.contains("macOS")) + #else + #error("Building for unknown OS") + #endif + } + + func testAgentIdentifierWithAdditionalAgents_withNilAdditionalAgents() { + let expectedIdentifier = "\(ARTDefault.libraryAgent()) \(ARTDefault.platformAgent())" + + XCTAssertEqual(ARTClientLibraryInfo.agentIdentifier(withAdditionalAgents: nil), expectedIdentifier) + } + + func testAgentIdentifierWithAdditionalAgents_withNonNilAdditionalAgents() { + let additionalAgents = [ + "demolib": "0.0.1", + "morelib": ARTClientOptionsAgentNotVersioned + ] + + let expectedIdentifier = "\(ARTDefault.libraryAgent()) demolib/0.0.1 morelib \(ARTDefault.platformAgent())" + + XCTAssertEqual(ARTClientLibraryInfo.agentIdentifier(withAdditionalAgents: additionalAgents), expectedIdentifier) + } +} diff --git a/Spec/Tests/ClientOptionsTests.swift b/Spec/Tests/ClientOptionsTests.swift deleted file mode 100644 index 86c19457f..000000000 --- a/Spec/Tests/ClientOptionsTests.swift +++ /dev/null @@ -1,19 +0,0 @@ -import XCTest - -import Ably.ARTClientOptions - -class ClientOptionsTests: XCTestCase { - - func testAgentLibraryIdentifier() { - let options = ARTClientOptions() - - let agents = [ - "demolib": "0.0.1", - "morelib": ARTClientOptionsAgentNotVersioned - ] - options.agents = agents - - let expectedIdentifier = "\(ARTDefault.libraryAgent()) demolib/0.0.1 morelib \(ARTDefault.platformAgent())" - XCTAssertEqual(options.agentLibraryIdentifier(), expectedIdentifier) - } -} diff --git a/Spec/Tests/RestClientTests.swift b/Spec/Tests/RestClientTests.swift index bb662c6f8..4ceb17faa 100644 --- a/Spec/Tests/RestClientTests.swift +++ b/Spec/Tests/RestClientTests.swift @@ -1666,7 +1666,7 @@ class RestClientTests: XCTestCase { channel.publish(nil, data: "message") { error in expect(error).to(beNil()) let headerAgent = testHTTPExecutor.requests.first!.allHTTPHeaderFields?["Ably-Agent"] - let ablyAgent = options.agentLibraryIdentifier() + let ablyAgent = ARTClientLibraryInfo.agentIdentifier(withAdditionalAgents: options.agents) expect(headerAgent).to(equal(ablyAgent)) expect(headerAgent!.hasPrefix("ably-cocoa/1.2.16")).to(beTrue()) done()