From f744f43f30e1064108707ae4365351ae6a204ac4 Mon Sep 17 00:00:00 2001 From: jguz-pubnub <102806147+jguz-pubnub@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:14:53 +0200 Subject: [PATCH] Fixed warnings reported by SwiftLint (#167) --- .../Example-iOS/Base.lproj/Main.storyboard | 13 ++-- Examples/Examples.xcodeproj/project.pbxproj | 23 +++--- .../xcschemes/Example-iOS.xcscheme | 4 +- .../ConfigDetailTableViewController.swift | 3 - ....swift => DetailTableViewController.swift} | 13 ++-- .../Sources/File/FileAPIViewController.swift | 2 - Package.swift | 4 +- PubNub.xcodeproj/project.pbxproj | 54 +++++++------- .../xcshareddata/xcschemes/Linting.xcscheme | 2 +- .../xcshareddata/xcschemes/PubNub.xcscheme | 2 +- .../xcschemes/PubNubContractTests.xcscheme | 2 +- .../PubNubContractTestsBeta.xcscheme | 2 +- .../xcschemes/PubNubMembership.xcscheme | 2 +- .../xcschemes/PubNubSpace.xcscheme | 2 +- .../xcschemes/PubNubUser.xcscheme | 2 +- .../Tests/MembershipTestHelpers.swift | 1 + PubNubSpace/Tests/SpaceTestHelpers.swift | 1 + PubNubSwift.podspec | 2 +- PubNubUser/Tests/Test+PubNubUserPatcher.swift | 2 + PubNubUser/Tests/UserTestHelpers.swift | 1 + README.md | 2 +- Sources/PubNub/Errors/ErrorDescription.swift | 1 - Sources/PubNub/Errors/PubNubError.swift | 1 - .../PubNub/EventEngine/Core/Dispatcher.swift | 22 +++--- .../EventEngine/Core/EffectHandler.swift | 14 ++-- .../PubNub/EventEngine/Core/EventEngine.swift | 14 ++-- .../EventEngine/Core/TransitionProtocol.swift | 6 +- .../Effects/DelayedHeartbeatEffect.swift | 12 ++-- .../Presence/Effects/HeartbeatEffect.swift | 10 +-- .../Presence/Effects/LeaveEffect.swift | 12 ++-- .../Effects/PresenceEffectFactory.swift | 12 ++-- .../Helpers/PresenceHeartbeatRequest.swift | 12 ++-- .../Presence/Helpers/PresenceInput.swift | 24 +++---- .../Helpers/PresenceLeaveRequest.swift | 10 +-- .../EventEngine/Presence/Presence.swift | 1 + .../Presence/PresenceTransition.swift | 30 ++++---- .../PubNubPresenceStateContainer.swift | 10 +-- .../Effects/EmitMessagesEffect.swift | 18 ++--- .../Subscribe/Effects/EmitStatusEffect.swift | 2 +- .../Effects/SubscribeEffectFactory.swift | 18 ++--- .../Subscribe/Effects/SubscribeEffects.swift | 42 +++++------ .../Subscribe/Helpers/SubscribeInput.swift | 44 ++++++------ .../Subscribe/Helpers/SubscribeRequest.swift | 20 +++--- .../EventEngine/Subscribe/Subscribe.swift | 2 + .../Subscribe/SubscribeTransition.swift | 71 ++++++++++--------- .../Events/New/Entities/EntityCreator.swift | 8 +-- Sources/PubNub/Events/New/EventEmitter.swift | 8 +-- .../SubscribeMessagePayload+PubNubEvent.swift | 1 + Sources/PubNub/Events/New/Subscribable.swift | 24 +++---- Sources/PubNub/Events/New/Subscription.swift | 36 +++++----- .../PubNub/Events/New/SubscriptionSet.swift | 42 +++++------ .../Old/Subscription/SubscriptionStream.swift | 5 +- Sources/PubNub/Extensions/URL+PubNub.swift | 1 - .../Extensions/URLQueryItem+PubNub.swift | 6 +- .../PubNub/Extensions/URLRequest+PubNub.swift | 8 +-- .../URLSessionConfiguration+PubNub.swift | 2 +- Sources/PubNub/Helpers/AnyJSONType.swift | 8 +-- Sources/PubNub/Helpers/Constants.swift | 2 +- Sources/PubNub/Helpers/Crypto/Crypto.swift | 2 +- .../PubNub/Helpers/Crypto/CryptoModule.swift | 34 ++++----- .../Crypto/Cryptors/AESCBCCryptor.swift | 18 ++--- .../Crypto/Cryptors/LegacyCryptor.swift | 26 +++---- .../Helpers/Crypto/Header/CryptorHeader.swift | 32 ++++----- .../CryptorHeaderWithinStreamFinder.swift | 19 ++--- .../Miscellaneous/CryptoInputStream.swift | 45 +++++++----- .../Crypto/Miscellaneous/CryptorUtils.swift | 2 +- .../Crypto/Miscellaneous/CryptorVector.swift | 12 ++-- .../Streams/MultipartInputStream.swift | 2 +- Sources/PubNub/Helpers/Typealias+PubNub.swift | 3 + Sources/PubNub/Models/PubNubAPNSPayload.swift | 2 +- .../PubNubFCMPayload/FCMAndroidPayload.swift | 1 - Sources/PubNub/Models/PubNubMessage.swift | 16 ++--- Sources/PubNub/Networking/HTTPFileTask.swift | 10 +-- .../Request/Operators/AutomaticRetry.swift | 19 +++-- .../Operators/InstanceIdOperator.swift | 4 -- .../Request/Operators/RequestIdOperator.swift | 4 -- .../PubNub/Networking/Request/Request.swift | 2 +- .../Networking/Routers/HistoryRouter.swift | 49 +++++++------ .../Routers/MessageActionsRouter.swift | 5 -- .../SubscribeObjectPayload.swift | 15 +--- .../Networking/Routers/SubscribeRouter.swift | 3 +- Sources/PubNub/PubNub.swift | 1 - Sources/PubNub/PubNubConfiguration.swift | 13 ++-- .../Subscription/ConnectionStatus.swift | 3 +- ...entEngineSubscriptionSessionStrategy.swift | 36 +++++----- ...SubscriptionSessionStrategy+Presence.swift | 8 ++- .../LegacySubscriptionSessionStrategy.swift | 20 +++--- .../Subscription/SubscriptionSession.swift | 62 ++++++++-------- 88 files changed, 580 insertions(+), 586 deletions(-) rename Examples/Sources/{MasterDetailTableViewController.swift => DetailTableViewController.swift} (98%) diff --git a/Examples/Example-iOS/Base.lproj/Main.storyboard b/Examples/Example-iOS/Base.lproj/Main.storyboard index de8c9c28..72a3384d 100644 --- a/Examples/Example-iOS/Base.lproj/Main.storyboard +++ b/Examples/Example-iOS/Base.lproj/Main.storyboard @@ -1,9 +1,8 @@ - + - - + @@ -25,17 +24,17 @@ - + - + - + @@ -88,7 +87,7 @@ - + diff --git a/Examples/Examples.xcodeproj/project.pbxproj b/Examples/Examples.xcodeproj/project.pbxproj index 40c104da..7403ce8c 100644 --- a/Examples/Examples.xcodeproj/project.pbxproj +++ b/Examples/Examples.xcodeproj/project.pbxproj @@ -3,11 +3,10 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ - 3567432822DF974600BF2639 /* MasterDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 359F779922B7FEF600B6B46F /* MasterDetailTableViewController.swift */; }; 357AD4EC252D067800099EB7 /* FileAPIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357AD4EB252D067800099EB7 /* FileAPIViewController.swift */; }; 357AD4EE252D087800099EB7 /* FileAPI.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 357AD4ED252D087800099EB7 /* FileAPI.storyboard */; }; 357AD4F2252E2FFF00099EB7 /* FileTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357AD4F1252E2FFF00099EB7 /* FileTableViewCell.swift */; }; @@ -17,6 +16,7 @@ 359F779F22B7FEF700B6B46F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 359F779E22B7FEF700B6B46F /* Assets.xcassets */; }; 359F77A222B7FEF700B6B46F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 359F77A022B7FEF700B6B46F /* LaunchScreen.storyboard */; }; 35F0258F22BAC6C9007BD7D3 /* ConfigDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35F0258E22BAC6C9007BD7D3 /* ConfigDetailTableViewController.swift */; }; + 3D34160D2BB5CE20008558A0 /* DetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D34160C2BB5CE20008558A0 /* DetailTableViewController.swift */; }; 792CF27228C4FBB300C83408 /* PubNub in Frameworks */ = {isa = PBXBuildFile; productRef = 792CF27128C4FBB300C83408 /* PubNub */; }; 792CF27428C4FBB300C83408 /* PubNubMembership in Frameworks */ = {isa = PBXBuildFile; productRef = 792CF27328C4FBB300C83408 /* PubNubMembership */; }; 792CF27628C4FBB300C83408 /* PubNubSpace in Frameworks */ = {isa = PBXBuildFile; productRef = 792CF27528C4FBB300C83408 /* PubNubSpace */; }; @@ -54,13 +54,13 @@ 357AD4F3252E302900099EB7 /* LocalFileExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFileExample.swift; sourceTree = ""; }; 359F779422B7FEF600B6B46F /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 359F779722B7FEF600B6B46F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 359F779922B7FEF600B6B46F /* MasterDetailTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterDetailTableViewController.swift; sourceTree = ""; }; 359F779C22B7FEF700B6B46F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 359F779E22B7FEF700B6B46F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 359F77A122B7FEF700B6B46F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 359F77A322B7FEF700B6B46F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 359F77AA22B7FF5700B6B46F /* PubNub.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PubNub.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 35F0258E22BAC6C9007BD7D3 /* ConfigDetailTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigDetailTableViewController.swift; sourceTree = ""; }; + 3D34160C2BB5CE20008558A0 /* DetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailTableViewController.swift; sourceTree = ""; }; 792CF27A28C4FCB800C83408 /* PubNub SDK */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "PubNub SDK"; path = ..; sourceTree = ""; }; /* End PBXFileReference section */ @@ -142,7 +142,7 @@ isa = PBXGroup; children = ( 359F779722B7FEF600B6B46F /* AppDelegate.swift */, - 359F779922B7FEF600B6B46F /* MasterDetailTableViewController.swift */, + 3D34160C2BB5CE20008558A0 /* DetailTableViewController.swift */, 35F0258E22BAC6C9007BD7D3 /* ConfigDetailTableViewController.swift */, 357AD4F0252E2FD600099EB7 /* File */, ); @@ -191,8 +191,9 @@ 359F778C22B7FEF600B6B46F /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1020; - LastUpgradeCheck = 1240; + LastUpgradeCheck = 1520; ORGANIZATIONNAME = PubNub; TargetAttributes = { 359F779322B7FEF600B6B46F = { @@ -242,9 +243,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3D34160D2BB5CE20008558A0 /* DetailTableViewController.swift in Sources */, 357AD4F4252E302900099EB7 /* LocalFileExample.swift in Sources */, 35F0258F22BAC6C9007BD7D3 /* ConfigDetailTableViewController.swift in Sources */, - 3567432822DF974600BF2639 /* MasterDetailTableViewController.swift in Sources */, 357AD4F2252E2FFF00099EB7 /* FileTableViewCell.swift in Sources */, 359F779822B7FEF600B6B46F /* AppDelegate.swift in Sources */, 357AD4EC252D067800099EB7 /* FileAPIViewController.swift in Sources */, @@ -311,6 +312,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -326,7 +328,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -334,7 +336,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; TVOS_DEPLOYMENT_TARGET = 12.0; - WATCHOS_DEPLOYMENT_TARGET = 2.0; + WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Debug; }; @@ -376,6 +378,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -385,7 +388,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -393,7 +396,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-O"; TVOS_DEPLOYMENT_TARGET = 12.0; VALIDATE_PRODUCT = YES; - WATCHOS_DEPLOYMENT_TARGET = 2.0; + WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Release; }; diff --git a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme index 4dfbc10c..952f113c 100644 --- a/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme +++ b/Examples/Examples.xcodeproj/xcshareddata/xcschemes/Example-iOS.xcscheme @@ -1,7 +1,7 @@ + LastUpgradeVersion = "1520" + version = "1.8"> diff --git a/Examples/Sources/ConfigDetailTableViewController.swift b/Examples/Sources/ConfigDetailTableViewController.swift index a7986221..d1ac789e 100644 --- a/Examples/Sources/ConfigDetailTableViewController.swift +++ b/Examples/Sources/ConfigDetailTableViewController.swift @@ -13,9 +13,6 @@ import UIKit import PubNub class ConfigDetailTableViewController: UITableViewController { - override func viewDidLoad() { - super.viewDidLoad() - } let configCellID = "PubNubConfigDetailCell" diff --git a/Examples/Sources/MasterDetailTableViewController.swift b/Examples/Sources/DetailTableViewController.swift similarity index 98% rename from Examples/Sources/MasterDetailTableViewController.swift rename to Examples/Sources/DetailTableViewController.swift index bded2ba0..94682640 100644 --- a/Examples/Sources/MasterDetailTableViewController.swift +++ b/Examples/Sources/DetailTableViewController.swift @@ -7,7 +7,6 @@ // This source code is licensed under the license found in the // LICENSE file in the root directory of this source tree. // -// swiftlint:disable file_length import Foundation import UIKit @@ -18,7 +17,7 @@ import PubNubSpace import PubNubUser // swiftlint:disable:next type_body_length -class MasterDetailTableViewController: UITableViewController { +class DetailTableViewController: UITableViewController { var pubnub: PubNub! var listener: SubscriptionListener? @@ -26,7 +25,7 @@ class MasterDetailTableViewController: UITableViewController { var spaceListener: PubNubSpaceListener? var membershipListener: PubNubMembershipListener? - let masterDetailCellID = "MasterDetailCell" + let detailCellID = "MasterDetailCell" enum SegueId: String { case config = "MasterDetailToConfigDetail" @@ -366,10 +365,6 @@ class MasterDetailTableViewController: UITableViewController { } } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - } - override func numberOfSections(in tableView: UITableView) -> Int { super.numberOfSections(in: tableView) @@ -391,7 +386,7 @@ class MasterDetailTableViewController: UITableViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { super.tableView(tableView, cellForRowAt: indexPath) - let cell = tableView.dequeueReusableCell(withIdentifier: masterDetailCellID, for: indexPath) + let cell = tableView.dequeueReusableCell(withIdentifier: detailCellID, for: indexPath) switch Section(rawValue: indexPath.section) { case .some(.pubnub): @@ -753,5 +748,5 @@ class MasterDetailTableViewController: UITableViewController { } } - // swiftlint:endable file_length + // swiftlint:disable:next file_length } diff --git a/Examples/Sources/File/FileAPIViewController.swift b/Examples/Sources/File/FileAPIViewController.swift index 6d2cf3ad..88c06f6c 100644 --- a/Examples/Sources/File/FileAPIViewController.swift +++ b/Examples/Sources/File/FileAPIViewController.swift @@ -385,6 +385,4 @@ extension FileAPIViewController: UIDocumentPickerDelegate { } } } - - // swiftlint:disable:next file_length } diff --git a/Package.swift b/Package.swift index d1f59a0c..7cc42d1e 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.3 // // Package.swift // @@ -15,7 +15,7 @@ let package = Package( name: "PubNub", platforms: [ .iOS(.v12), - .macOS(.v10_13), + .macOS(.v10_15), .tvOS(.v12), .watchOS(.v4) ], diff --git a/PubNub.xcodeproj/project.pbxproj b/PubNub.xcodeproj/project.pbxproj index 18a5af73..3c42f42f 100644 --- a/PubNub.xcodeproj/project.pbxproj +++ b/PubNub.xcodeproj/project.pbxproj @@ -3760,7 +3760,7 @@ "@loader_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; @@ -3795,7 +3795,7 @@ "@loader_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; @@ -3846,7 +3846,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -3895,7 +3895,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -3924,7 +3924,7 @@ GCC_DYNAMIC_NO_PIC = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -3951,7 +3951,7 @@ ENABLE_NS_ASSERTIONS = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4001,7 +4001,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4052,7 +4052,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4087,7 +4087,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4121,7 +4121,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4171,7 +4171,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4221,7 +4221,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4255,7 +4255,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4290,7 +4290,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4310,7 +4310,10 @@ 359152A622BA9F380048842D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 12.0; WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Debug; @@ -4318,7 +4321,10 @@ 359152A722BA9F380048842D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 10.15; PRODUCT_NAME = "$(TARGET_NAME)"; + TVOS_DEPLOYMENT_TARGET = 12.0; WATCHOS_DEPLOYMENT_TARGET = 4.0; }; name = Release; @@ -4335,7 +4341,7 @@ GCC_DYNAMIC_NO_PIC = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4362,7 +4368,7 @@ ENABLE_NS_ASSERTIONS = NO; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4393,7 +4399,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4427,7 +4433,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4459,7 +4465,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -4494,7 +4500,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -4699,7 +4705,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; @@ -4740,7 +4746,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 7.1.0; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; @@ -4894,7 +4900,7 @@ "@loader_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; @@ -4930,7 +4936,7 @@ "@loader_path/../Frameworks", "@loader_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; diff --git a/PubNub.xcodeproj/xcshareddata/xcschemes/Linting.xcscheme b/PubNub.xcodeproj/xcshareddata/xcschemes/Linting.xcscheme index 62b7910a..629a2994 100644 --- a/PubNub.xcodeproj/xcshareddata/xcschemes/Linting.xcscheme +++ b/PubNub.xcodeproj/xcshareddata/xcschemes/Linting.xcscheme @@ -1,6 +1,6 @@ { associatedtype Invocation: AnyEffectInvocation associatedtype Event associatedtype Dependencies - + func dispatch( invocations: [EffectInvocation], with dependencies: EventEngineDependencies, @@ -35,15 +35,15 @@ protocol Dispatcher { class EffectDispatcher: Dispatcher { private let factory: any EffectHandlerFactory private let effectsCache = EffectsCache() - + init(factory: some EffectHandlerFactory) { self.factory = factory } - + func hasPendingInvocation(_ invocation: Invocation) -> Bool { effectsCache.hasPendingEffect(with: invocation.id) } - + func dispatch( invocations: [EffectInvocation], with dependencies: EventEngineDependencies, @@ -69,7 +69,7 @@ class EffectDispatcher: Di } } } - + private func executeEffect( effect: some EffectHandler, storageId id: String, @@ -85,21 +85,21 @@ class EffectDispatcher: Di // MARK: - EffectsCache -fileprivate class EffectsCache { +private class EffectsCache { private var managedEffects: Atomic<[String: EffectWrapper]> = Atomic([:]) func hasPendingEffect(with id: String) -> Bool { managedEffects.lockedRead { $0[id] } != nil } - + func put(effect: some EffectHandler, with id: String) { managedEffects.lockedWrite { $0[id] = EffectWrapper(id: id, effect: effect) } } - + func getEffect(with id: String) -> (any EffectHandler)? { - managedEffects.lockedRead() { $0[id] }?.effect + managedEffects.lockedRead { $0[id] }?.effect } - + func removeEffect(id: String) { managedEffects.lockedWrite { $0[id] = nil } } @@ -107,7 +107,7 @@ fileprivate class EffectsCache { // MARK: - EffectWrapper -fileprivate struct EffectWrapper { +private struct EffectWrapper { let id: String let effect: any EffectHandler } diff --git a/Sources/PubNub/EventEngine/Core/EffectHandler.swift b/Sources/PubNub/EventEngine/Core/EffectHandler.swift index a968aaf5..731c35ff 100644 --- a/Sources/PubNub/EventEngine/Core/EffectHandler.swift +++ b/Sources/PubNub/EventEngine/Core/EffectHandler.swift @@ -15,7 +15,7 @@ protocol EffectHandlerFactory { associatedtype Invocation associatedtype Event associatedtype Dependencies - + func effect( for invocation: Invocation, with dependencies: EventEngineDependencies @@ -26,7 +26,7 @@ protocol EffectHandlerFactory { protocol EffectHandler { associatedtype Event - + func performTask(completionBlock: @escaping ([Event]) -> Void) func cancelTask() } @@ -39,7 +39,7 @@ extension EffectHandler { protocol DelayedEffectHandler: AnyObject, EffectHandler { var workItem: DispatchWorkItem? { get set } - + func delayInterval() -> TimeInterval? func onEmptyInterval(notify completionBlock: @escaping ([Event]) -> Void) func onDelayExpired(notify completionBlock: @escaping ([Event]) -> Void) @@ -50,7 +50,7 @@ protocol DelayedEffectHandler: AnyObject, EffectHandler { class TimerEffect: EffectHandler { private let interval: TimeInterval private var workItem: DispatchWorkItem? - + init?(interval: TimeInterval?) { if let interval = interval { self.interval = interval @@ -58,9 +58,9 @@ class TimerEffect: EffectHandler { return nil } } - + func performTask(completionBlock: @escaping ([Void]) -> Void) { - let workItem = DispatchWorkItem() { + let workItem = DispatchWorkItem { completionBlock([]) } DispatchQueue.global(qos: .default).asyncAfter( @@ -69,7 +69,7 @@ class TimerEffect: EffectHandler { ) self.workItem = workItem } - + func cancelTask() { workItem?.cancel() } diff --git a/Sources/PubNub/EventEngine/Core/EventEngine.swift b/Sources/PubNub/EventEngine/Core/EventEngine.swift index 4f8a3b99..fc085585 100644 --- a/Sources/PubNub/EventEngine/Core/EventEngine.swift +++ b/Sources/PubNub/EventEngine/Core/EventEngine.swift @@ -18,10 +18,10 @@ class EventEngine { private let transition: any TransitionProtocol private let dispatcher: any Dispatcher private(set) var state: State - + var dependencies: EventEngineDependencies var onStateUpdated: ((State) -> Void)? - + init( state: State, transition: some TransitionProtocol, @@ -35,10 +35,10 @@ class EventEngine { self.dispatcher = dispatcher self.dependencies = dependencies } - + func send(event: Event) { objc_sync_enter(self) - + defer { objc_sync_exit(self) } @@ -48,13 +48,13 @@ class EventEngine { ) else { return } - + let transitionResult = transition.transition(from: state, event: event) let invocations = transitionResult.invocations - + state = transitionResult.state onStateUpdated?(state) - + let listener = DispatcherListener( onAnyInvocationCompleted: { [weak self] results in results.forEach { diff --git a/Sources/PubNub/EventEngine/Core/TransitionProtocol.swift b/Sources/PubNub/EventEngine/Core/TransitionProtocol.swift index 2a0446bf..6c399552 100644 --- a/Sources/PubNub/EventEngine/Core/TransitionProtocol.swift +++ b/Sources/PubNub/EventEngine/Core/TransitionProtocol.swift @@ -15,7 +15,7 @@ protocol AnyIdentifiableInvocation { } protocol AnyCancellableInvocation: AnyIdentifiableInvocation { - + } protocol AnyEffectInvocation: AnyIdentifiableInvocation { @@ -25,7 +25,7 @@ protocol AnyEffectInvocation: AnyIdentifiableInvocation { struct TransitionResult { let state: State let invocations: [EffectInvocation] - + init(state: State, invocations: [EffectInvocation] = []) { self.state = state self.invocations = invocations @@ -42,7 +42,7 @@ protocol TransitionProtocol { associatedtype State associatedtype Event associatedtype Invocation: AnyEffectInvocation - + func canTransition(from state: State, dueTo event: Event) -> Bool func transition(from state: State, event: Event) -> TransitionResult } diff --git a/Sources/PubNub/EventEngine/Presence/Effects/DelayedHeartbeatEffect.swift b/Sources/PubNub/EventEngine/Presence/Effects/DelayedHeartbeatEffect.swift index 3c38a8a1..c9c266e2 100644 --- a/Sources/PubNub/EventEngine/Presence/Effects/DelayedHeartbeatEffect.swift +++ b/Sources/PubNub/EventEngine/Presence/Effects/DelayedHeartbeatEffect.swift @@ -14,7 +14,7 @@ class DelayedHeartbeatEffect: EffectHandler { private let request: PresenceHeartbeatRequest private let reason: PubNubError private let timerEffect: TimerEffect? - + init( request: PresenceHeartbeatRequest, retryAttempt: Int, @@ -24,15 +24,15 @@ class DelayedHeartbeatEffect: EffectHandler { self.reason = reason self.timerEffect = TimerEffect(interval: request.reconnectionDelay(dueTo: reason, retryAttempt: retryAttempt)) } - + func performTask(completionBlock: @escaping ([Presence.Event]) -> Void) { guard let timerEffect = timerEffect else { completionBlock([.heartbeatGiveUp(error: reason)]); return } timerEffect.performTask { [weak self] _ in - self?.request.execute() { result in + self?.request.execute { result in switch result { - case .success(_): + case .success: completionBlock([.heartbeatSuccess]) case .failure(let error): completionBlock([.heartbeatFailed(error: error)]) @@ -40,12 +40,12 @@ class DelayedHeartbeatEffect: EffectHandler { } } } - + func cancelTask() { timerEffect?.cancelTask() request.cancel() } - + deinit { cancelTask() } diff --git a/Sources/PubNub/EventEngine/Presence/Effects/HeartbeatEffect.swift b/Sources/PubNub/EventEngine/Presence/Effects/HeartbeatEffect.swift index 986df121..2e53437a 100644 --- a/Sources/PubNub/EventEngine/Presence/Effects/HeartbeatEffect.swift +++ b/Sources/PubNub/EventEngine/Presence/Effects/HeartbeatEffect.swift @@ -12,22 +12,22 @@ import Foundation class HeartbeatEffect: EffectHandler { private let request: PresenceHeartbeatRequest - + init(request: PresenceHeartbeatRequest) { self.request = request } - + func performTask(completionBlock: @escaping ([Presence.Event]) -> Void) { - request.execute() { result in + request.execute { result in switch result { - case .success(_): + case .success: completionBlock([.heartbeatSuccess]) case .failure(let error): completionBlock([.heartbeatFailed(error: error)]) } } } - + deinit { request.cancel() } diff --git a/Sources/PubNub/EventEngine/Presence/Effects/LeaveEffect.swift b/Sources/PubNub/EventEngine/Presence/Effects/LeaveEffect.swift index 0f87a1e9..e548983d 100644 --- a/Sources/PubNub/EventEngine/Presence/Effects/LeaveEffect.swift +++ b/Sources/PubNub/EventEngine/Presence/Effects/LeaveEffect.swift @@ -12,22 +12,22 @@ import Foundation class LeaveEffect: EffectHandler { private let request: PresenceLeaveRequest - + init(request: PresenceLeaveRequest) { self.request = request } - + func performTask(completionBlock: @escaping ([Presence.Event]) -> Void) { - request.execute() { result in + request.execute { result in switch result { - case .success(_): + case .success: completionBlock([]) - case .failure(_): + case .failure: completionBlock([]) } } } - + deinit { request.cancel() } diff --git a/Sources/PubNub/EventEngine/Presence/Effects/PresenceEffectFactory.swift b/Sources/PubNub/EventEngine/Presence/Effects/PresenceEffectFactory.swift index e1c66252..f3ff97c8 100644 --- a/Sources/PubNub/EventEngine/Presence/Effects/PresenceEffectFactory.swift +++ b/Sources/PubNub/EventEngine/Presence/Effects/PresenceEffectFactory.swift @@ -14,7 +14,7 @@ class PresenceEffectFactory: EffectHandlerFactory { private let session: SessionReplaceable private let sessionResponseQueue: DispatchQueue private let presenceStateContainer: PubNubPresenceStateContainer - + init( session: SessionReplaceable, sessionResponseQueue: DispatchQueue = .main, @@ -24,13 +24,13 @@ class PresenceEffectFactory: EffectHandlerFactory { self.sessionResponseQueue = sessionResponseQueue self.presenceStateContainer = presenceStateContainer } - + func effect( for invocation: Presence.Invocation, with dependencies: EventEngineDependencies ) -> any EffectHandler { switch invocation { - case .heartbeat(let channels, let groups): + case let .heartbeat(channels, groups): return HeartbeatEffect( request: PresenceHeartbeatRequest( channels: channels, @@ -41,7 +41,7 @@ class PresenceEffectFactory: EffectHandlerFactory { sessionResponseQueue: sessionResponseQueue ) ) - case .delayedHeartbeat(let channels, let groups, let retryAttempt, let reason): + case let .delayedHeartbeat(channels, groups, retryAttempt, reason): return DelayedHeartbeatEffect( request: PresenceHeartbeatRequest( channels: channels, @@ -54,7 +54,7 @@ class PresenceEffectFactory: EffectHandlerFactory { retryAttempt: retryAttempt, reason: reason ) - case .leave(let channels, let groups): + case let .leave(channels, groups): return LeaveEffect( request: PresenceLeaveRequest( channels: channels, @@ -68,7 +68,7 @@ class PresenceEffectFactory: EffectHandlerFactory { return WaitEffect(configuration: dependencies.value.configuration) } } - + deinit { session.invalidateAndCancel() } diff --git a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceHeartbeatRequest.swift b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceHeartbeatRequest.swift index d4d14865..0ced846c 100644 --- a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceHeartbeatRequest.swift +++ b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceHeartbeatRequest.swift @@ -14,12 +14,12 @@ class PresenceHeartbeatRequest { let channels: [String] let groups: [String] let configuration: PubNubConfiguration - + private let session: SessionReplaceable private let sessionResponseQueue: DispatchQueue private let channelStates: [String: JSONCodable] private var request: RequestReplaceable? - + init( channels: [String], groups: [String], @@ -35,7 +35,7 @@ class PresenceHeartbeatRequest { self.session = session self.sessionResponseQueue = sessionResponseQueue } - + func execute(completionBlock: @escaping (Result) -> Void) { let endpoint = PresenceRouter.Endpoint.heartbeat( channels: channels, @@ -56,11 +56,11 @@ class PresenceHeartbeatRequest { } } } - + func cancel() { request?.cancel(PubNubError(.clientCancelled)) } - + func reconnectionDelay(dueTo error: PubNubError, retryAttempt: Int) -> TimeInterval? { guard let automaticRetry = configuration.automaticRetry else { return nil @@ -82,7 +82,7 @@ class PresenceHeartbeatRequest { response: urlResponse, error: underlyingError ) - + return shouldRetry ? automaticRetry.policy.delay(for: retryAttempt) : nil } } diff --git a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceInput.swift b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceInput.swift index 3a2f780c..ac1fbe2c 100644 --- a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceInput.swift +++ b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceInput.swift @@ -12,47 +12,47 @@ import Foundation struct PresenceInput: Equatable { fileprivate let channelsSet: Set fileprivate let groupsSet: Set - + init(channels: [String] = [], groups: [String] = []) { channelsSet = Set(channels) groupsSet = Set(groups) } - + fileprivate init(channels: Set, groups: Set) { channelsSet = channels groupsSet = groups } - + var channels: [String] { channelsSet.map { $0 } } - + var groups: [String] { groupsSet.map { $0 } } - + var isEmpty: Bool { channelsSet.isEmpty && groupsSet.isEmpty } - - static func +(lhs: PresenceInput, rhs: PresenceInput) -> PresenceInput { + + static func + (lhs: PresenceInput, rhs: PresenceInput) -> PresenceInput { PresenceInput( channels: lhs.channelsSet.union(rhs.channelsSet), groups: lhs.groupsSet.union(rhs.groupsSet) ) } - - static func -(lhs: PresenceInput, rhs: PresenceInput) -> PresenceInput { + + static func - (lhs: PresenceInput, rhs: PresenceInput) -> PresenceInput { PresenceInput( channels: lhs.channelsSet.subtracting(rhs.channelsSet), groups: lhs.groupsSet.subtracting(rhs.groupsSet) ) } - - static func ==(lhs: PresenceInput, rhs: PresenceInput) -> Bool { + + static func == (lhs: PresenceInput, rhs: PresenceInput) -> Bool { let equalChannels = lhs.channels.sorted(by: <) == rhs.channels.sorted(by: <) let equalGroups = lhs.groups.sorted(by: <) == rhs.groups.sorted(by: <) - + return equalChannels && equalGroups } } diff --git a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceLeaveRequest.swift b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceLeaveRequest.swift index 9e7f44e3..57bf233b 100644 --- a/Sources/PubNub/EventEngine/Presence/Helpers/PresenceLeaveRequest.swift +++ b/Sources/PubNub/EventEngine/Presence/Helpers/PresenceLeaveRequest.swift @@ -14,11 +14,11 @@ class PresenceLeaveRequest { let channels: [String] let groups: [String] let configuration: PubNubConfiguration - + private let session: SessionReplaceable private let sessionResponseQueue: DispatchQueue private var request: RequestReplaceable? - + init( channels: [String], groups: [String], @@ -32,7 +32,7 @@ class PresenceLeaveRequest { self.session = session self.sessionResponseQueue = sessionResponseQueue } - + func execute(completionBlock: @escaping (Result) -> Void) { let endpoint = PresenceRouter.Endpoint.leave( channels: channels, @@ -44,14 +44,14 @@ class PresenceLeaveRequest { ) request?.validate().response(on: sessionResponseQueue, decoder: GenericServiceResponseDecoder()) { result in switch result { - case .success(_): + case .success: completionBlock(.success(())) case .failure(let error): completionBlock(.failure(error as? PubNubError ?? PubNubError(.unknown, underlying: error))) } } } - + func cancel() { request?.cancel(PubNubError(.clientCancelled)) } diff --git a/Sources/PubNub/EventEngine/Presence/Presence.swift b/Sources/PubNub/EventEngine/Presence/Presence.swift index 553f7a15..2edc2efa 100644 --- a/Sources/PubNub/EventEngine/Presence/Presence.swift +++ b/Sources/PubNub/EventEngine/Presence/Presence.swift @@ -93,6 +93,7 @@ extension Presence { case delayedHeartbeat(channels: [String], groups: [String], retryAttempt: Int, error: PubNubError) case wait + // swiftlint:disable:next nesting enum Cancellable: AnyCancellableInvocation { case wait case delayedHeartbeat diff --git a/Sources/PubNub/EventEngine/Presence/PresenceTransition.swift b/Sources/PubNub/EventEngine/Presence/PresenceTransition.swift index 29ed3dd0..fc8f7516 100644 --- a/Sources/PubNub/EventEngine/Presence/PresenceTransition.swift +++ b/Sources/PubNub/EventEngine/Presence/PresenceTransition.swift @@ -14,24 +14,24 @@ class PresenceTransition: TransitionProtocol { typealias State = (any PresenceState) typealias Event = Presence.Event typealias Invocation = Presence.Invocation - + private let configuration: PubNubConfiguration init(configuration: PubNubConfiguration) { self.configuration = configuration } - + func canTransition(from state: State, dueTo event: Event) -> Bool { switch event { - case .joined(_,_): + case .joined: return configuration.heartbeatInterval > 0 - case .left(_,_): + case .left: return !(state is Presence.HeartbeatInactive) case .heartbeatSuccess: return state is Presence.Heartbeating || state is Presence.HeartbeatReconnecting - case .heartbeatFailed(_): + case .heartbeatFailed: return state is Presence.Heartbeating || state is Presence.HeartbeatReconnecting - case .heartbeatGiveUp(_): + case .heartbeatGiveUp: return state is Presence.HeartbeatReconnecting case .timesUp: return state is Presence.HeartbeatCooldown @@ -43,7 +43,7 @@ class PresenceTransition: TransitionProtocol { return state is Presence.HeartbeatStopped || state is Presence.HeartbeatFailed } } - + private func onEntry(to state: State) -> [EffectInvocation] { switch state { case is Presence.Heartbeating: @@ -62,7 +62,7 @@ class PresenceTransition: TransitionProtocol { return [] } } - + private func onExit(from state: State) -> [EffectInvocation] { switch state { case is Presence.HeartbeatCooldown: @@ -73,20 +73,20 @@ class PresenceTransition: TransitionProtocol { return [] } } - + func transition(from state: State, event: Event) -> TransitionResult { var results: TransitionResult - + switch event { - case .joined(let channels, let groups): + case let .joined(channels, groups): results = heartbeatingTransition(from: state, joining: (channels: channels, groups: groups)) - case .left(let channels, let groups): + case let .left(channels, groups): results = heartbeatingTransition(from: state, leaving: (channels: channels, groups: groups)) case .heartbeatSuccess: results = heartbeatSuccessTransition(from: state) - case .heartbeatFailed(let error): + case let .heartbeatFailed(error): results = heartbeatReconnectingTransition(from: state, dueTo: error) - case .heartbeatGiveUp(let error): + case let .heartbeatGiveUp(error): results = heartbeatReconnectingGiveUpTransition(from: state, dueTo: error) case .timesUp: results = heartbeatingTransition(from: state) @@ -97,7 +97,7 @@ class PresenceTransition: TransitionProtocol { case .disconnect: results = heartbeatStoppedTransition(from: state) } - + return TransitionResult( state: results.state, invocations: onExit(from: state) + results.invocations + onEntry(to: results.state) diff --git a/Sources/PubNub/EventEngine/Presence/PubNubPresenceStateContainer.swift b/Sources/PubNub/EventEngine/Presence/PubNubPresenceStateContainer.swift index 8a6b8ae6..3a578886 100644 --- a/Sources/PubNub/EventEngine/Presence/PubNubPresenceStateContainer.swift +++ b/Sources/PubNub/EventEngine/Presence/PubNubPresenceStateContainer.swift @@ -12,10 +12,10 @@ import Foundation class PubNubPresenceStateContainer { static let shared: PubNubPresenceStateContainer = PubNubPresenceStateContainer() - + private var channelStates: Atomic<[String: JSONCodable]> = Atomic([:]) private init() {} - + func registerState(_ state: JSONCodable, forChannels channels: [String]) { channelStates.lockedWrite { channelStates in channels.forEach { @@ -23,7 +23,7 @@ class PubNubPresenceStateContainer { } } } - + func removeState(forChannels channels: [String]) { channelStates.lockedWrite { channelStates in channels.map { @@ -31,7 +31,7 @@ class PubNubPresenceStateContainer { } } } - + func getStates(forChannels channels: [String]) -> [String: JSONCodable] { channelStates.lockedRead { $0.filter { @@ -39,7 +39,7 @@ class PubNubPresenceStateContainer { } } } - + func removeAll() { channelStates.lockedWrite { $0.removeAll() diff --git a/Sources/PubNub/EventEngine/Subscribe/Effects/EmitMessagesEffect.swift b/Sources/PubNub/EventEngine/Subscribe/Effects/EmitMessagesEffect.swift index 541219ef..a64a1faa 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Effects/EmitMessagesEffect.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Effects/EmitMessagesEffect.swift @@ -12,23 +12,23 @@ import Foundation class MessageCache { private(set) var messagesArray = [SubscribeMessagePayload?].init(repeating: nil, count: 100) - + init(messagesArray: [SubscribeMessagePayload?] = .init(repeating: nil, count: 100)) { self.messagesArray = messagesArray } - + var isOverflowed: Bool { return messagesArray.count >= 100 } - + func contains(_ message: SubscribeMessagePayload) -> Bool { messagesArray.contains(message) } - + func append(_ message: SubscribeMessagePayload) { messagesArray.append(message) } - + func dropTheOldest() { messagesArray.remove(at: 0) } @@ -39,7 +39,7 @@ struct EmitMessagesEffect: EffectHandler { let cursor: SubscribeCursor let listeners: [BaseSubscriptionListener] let messageCache: MessageCache - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { // Attempt to detect missed messages due to queue overflow if messages.count >= 100 { @@ -53,7 +53,7 @@ struct EmitMessagesEffect: EffectHandler { ) } } - + let filteredMessages = messages.filter { message in // Dedupe the message // Update cache and notify if not a duplicate message if !messageCache.contains(message) { @@ -66,11 +66,11 @@ struct EmitMessagesEffect: EffectHandler { } return false } - + listeners.forEach { $0.emit(batch: filteredMessages) } - + completionBlock([]) } } diff --git a/Sources/PubNub/EventEngine/Subscribe/Effects/EmitStatusEffect.swift b/Sources/PubNub/EventEngine/Subscribe/Effects/EmitStatusEffect.swift index 3fcdba57..bcb2df5d 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Effects/EmitStatusEffect.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Effects/EmitStatusEffect.swift @@ -12,7 +12,7 @@ import Foundation struct EmitStatusEffect: EffectHandler { let statusChange: Subscribe.ConnectionStatusChange let listeners: [BaseSubscriptionListener] - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { if let error = statusChange.error { listeners.forEach { diff --git a/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffectFactory.swift b/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffectFactory.swift index 6198fbfb..26085ab6 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffectFactory.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffectFactory.swift @@ -15,7 +15,7 @@ class SubscribeEffectFactory: EffectHandlerFactory { private let sessionResponseQueue: DispatchQueue private let messageCache: MessageCache private let presenceStateContainer: PubNubPresenceStateContainer - + init( session: SessionReplaceable, sessionResponseQueue: DispatchQueue = .main, @@ -27,13 +27,13 @@ class SubscribeEffectFactory: EffectHandlerFactory { self.messageCache = messageCache self.presenceStateContainer = presenceStateContainer } - + func effect( for invocation: Subscribe.Invocation, with dependencies: EventEngineDependencies ) -> any EffectHandler { switch invocation { - case .handshakeRequest(let channels, let groups): + case let .handshakeRequest(channels, groups): return HandshakeEffect( request: SubscribeRequest( configuration: dependencies.value.configuration, @@ -45,7 +45,7 @@ class SubscribeEffectFactory: EffectHandlerFactory { sessionResponseQueue: sessionResponseQueue ), listeners: dependencies.value.listeners ) - case .handshakeReconnect(let channels, let groups, let retryAttempt, let reason): + case let .handshakeReconnect(channels, groups, retryAttempt, reason): return HandshakeReconnectEffect( request: SubscribeRequest( configuration: dependencies.value.configuration, @@ -59,7 +59,7 @@ class SubscribeEffectFactory: EffectHandlerFactory { error: reason, retryAttempt: retryAttempt ) - case .receiveMessages(let channels, let groups, let cursor): + case let .receiveMessages(channels, groups, cursor): return ReceivingEffect( request: SubscribeRequest( configuration: dependencies.value.configuration, @@ -72,7 +72,7 @@ class SubscribeEffectFactory: EffectHandlerFactory { sessionResponseQueue: sessionResponseQueue ), listeners: dependencies.value.listeners ) - case .receiveReconnect(let channels, let groups, let cursor, let retryAttempt, let reason): + case let .receiveReconnect(channels, groups, cursor, retryAttempt, reason): return ReceiveReconnectEffect( request: SubscribeRequest( configuration: dependencies.value.configuration, @@ -87,21 +87,21 @@ class SubscribeEffectFactory: EffectHandlerFactory { error: reason, retryAttempt: retryAttempt ) - case .emitMessages(let messages, let cursor): + case let .emitMessages(messages, cursor): return EmitMessagesEffect( messages: messages, cursor: cursor, listeners: dependencies.value.listeners, messageCache: messageCache ) - case .emitStatus(let statusChange): + case let .emitStatus(statusChange): return EmitStatusEffect( statusChange: statusChange, listeners: dependencies.value.listeners ) } } - + deinit { session.invalidateAndCancel() } diff --git a/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffects.swift b/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffects.swift index 1a8bc78c..3df7a8ca 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffects.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Effects/SubscribeEffects.swift @@ -14,7 +14,7 @@ import Foundation class HandshakeEffect: EffectHandler { private let subscribeEffect: SubscribeEffect - + init(request: SubscribeRequest, listeners: [BaseSubscriptionListener]) { self.subscribeEffect = SubscribeEffect( request: request, @@ -23,16 +23,16 @@ class HandshakeEffect: EffectHandler { onErrorReceived: { .handshakeFailure(error: $0) } ) } - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { subscribeEffect.listeners.forEach { $0.emit(subscribe: .connectionChanged(.connecting)) } subscribeEffect.performTask(completionBlock: completionBlock) } - + func cancelTask() { subscribeEffect.cancelTask() } - + deinit { cancelTask() } @@ -51,15 +51,15 @@ class ReceivingEffect: EffectHandler { onErrorReceived: { .receiveFailure(error: $0) } ) } - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { subscribeEffect.performTask(completionBlock: completionBlock) } - + func cancelTask() { subscribeEffect.cancelTask() } - + deinit { cancelTask() } @@ -71,7 +71,7 @@ class HandshakeReconnectEffect: EffectHandler { private let subscribeEffect: SubscribeEffect private let timerEffect: TimerEffect? private let error: PubNubError - + init( request: SubscribeRequest, listeners: [BaseSubscriptionListener], @@ -90,7 +90,7 @@ class HandshakeReconnectEffect: EffectHandler { ) self.error = error } - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { guard let timerEffect = timerEffect else { completionBlock([.handshakeReconnectGiveUp(error: error)]); return @@ -99,12 +99,12 @@ class HandshakeReconnectEffect: EffectHandler { self?.subscribeEffect.performTask(completionBlock: completionBlock) } } - + func cancelTask() { timerEffect?.cancelTask() subscribeEffect.cancelTask() } - + deinit { cancelTask() } @@ -116,7 +116,7 @@ class ReceiveReconnectEffect: EffectHandler { private let subscribeEffect: SubscribeEffect private let timerEffect: TimerEffect? private let error: PubNubError - + init( request: SubscribeRequest, listeners: [BaseSubscriptionListener], @@ -135,7 +135,7 @@ class ReceiveReconnectEffect: EffectHandler { ) self.error = error } - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { subscribeEffect.listeners.forEach { $0.emit(subscribe: .connectionChanged(.reconnecting)) @@ -153,12 +153,12 @@ class ReceiveReconnectEffect: EffectHandler { self?.subscribeEffect.performTask(completionBlock: completionBlock) } } - + func cancelTask() { timerEffect?.cancelTask() subscribeEffect.cancelTask() } - + deinit { cancelTask() } @@ -166,7 +166,7 @@ class ReceiveReconnectEffect: EffectHandler { // MARK: - SubscribeEffect -fileprivate class SubscribeEffect: EffectHandler { +private class SubscribeEffect: EffectHandler { let request: SubscribeRequest let listeners: [BaseSubscriptionListener] let onResponseReceived: (SubscribeResponse) -> Subscribe.Event @@ -183,7 +183,7 @@ fileprivate class SubscribeEffect: EffectHandler { self.onResponseReceived = onResponseReceived self.onErrorReceived = onErrorReceived } - + func performTask(completionBlock: @escaping ([Subscribe.Event]) -> Void) { request.execute(onCompletion: { [weak self] in guard let selfRef = self else { return } @@ -192,8 +192,8 @@ fileprivate class SubscribeEffect: EffectHandler { selfRef.listeners.forEach { $0.emit(subscribe: .responseReceived( SubscribeResponseHeader( - channels: selfRef.request.channels.map { PubNubChannel(channel: $0)}, - groups: selfRef.request.groups.map { PubNubChannel(channel: $0)}, + channels: selfRef.request.channels.map { PubNubChannel(channel: $0) }, + groups: selfRef.request.groups.map { PubNubChannel(channel: $0) }, previous: SubscribeCursor(timetoken: selfRef.request.timetoken, region: selfRef.request.region), next: response.cursor )) @@ -205,11 +205,11 @@ fileprivate class SubscribeEffect: EffectHandler { } }) } - + func cancelTask() { request.cancel() } - + deinit { cancelTask() } diff --git a/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeInput.swift b/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeInput.swift index fc5b0457..0701d68f 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeInput.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeInput.swift @@ -13,18 +13,20 @@ import Foundation struct SubscribeInput: Equatable { private let channelEntries: [String: PubNubChannel] private let groupEntries: [String: PubNubChannel] - + + // swiftlint:disable:next large_tuple typealias InsertingResult = ( newInput: SubscribeInput, insertedChannels: [PubNubChannel], insertedGroups: [PubNubChannel] ) + // swiftlint:disable:next large_tuple typealias RemovingResult = ( newInput: SubscribeInput, removedChannels: [PubNubChannel], removedGroups: [PubNubChannel] ) - + init(channels: [PubNubChannel] = [], groups: [PubNubChannel] = []) { self.channelEntries = channels.reduce(into: [String: PubNubChannel]()) { r, channel in _ = r.insert(channel) @@ -33,32 +35,32 @@ struct SubscribeInput: Equatable { _ = r.insert(channel) } } - + private init(channels: [String: PubNubChannel], groups: [String: PubNubChannel]) { self.channelEntries = channels self.groupEntries = groups } - + var isEmpty: Bool { channelEntries.isEmpty && groupEntries.isEmpty } - + var channels: [PubNubChannel] { Array(channelEntries.values) } - + var groups: [PubNubChannel] { Array(groupEntries.values) } - + var subscribedChannelNames: [String] { channelEntries.map { $0.key } } - + var subscribedGroupNames: [String] { groupEntries.map { $0.key } } - + var allSubscribedChannelNames: [String] { channelEntries.reduce(into: [String]()) { result, entry in result.append(entry.value.id) @@ -67,7 +69,7 @@ struct SubscribeInput: Equatable { } } } - + var allSubscribedGroupNames: [String] { groupEntries.reduce(into: [String]()) { result, entry in result.append(entry.value.id) @@ -76,7 +78,7 @@ struct SubscribeInput: Equatable { } } } - + var presenceSubscribedChannelNames: [String] { channelEntries.compactMap { if $0.value.isPresenceSubscribed { @@ -86,7 +88,7 @@ struct SubscribeInput: Equatable { } } } - + var presenceSubscribedGroupNames: [String] { groupEntries.compactMap { if $0.value.isPresenceSubscribed { @@ -96,11 +98,11 @@ struct SubscribeInput: Equatable { } } } - + var totalSubscribedCount: Int { channelEntries.count + groupEntries.count } - + func adding( channels: [PubNubChannel], and groups: [PubNubChannel] @@ -108,17 +110,17 @@ struct SubscribeInput: Equatable { // Gets a copy of current channels and channel groups var currentChannels = channelEntries var currentGroups = groupEntries - + let insertedChannels = channels.filter { currentChannels.insert($0) } let insertedGroups = groups.filter { currentGroups.insert($0) } - + return InsertingResult( newInput: SubscribeInput(channels: currentChannels, groups: currentGroups), insertedChannels: insertedChannels, insertedGroups: insertedGroups ) } - + func removing( mainChannels: [PubNubChannel], presenceChannelsOnly: [PubNubChannel], @@ -128,7 +130,7 @@ struct SubscribeInput: Equatable { // Gets a copy of current channels and channel groups var currentChannels = channelEntries var currentGroups = groupEntries - + let removedChannels = mainChannels.compactMap { currentChannels.removeValue(forKey: $0.id) } + presenceChannelsOnly.compactMap { @@ -145,11 +147,11 @@ struct SubscribeInput: Equatable { removedGroups: removedGroups ) } - - static func ==(lhs: SubscribeInput, rhs: SubscribeInput) -> Bool { + + static func == (lhs: SubscribeInput, rhs: SubscribeInput) -> Bool { let equalChannels = lhs.allSubscribedChannelNames.sorted(by: <) == rhs.allSubscribedChannelNames.sorted(by: <) let equalGroups = lhs.allSubscribedGroupNames.sorted(by: <) == rhs.allSubscribedGroupNames.sorted(by: <) - + return equalChannels && equalGroups } } diff --git a/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeRequest.swift b/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeRequest.swift index 84046296..2693d66b 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeRequest.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Helpers/SubscribeRequest.swift @@ -15,17 +15,17 @@ class SubscribeRequest { let groups: [String] let timetoken: Timetoken? let region: Int? - + private let configuration: PubNubConfiguration private let session: SessionReplaceable private let sessionResponseQueue: DispatchQueue private let channelStates: [String: JSONCodable] - + private var request: RequestReplaceable? - + var retryLimit: UInt { configuration.automaticRetry?.retryLimit ?? 0 } var onAuthChallengeReceived: (() -> Void)? - + init( configuration: PubNubConfiguration, channels: [String], @@ -44,14 +44,14 @@ class SubscribeRequest { self.region = region self.session = session self.sessionResponseQueue = sessionResponseQueue - + if let sessionListener = session.sessionStream as? SessionListener { sessionListener.sessionDidReceiveChallenge = { [weak self] _, _ in self?.onAuthChallengeReceived?() } } } - + func reconnectionDelay(dueTo error: PubNubError, retryAttempt: Int) -> TimeInterval? { guard let automaticRetry = configuration.automaticRetry else { return nil @@ -74,7 +74,7 @@ class SubscribeRequest { ) return shouldRetry ? automaticRetry.policy.delay(for: retryAttempt) : nil } - + func execute(onCompletion: @escaping (Result) -> Void) { let router = SubscribeRouter( .subscribe( @@ -82,7 +82,7 @@ class SubscribeRequest { groups: groups, channelStates: channelStates, timetoken: timetoken, - region: region?.description ?? nil, + region: region?.description, heartbeat: configuration.durationUntilTimeout, filter: configuration.filterExpression ), @@ -105,12 +105,12 @@ class SubscribeRequest { } ) } - + func cancel() { onAuthChallengeReceived = nil request?.cancel(PubNubError(.clientCancelled)) } - + deinit { cancel() } diff --git a/Sources/PubNub/EventEngine/Subscribe/Subscribe.swift b/Sources/PubNub/EventEngine/Subscribe/Subscribe.swift index 43d1065e..c5a8ba8a 100644 --- a/Sources/PubNub/EventEngine/Subscribe/Subscribe.swift +++ b/Sources/PubNub/EventEngine/Subscribe/Subscribe.swift @@ -101,6 +101,7 @@ extension Subscribe { } struct UnsubscribedState: SubscribeState { + // swiftlint:disable:next force_unwrapping let cursor: SubscribeCursor = .init(timetoken: 0)! let input: SubscribeInput = .init() let connectionStatus = ConnectionStatus.disconnected @@ -160,6 +161,7 @@ extension Subscribe { case emitStatus(change: Subscribe.ConnectionStatusChange) case emitMessages(events: [SubscribeMessagePayload], forCursor: SubscribeCursor) + // swiftlint:disable:next nesting enum Cancellable: AnyCancellableInvocation { case handshakeRequest case handshakeReconnect diff --git a/Sources/PubNub/EventEngine/Subscribe/SubscribeTransition.swift b/Sources/PubNub/EventEngine/Subscribe/SubscribeTransition.swift index 10af338b..31a2bd53 100644 --- a/Sources/PubNub/EventEngine/Subscribe/SubscribeTransition.swift +++ b/Sources/PubNub/EventEngine/Subscribe/SubscribeTransition.swift @@ -14,32 +14,33 @@ class SubscribeTransition: TransitionProtocol { typealias State = (any SubscribeState) typealias Event = Subscribe.Event typealias Invocation = Subscribe.Invocation - + + // swiftlint:disable:next cyclomatic_complexity func canTransition(from state: State, dueTo event: Event) -> Bool { switch event { - case .handshakeSuccess(_): + case .handshakeSuccess: return state is Subscribe.HandshakingState - case .handshakeFailure(_): + case .handshakeFailure: return state is Subscribe.HandshakingState - case .handshakeReconnectSuccess(_): + case .handshakeReconnectSuccess: return state is Subscribe.HandshakeReconnectingState - case .handshakeReconnectFailure(_): + case .handshakeReconnectFailure: return state is Subscribe.HandshakeReconnectingState - case .handshakeReconnectGiveUp(_): + case .handshakeReconnectGiveUp: return state is Subscribe.HandshakeReconnectingState - case .receiveSuccess(_,_): + case .receiveSuccess: return state is Subscribe.ReceivingState - case .receiveFailure(_): + case .receiveFailure: return state is Subscribe.ReceivingState - case .receiveReconnectSuccess(_,_): + case .receiveReconnectSuccess: return state is Subscribe.ReceiveReconnectingState - case .receiveReconnectFailure(_): + case .receiveReconnectFailure: return state is Subscribe.ReceiveReconnectingState - case .receiveReconnectGiveUp(_): + case .receiveReconnectGiveUp: return state is Subscribe.ReceiveReconnectingState - case .subscriptionChanged(_, _): + case .subscriptionChanged: return true - case .subscriptionRestored(_, _, _): + case .subscriptionRestored: return true case .unsubscribeAll: return true @@ -56,7 +57,7 @@ class SubscribeTransition: TransitionProtocol { ) } } - + private func onExit(from state: State) -> [EffectInvocation] { switch state { case is Subscribe.HandshakingState: @@ -71,7 +72,7 @@ class SubscribeTransition: TransitionProtocol { return [] } } - + private func onEntry(to state: State) -> [EffectInvocation] { switch state { case let state as Subscribe.HandshakingState: @@ -120,49 +121,50 @@ class SubscribeTransition: TransitionProtocol { return [] } } - + + // swiftlint:disable:next cyclomatic_complexity func transition(from state: State, event: Event) -> TransitionResult { var results: TransitionResult - + switch event { - case .handshakeSuccess(let cursor): + case let .handshakeSuccess(cursor): results = setReceivingState(from: state, cursor: resolveCursor(for: state, new: cursor)) - case .handshakeFailure(let error): + case let .handshakeFailure(error): results = setHandshakeReconnectingState(from: state, error: error) - case .handshakeReconnectSuccess(let cursor): + case let .handshakeReconnectSuccess(cursor): results = setReceivingState(from: state, cursor: resolveCursor(for: state, new: cursor)) - case .handshakeReconnectFailure(let error): + case let .handshakeReconnectFailure(error): results = setHandshakeReconnectingState(from: state, error: error) - case .handshakeReconnectGiveUp(let error): + case let .handshakeReconnectGiveUp(error): results = setHandshakeFailedState(from: state, error: error) - case .receiveSuccess(let cursor, let messages): + case let .receiveSuccess(cursor, messages): results = setReceivingState(from: state, cursor: cursor, messages: messages) case .receiveFailure(let error): results = setReceiveReconnectingState(from: state, error: error) - case .receiveReconnectSuccess(let cursor, let messages): + case let .receiveReconnectSuccess(cursor, messages): results = setReceivingState(from: state, cursor: cursor, messages: messages) - case .receiveReconnectFailure(let error): + case let .receiveReconnectFailure(error): results = setReceiveReconnectingState(from: state, error: error) - case .receiveReconnectGiveUp(let error): + case let .receiveReconnectGiveUp(error): results = setReceiveFailedState(from: state, error: error) - case .subscriptionChanged(let channels, let groups): + case let .subscriptionChanged(channels, groups): results = onSubscriptionAltered(from: state, channels: channels, groups: groups, cursor: state.cursor) - case .subscriptionRestored(let channels, let groups, let cursor): + case let .subscriptionRestored(channels, groups, cursor): results = onSubscriptionAltered(from: state, channels: channels, groups: groups, cursor: cursor) case .disconnect: results = setStoppedState(from: state) case .unsubscribeAll: results = setUnsubscribedState(from: state) - case .reconnect(let cursor): + case let .reconnect(cursor): results = setHandshakingState(from: state, cursor: cursor) } - + return TransitionResult( state: results.state, invocations: onExit(from: state) + results.invocations + onEntry(to: results.state) ) } - + private func resolveCursor( for currentState: State, new cursor: SubscribeCursor @@ -178,6 +180,7 @@ class SubscribeTransition: TransitionProtocol { } fileprivate extension SubscribeTransition { + // swiftlint:disable:next cyclomatic_complexity func onSubscriptionAltered( from state: State, channels: [String], @@ -188,7 +191,7 @@ fileprivate extension SubscribeTransition { channels: channels.map { PubNubChannel(channel: $0) }, groups: groups.map { PubNubChannel(channel: $0) } ) - + if newInput.isEmpty { return setUnsubscribedState(from: state) } else { @@ -282,7 +285,7 @@ fileprivate extension SubscribeTransition { error: nil )) ) - + if state is Subscribe.HandshakingState || state is Subscribe.HandshakeReconnectingState { return TransitionResult( state: Subscribe.ReceivingState(input: state.input, cursor: cursor), @@ -354,7 +357,7 @@ fileprivate extension SubscribeTransition { state: Subscribe.ReceiveStoppedState(input: state.input, cursor: state.cursor), invocations: invocations ) - + switch state { case is Subscribe.HandshakingState: return handshakeStoppedTransition diff --git a/Sources/PubNub/Events/New/Entities/EntityCreator.swift b/Sources/PubNub/Events/New/Entities/EntityCreator.swift index b8382985..ed05acd6 100644 --- a/Sources/PubNub/Events/New/Entities/EntityCreator.swift +++ b/Sources/PubNub/Events/New/Entities/EntityCreator.swift @@ -22,14 +22,14 @@ public protocol EntityCreator { /// - name: The unique identifier for the channel. /// - Returns: A `ChannelRepresentation` object representing the channel. func channel(_ name: String) -> ChannelRepresentation - + /// Creates a new channel group entity the user can subscribe to. /// /// - Parameters: /// - name: The unique identifier for the channel group. /// - Returns: A `ChannelGroupRepresentation` object representing the channel group. func channelGroup(_ name: String) -> ChannelGroupRepresentation - + /// Creates user metadata entity the user can subscribe to. /// /// This method does not create any entity, either locally or remotely; it merely provides @@ -39,7 +39,7 @@ public protocol EntityCreator { /// - name: The unique identifier for the user metadata. /// - Returns: A `UserMetadataRepresentation` object representing the user metadata. func userMetadata(_ name: String) -> UserMetadataRepresentation - + /// Creates channel metadata entity the user can subscribe to. /// /// This method does not create any entity, either locally or remotely; it merely provides @@ -80,7 +80,7 @@ public extension EntityCreator { protocol SubscribeReceiver: AnyObject { func registerAdapter(_ adapter: BaseSubscriptionListenerAdapter) func hasRegisteredAdapter(with uuid: UUID) -> Bool - + func internalSubscribe( with channels: [Subscription], and groups: [Subscription], diff --git a/Sources/PubNub/Events/New/EventEmitter.swift b/Sources/PubNub/Events/New/EventEmitter.swift index 232df6c4..f8ce4534 100644 --- a/Sources/PubNub/Events/New/EventEmitter.swift +++ b/Sources/PubNub/Events/New/EventEmitter.swift @@ -102,7 +102,7 @@ extension EventEmitter { // into concrete events for the user. protocol SubscribeMessagesReceiver: AnyObject { // A dictionary representing the names of the underlying subscriptions - var subscriptionTopology: [SubscribableType : [String]] { get } + var subscriptionTopology: [SubscribableType: [String]] { get } // This method should return an array of `PubNubEvent` instances, // representing the concrete events for the user. @discardableResult func onPayloadsReceived(payloads: [SubscribeMessagePayload]) -> [PubNubEvent] @@ -112,18 +112,18 @@ protocol SubscribeMessagesReceiver: AnyObject { // and either `Subscription` or `SubscriptionSet`, forwarding the received payloads. class BaseSubscriptionListenerAdapter: BaseSubscriptionListener { private(set) weak var receiver: SubscribeMessagesReceiver? - + init(receiver: SubscribeMessagesReceiver, uuid: UUID, queue: DispatchQueue) { self.receiver = receiver super.init(queue: queue, uuid: uuid) } - + override func emit(batch: [SubscribeMessagePayload]) { if let receiver = receiver { receiver.onPayloadsReceived(payloads: batch) } } - + deinit { cancel() } diff --git a/Sources/PubNub/Events/New/Extensions/SubscribeMessagePayload+PubNubEvent.swift b/Sources/PubNub/Events/New/Extensions/SubscribeMessagePayload+PubNubEvent.swift index 2b100071..21b37b8c 100644 --- a/Sources/PubNub/Events/New/Extensions/SubscribeMessagePayload+PubNubEvent.swift +++ b/Sources/PubNub/Events/New/Extensions/SubscribeMessagePayload+PubNubEvent.swift @@ -11,6 +11,7 @@ import Foundation extension SubscribeMessagePayload { + // swiftlint:disable:next cyclomatic_complexity func asPubNubEvent() -> PubNubEvent { switch messageType { case .message: diff --git a/Sources/PubNub/Events/New/Subscribable.swift b/Sources/PubNub/Events/New/Subscribable.swift index 50fb1f73..d7d49887 100644 --- a/Sources/PubNub/Events/New/Subscribable.swift +++ b/Sources/PubNub/Events/New/Subscribable.swift @@ -38,7 +38,7 @@ public class Subscribable: Subscriber { weak var receiver: SubscribeReceiver? /// An underlying subscription type let subscriptionType: SubscribableType - + init(name: String, subscriptionType: SubscribableType, receiver: SubscribeReceiver) { self.name = name self.subscriptionType = subscriptionType @@ -96,32 +96,32 @@ public typealias SubscriptionInterface = EventEmitter & SubscriptionDisposable & /// Use this class to define various subscription options that can be applied. public class SubscriptionOptions { let allOptions: [SubscriptionOptions] - + init(allOptions: [SubscriptionOptions] = []) { self.allOptions = allOptions } - + convenience init() { self.init(allOptions: []) } - + func filterCriteriaSatisfied(event: PubNubEvent) -> Bool { allOptions.compactMap { $0 as? FilterOption - }.reduce(into: true, { filteringResult, filter in - filteringResult = filteringResult && filter.predicate(event) - }) + }.allSatisfy { filter in + filter.predicate(event) + } } - + func hasPresenceOption() -> Bool { !(allOptions.filter { $0 is ReceivePresenceEvents }.isEmpty) } - + /// Provides an instance of `PubNubSubscriptionOptions` with no additional options. public static func empty() -> SubscriptionOptions { SubscriptionOptions(allOptions: []) } - + /// Combines two instances of `PubNubSubscriptionOptions` using the `+` operator. /// /// - Parameters: @@ -129,13 +129,13 @@ public class SubscriptionOptions { /// - rhs: The right-hand side instance. /// /// - Returns: A new `SubscriptionOptions` instance combining the options from both instances. - public static func +( + public static func + ( lhs: SubscriptionOptions, rhs: SubscriptionOptions ) -> SubscriptionOptions { var lhsOptions: [SubscriptionOptions] = lhs.allOptions var rhsOptions: [SubscriptionOptions] = rhs.allOptions - + if lhs.allOptions.isEmpty { lhsOptions = [lhs] } diff --git a/Sources/PubNub/Events/New/Subscription.swift b/Sources/PubNub/Events/New/Subscription.swift index 42817e77..8dd34ae5 100644 --- a/Sources/PubNub/Events/New/Subscription.swift +++ b/Sources/PubNub/Events/New/Subscription.swift @@ -30,7 +30,7 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { self.entity = entity self.options = SubscriptionOptions.empty() + options } - + public let queue: DispatchQueue /// A unique identifier for `Subscription` public let uuid: UUID = UUID() @@ -42,7 +42,7 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { public private(set) var isDisposed = false // Stores the timetoken the user subscribed with private(set) var timetoken: Timetoken? - + public var onEvent: ((PubNubEvent) -> Void)? public var onEvents: (([PubNubEvent]) -> Void)? public var onMessage: ((PubNubMessage) -> Void)? @@ -51,26 +51,26 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { public var onMessageAction: ((PubNubMessageActionEvent) -> Void)? public var onFileEvent: ((PubNubFileChangeEvent) -> Void)? public var onAppContext: ((PubNubAppContextEvent) -> Void)? - + // Intercepts messages from the Subscribe loop and forwards them to the current `Subscription` lazy var adapter = BaseSubscriptionListenerAdapter( receiver: self, uuid: uuid, queue: queue ) - + internal var receiver: SubscribeReceiver? { entity.receiver } - + internal var subscriptionType: SubscribableType { entity.subscriptionType } - + internal var subscriptionNames: [String] { let hasPresenceOption = options.hasPresenceOption() let name = entity.name - + switch entity { case is ChannelRepresentation: return hasPresenceOption ? [name, name.presenceChannelName] : [name] @@ -80,7 +80,7 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { return [entity.name] } } - + /// Creates a clone of the current instance of `Subscription`. /// /// Use this method to create a new instance with the same configuration as the current `Subscription`. @@ -96,7 +96,7 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { } return clonedSubscription } - + /// Disposes the current `Subscription`, ending the subscription. /// /// Use this method to gracefully end the subscription and release associated resources. @@ -106,7 +106,7 @@ public final class Subscription: EventEmitter, SubscriptionDisposable { unsubscribe() isDisposed = true } - + deinit { dispose() } @@ -145,10 +145,10 @@ extension Subscription: SubscribeCapable { } extension Subscription: Hashable { - public static func ==(lhs: Subscription, rhs: Subscription) -> Bool { + public static func == (lhs: Subscription, rhs: Subscription) -> Bool { lhs.uuid == rhs.uuid } - + public func hash(into hasher: inout Hasher) { hasher.combine(uuid) } @@ -157,20 +157,20 @@ extension Subscription: Hashable { // MARK: - SubscribeMessagePayloadReceiver extension Subscription: SubscribeMessagesReceiver { - var subscriptionTopology: [SubscribableType : [String]] { + var subscriptionTopology: [SubscribableType: [String]] { [subscriptionType: subscriptionNames] } - + @discardableResult func onPayloadsReceived(payloads: [SubscribeMessagePayload]) -> [PubNubEvent] { let events = payloads.compactMap { event(from: $0) } emit(events: events) return events } - + func event(from payload: SubscribeMessagePayload) -> PubNubEvent? { let isNewerOrEqualToTimetoken = payload.publishTimetoken.timetoken >= timetoken ?? 0 let isMatchingEntity: Bool - + if subscriptionType == .channel { isMatchingEntity = isMatchingEntityName(entity.name, string: payload.channel) } else if subscriptionType == .channelGroup { @@ -178,7 +178,7 @@ extension Subscription: SubscribeMessagesReceiver { } else { isMatchingEntity = true } - + if isMatchingEntity && isNewerOrEqualToTimetoken { let event = payload.asPubNubEvent() return options.filterCriteriaSatisfied(event: event) ? event : nil @@ -186,7 +186,7 @@ extension Subscription: SubscribeMessagesReceiver { return nil } } - + fileprivate func isMatchingEntityName(_ entityName: String, string: String) -> Bool { guard entityName.hasSuffix(".*") else { return entityName == string diff --git a/Sources/PubNub/Events/New/SubscriptionSet.swift b/Sources/PubNub/Events/New/SubscriptionSet.swift index 6702f95a..f93d2c5c 100644 --- a/Sources/PubNub/Events/New/SubscriptionSet.swift +++ b/Sources/PubNub/Events/New/SubscriptionSet.swift @@ -22,7 +22,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { public var onMessageAction: ((PubNubMessageActionEvent) -> Void)? public var onFileEvent: ((PubNubFileChangeEvent) -> Void)? public var onAppContext: ((PubNubAppContextEvent) -> Void)? - + public let queue: DispatchQueue /// Additional subscription options public let options: SubscriptionOptions @@ -32,7 +32,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { public private(set) var isDisposed = false // Internally holds a collection of child subscriptions private(set) var currentSubscriptions: Set - + // Internally intercepts messages from the Subscribe loop // and forwards them to the current `SubscriptionSet` lazy var adapter = BaseSubscriptionListenerAdapter( @@ -40,7 +40,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { uuid: uuid, queue: queue ) - + /// Initializes `SubscriptionSet` object with the specified parameters. /// /// - Parameters: @@ -62,7 +62,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { ) }) } - + /// Initializes `SubscriptionSet` object with the specified parameters. /// /// - Parameters: @@ -78,7 +78,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { self.options = options self.currentSubscriptions = Set(subscriptions) } - + /// Adds `Subscription` to the existing set of subscriptions. /// /// - Parameters: @@ -86,7 +86,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { public func add(subscription: Subscription) { currentSubscriptions.insert(subscription) } - + /// Adds a collection of `Subscription` to the existing set of subscriptions. /// /// - Parameters: @@ -96,7 +96,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { currentSubscriptions.insert($0) } } - + /// Removes `Subscription` from the existing set of subscriptions. /// /// - Parameters: @@ -104,7 +104,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { public func remove(subscription: Subscription) { currentSubscriptions.remove(subscription) } - + /// Removes a collection of `Subscription` from the existing set of subscriptions. /// /// - Parameters: @@ -114,7 +114,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { currentSubscriptions.remove($0) } } - + /// Creates a clone of the current instance of `SubscriptionSet`. /// /// Use this method to create a new instance with the same configuration as the current `SubscriptionSet`. @@ -130,7 +130,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { } return clonedSubscriptionSet } - + /// Disposes of the current instance of `SubscriptionSet`, ending all associated subscriptions. /// /// Use this method to gracefully end the subscription and release associated resources. @@ -140,7 +140,7 @@ public final class SubscriptionSet: EventEmitter, SubscriptionDisposable { currentSubscriptions.forEach { $0.dispose() } isDisposed = true } - + deinit { dispose() } @@ -160,22 +160,22 @@ extension SubscriptionSet: SubscribeCapable { } receiver.registerAdapter(adapter) currentSubscriptions.forEach { receiver.registerAdapter($0.adapter) } - + let channels = currentSubscriptions.filter { $0.subscriptionType == .channel }.allObjects - + let groups = currentSubscriptions.filter { $0.subscriptionType == .channelGroup }.allObjects - + receiver.internalSubscribe( with: channels, and: groups, at: timetoken ) } - + /// Unsubscribes from all entities within the current `SubscriptionSet`. If there are no remaining /// subscriptions that match the associated entities, the unsubscribe action will be performed, /// and the entities will be deregistered from the Subscribe loop. @@ -185,7 +185,7 @@ extension SubscriptionSet: SubscribeCapable { public func unsubscribe() { guard let receiver = currentSubscriptions.first?.receiver, !isDisposed else { return - } + } receiver.internalUnsubscribe( from: currentSubscriptions.filter { $0.subscriptionType == .channel }, and: currentSubscriptions.filter { $0.subscriptionType == .channelGroup }, @@ -197,18 +197,18 @@ extension SubscriptionSet: SubscribeCapable { // MARK: - SubscribeMessagePayloadReceiver extension SubscriptionSet: SubscribeMessagesReceiver { - var subscriptionTopology: [SubscribableType : [String]] { + var subscriptionTopology: [SubscribableType: [String]] { var result: [SubscribableType: [String]] = [:] result[.channel] = [] result[.channelGroup] = [] - + return currentSubscriptions.reduce(into: result, { accumulatedRes, current in let currentRes = current.subscriptionTopology accumulatedRes[.channel]?.append(contentsOf: currentRes[.channel] ?? []) accumulatedRes[.channelGroup]?.append(contentsOf: currentRes[.channelGroup] ?? []) }) } - + // Processes payloads according to the following rules: // // 1. Gets a subscription from the associated list of child subscriptions @@ -232,8 +232,8 @@ extension SubscriptionSet: Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(uuid) } - - public static func ==(lhs: SubscriptionSet, rhs: SubscriptionSet) -> Bool { + + public static func == (lhs: SubscriptionSet, rhs: SubscriptionSet) -> Bool { lhs.uuid == rhs.uuid } } diff --git a/Sources/PubNub/Events/Old/Subscription/SubscriptionStream.swift b/Sources/PubNub/Events/Old/Subscription/SubscriptionStream.swift index 62d805c6..34bc88f7 100644 --- a/Sources/PubNub/Events/Old/Subscription/SubscriptionStream.swift +++ b/Sources/PubNub/Events/Old/Subscription/SubscriptionStream.swift @@ -196,6 +196,7 @@ public final class CoreListener: BaseSubscriptionListener { } } + // swiftlint:disable:next cyclomatic_complexity override public func emit(batch: [SubscribeMessagePayload]) { emitDidReceive(subscription: batch.map { message in switch message.messageType { @@ -312,7 +313,7 @@ open class BaseSubscriptionListener: EventStreamReceiver, Hashable { self.queue = queue self.uuid = UUID() } - + init(queue: DispatchQueue = .main, uuid: UUID = UUID()) { self.queue = queue self.uuid = uuid @@ -328,7 +329,7 @@ open class BaseSubscriptionListener: EventStreamReceiver, Hashable { public func hash(into hasher: inout Hasher) { hasher.combine(uuid) } - + public static func == (lhs: BaseSubscriptionListener, rhs: BaseSubscriptionListener) -> Bool { return lhs.uuid == rhs.uuid } diff --git a/Sources/PubNub/Extensions/URL+PubNub.swift b/Sources/PubNub/Extensions/URL+PubNub.swift index f09bde35..c2c09b64 100644 --- a/Sources/PubNub/Extensions/URL+PubNub.swift +++ b/Sources/PubNub/Extensions/URL+PubNub.swift @@ -53,7 +53,6 @@ public extension URL { var contentType: String { #if canImport(UniformTypeIdentifiers) if #available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) { - // swiftlint:disable:next line_length guard let contentType = try? self.resourceValues(forKeys: [.contentTypeKey]).contentType?.preferredMIMEType else { return "application/octet-stream" } diff --git a/Sources/PubNub/Extensions/URLQueryItem+PubNub.swift b/Sources/PubNub/Extensions/URLQueryItem+PubNub.swift index d309d8fb..ec7f9863 100644 --- a/Sources/PubNub/Extensions/URLQueryItem+PubNub.swift +++ b/Sources/PubNub/Extensions/URLQueryItem+PubNub.swift @@ -52,13 +52,13 @@ public extension Array where Element == URLQueryItem { internal mutating func appendIfPresent(key: QueryKey, value: String?) { appendIfPresent(name: key.rawValue, value: value) } - + internal mutating func append(key: QueryKey, value: @autoclosure () -> String?, when condition: Bool) { if condition { append(URLQueryItem(name: key.rawValue, value: value())) } } - + internal mutating func appendIfPresent(key: QueryKey, value: @autoclosure () -> String?, when condition: Bool) { guard condition else { return @@ -67,7 +67,7 @@ public extension Array where Element == URLQueryItem { append(URLQueryItem(name: key.rawValue, value: value)) } } - + /// Creates a new query item with a csv string value and appends only if the value is not empty mutating func appendIfNotEmpty(name: String, value: [String]) { if !value.isEmpty { diff --git a/Sources/PubNub/Extensions/URLRequest+PubNub.swift b/Sources/PubNub/Extensions/URLRequest+PubNub.swift index 4e9eb7d5..a89c0d2f 100644 --- a/Sources/PubNub/Extensions/URLRequest+PubNub.swift +++ b/Sources/PubNub/Extensions/URLRequest+PubNub.swift @@ -51,10 +51,10 @@ public extension URLRequest { guard let contentStream = content.inputStream else { throw PubNubError(.streamCouldNotBeInitialized, additional: [content.debugDescription]) } - + let finalStream: InputStream let contentLength: Int - + // If we were given a Crypto module we should convert the stream to a secure stream if let cryptoModule = cryptoModule { switch cryptoModule.encrypt(stream: contentStream, contentLength: content.contentLength) { @@ -63,7 +63,7 @@ public extension URLRequest { contentLength = prefixData.count + ((encryptingResult as? MultipartInputStream)?.length ?? 0) + postfixData.count case .failure(let encryptionError): throw encryptionError - } + } } else { finalStream = contentStream contentLength = prefixData.count + content.contentLength + postfixData.count @@ -71,7 +71,7 @@ public extension URLRequest { setValue("\(contentLength)", forHTTPHeaderField: "Content-Length") setValue("multipart/form-data; boundary=\(response.fileId)", forHTTPHeaderField: "Content-Type") - + httpBodyStream = MultipartInputStream( inputStreams: [InputStream(data: prefixData), finalStream, InputStream(data: postfixData)] ) diff --git a/Sources/PubNub/Extensions/URLSessionConfiguration+PubNub.swift b/Sources/PubNub/Extensions/URLSessionConfiguration+PubNub.swift index f95245c7..69361dd7 100644 --- a/Sources/PubNub/Extensions/URLSessionConfiguration+PubNub.swift +++ b/Sources/PubNub/Extensions/URLSessionConfiguration+PubNub.swift @@ -49,7 +49,7 @@ public extension URLSessionConfiguration { static var subscription: URLSessionConfiguration { let configuration = URLSessionConfiguration.pubnub configuration.timeoutIntervalForRequest += Constant.minimumSubscribeRequestTimeout - configuration.httpMaximumConnectionsPerHost = 1; + configuration.httpMaximumConnectionsPerHost = 1 return configuration } diff --git a/Sources/PubNub/Helpers/AnyJSONType.swift b/Sources/PubNub/Helpers/AnyJSONType.swift index 749f4c74..29278533 100644 --- a/Sources/PubNub/Helpers/AnyJSONType.swift +++ b/Sources/PubNub/Helpers/AnyJSONType.swift @@ -369,10 +369,10 @@ extension AnyJSONType: Hashable { return true case let (.array(lhsArray), .array(rhsArray)): if lhsArray.count == rhsArray.count { - for (index, lhsValue) in lhsArray.enumerated() { - if AnyJSONType(rawValue: lhsValue) != AnyJSONType(rawValue: rhsArray[index]) { - return false - } + for (index, lhsValue) in lhsArray.enumerated() where AnyJSONType( + rawValue: lhsValue + ) != AnyJSONType(rawValue: rhsArray[index]) { + return false } return true } diff --git a/Sources/PubNub/Helpers/Constants.swift b/Sources/PubNub/Helpers/Constants.swift index 8c287679..1c7ddc70 100644 --- a/Sources/PubNub/Helpers/Constants.swift +++ b/Sources/PubNub/Helpers/Constants.swift @@ -162,7 +162,7 @@ public extension Constant { /// Produces a `User-Agent` header according to /// [RFC7231 section 5.5.3](https://tools.ietf.org/html/rfc7231#section-5.5.3) static let userAgentHeaderKey = "User-Agent" - + /// A header indicating how long to wait before making a new request /// [RFC6585 section 4](https://datatracker.ietf.org/doc/html/rfc6585#section-4) static let retryAfterHeaderKey = "Retry-After" diff --git a/Sources/PubNub/Helpers/Crypto/Crypto.swift b/Sources/PubNub/Helpers/Crypto/Crypto.swift index 3056c8f0..97e8d6d6 100644 --- a/Sources/PubNub/Helpers/Crypto/Crypto.swift +++ b/Sources/PubNub/Helpers/Crypto/Crypto.swift @@ -19,7 +19,7 @@ public struct Crypto: Hashable { let key: String /// Whether random initialization vector should be used let randomizeIV: Bool - + public init(key: String, withRandomIV: Bool = true) { self.key = key self.randomizeIV = withRandomIV diff --git a/Sources/PubNub/Helpers/Crypto/CryptoModule.swift b/Sources/PubNub/Helpers/Crypto/CryptoModule.swift index fdfe29fa..dcbd8995 100644 --- a/Sources/PubNub/Helpers/Crypto/CryptoModule.swift +++ b/Sources/PubNub/Helpers/Crypto/CryptoModule.swift @@ -26,9 +26,9 @@ public struct CryptoModule { private let defaultCryptor: any Cryptor private let cryptors: [any Cryptor] private let legacyCryptorId: CryptorId = [] - + typealias Base64EncodedString = String - + /// Initializes `CryptoModule` with custom ``Cryptor`` objects capable of encryption and decryption /// /// Use this constructor if you would like to provide **custom** objects for decryption and encryption @@ -43,7 +43,7 @@ public struct CryptoModule { self.defaultCryptor = cryptor self.cryptors = cryptors } - + /// Encrypts the given `Data` object /// /// - Parameters: @@ -70,7 +70,7 @@ public struct CryptoModule { PubNubError(.encryptionFailure, underlying: $0) } } - + /// Decrypts the given `Data` object /// /// - Parameters: @@ -87,7 +87,7 @@ public struct CryptoModule { } do { let header = try CryptorHeader.from(data: data) - + guard let cryptor = cryptor(matching: header) else { return .failure(PubNubError( .unknownCryptorFailure, @@ -97,10 +97,10 @@ public struct CryptoModule { ] )) } - + let metadata: Data let contentData: Data - + switch header { case .none: metadata = Data() @@ -110,7 +110,7 @@ public struct CryptoModule { contentData = data.suffix(from: offset + dataLength) metadata = data.subdata(in: offset.. (any Cryptor)? { header.cryptorId() == defaultCryptor.id ? defaultCryptor : cryptors.first(where: { $0.id == header.cryptorId() @@ -268,7 +268,7 @@ public extension CryptoModule { static func aesCbcCryptoModule(with key: String, withRandomIV: Bool = true) -> CryptoModule { CryptoModule(default: AESCBCCryptor(key: key), cryptors: [LegacyCryptor(key: key, withRandomIV: withRandomIV)]) } - + /// Returns legacy `CryptoModule` for encryption/decryption /// /// - Parameters: @@ -281,7 +281,7 @@ public extension CryptoModule { } extension CryptoModule: Equatable { - public static func ==(lhs: CryptoModule, rhs: CryptoModule) -> Bool { + public static func == (lhs: CryptoModule, rhs: CryptoModule) -> Bool { lhs.cryptors.map { $0.id } == rhs.cryptors.map { $0.id } } } @@ -312,7 +312,7 @@ extension CryptoModule { $0.base64EncodedString() } } - + func decryptedString(from data: Data) -> Result { decrypt(data: data).flatMap { if let stringValue = String(data: $0, encoding: .utf8) { diff --git a/Sources/PubNub/Helpers/Crypto/Cryptors/AESCBCCryptor.swift b/Sources/PubNub/Helpers/Crypto/Cryptors/AESCBCCryptor.swift index a5b067ac..4aa4d1b8 100644 --- a/Sources/PubNub/Helpers/Crypto/Cryptors/AESCBCCryptor.swift +++ b/Sources/PubNub/Helpers/Crypto/Cryptors/AESCBCCryptor.swift @@ -14,20 +14,20 @@ import CommonCrypto /// Provides PubNub's **recommended** ``Cryptor`` for encryption/decryption public struct AESCBCCryptor: Cryptor { private let key: Data - + public init(key: String) { self.key = CryptorUtils.SHA256.hash(from: key.data(using: .utf8) ?? Data()) } - + public var id: CryptorId { [0x41, 0x43, 0x52, 0x48] } - + public func encrypt(data: Data) -> Result { do { let ivGenerator = CryptorVector.random(bytesCount: kCCBlockSizeAES128) let ivData = try ivGenerator.data() - + let encrypted = try data.crypt( operation: CCOperation(kCCEncrypt), algorithm: CCAlgorithm(kCCAlgorithmAES128), @@ -37,7 +37,7 @@ public struct AESCBCCryptor: Cryptor { initializationVector: ivData, messageData: data ) - + return .success(EncryptedData( metadata: ivData, data: encrypted @@ -49,7 +49,7 @@ public struct AESCBCCryptor: Cryptor { )) } } - + public func decrypt(data: EncryptedData) -> Result { do { if data.data.isEmpty { @@ -76,12 +76,12 @@ public struct AESCBCCryptor: Cryptor { )) } } - + public func encrypt(stream: InputStream, contentLength: Int) -> Result { do { let ivGenerator = CryptorVector.random(bytesCount: kCCBlockSizeAES128) let ivData = try ivGenerator.data() - + let cryptoInputStreamCipher = CryptoInputStream.Cipher( algorithm: CCAlgorithm(kCCAlgorithmAES128), blockSize: kCCBlockSizeAES128 @@ -110,7 +110,7 @@ public struct AESCBCCryptor: Cryptor { )) } } - + public func decrypt(data: EncryptedStreamData, outputPath: URL) -> Result { do { let cryptoInputStreamCipher = CryptoInputStream.Cipher( diff --git a/Sources/PubNub/Helpers/Crypto/Cryptors/LegacyCryptor.swift b/Sources/PubNub/Helpers/Crypto/Cryptors/LegacyCryptor.swift index af0fa871..4a404336 100644 --- a/Sources/PubNub/Helpers/Crypto/Cryptors/LegacyCryptor.swift +++ b/Sources/PubNub/Helpers/Crypto/Cryptors/LegacyCryptor.swift @@ -17,25 +17,25 @@ import CommonCrypto public struct LegacyCryptor: Cryptor { private let key: Data private let withRandomIV: Bool - + static let ID: CryptorId = [0x00, 0x00, 0x00, 0x00] - + public init(key: String, withRandomIV: Bool = true) { let hash = CryptorUtils.SHA256.hash(from: key.data(using: .utf8) ?? Data()) let hexStrData = CryptorUtils.hexFrom(hash).lowercased(with: .current).data(using: .utf8) ?? Data() self.key = hexStrData self.withRandomIV = withRandomIV } - + public var id: CryptorId { Self.ID } - + public func encrypt(data: Data) -> Result { do { let vectorGen = withRandomIV ? CryptorVector.random(bytesCount: kCCBlockSizeAES128) : CryptorVector.fixed let ivData = try vectorGen.data() - + let encrypted = try data.crypt( operation: CCOperation(kCCEncrypt), algorithm: CCAlgorithm(kCCAlgorithmAES128), @@ -45,7 +45,7 @@ public struct LegacyCryptor: Cryptor { initializationVector: ivData, messageData: data ) - + // Join IV and encrypted content when using a random IV return .success(EncryptedData( metadata: Data(), @@ -58,11 +58,11 @@ public struct LegacyCryptor: Cryptor { )) } } - + public func decrypt(data: EncryptedData) -> Result { let iv: Data let cipherText: Data - + do { if withRandomIV { iv = data.data.prefix(kCCBlockSizeAES128) @@ -71,14 +71,14 @@ public struct LegacyCryptor: Cryptor { iv = try CryptorVector.fixed.data() cipherText = data.data } - + if cipherText.isEmpty { return .failure(PubNubError( .decryptionFailure, additional: ["Cannot decrypt empty Data in \(String(describing: self))"]) ) } - + return .success( try data.data.crypt( operation: CCOperation(kCCDecrypt), @@ -97,13 +97,13 @@ public struct LegacyCryptor: Cryptor { )) } } - + public func encrypt(stream: InputStream, contentLength: Int) -> Result { do { // Always uses random IV for InputStream processing let ivGenerator = CryptorVector.random(bytesCount: kCCBlockSizeAES128) let iv = try ivGenerator.data() - + let cryptoInputStreamCipher = CryptoInputStream.Cipher( algorithm: CCAlgorithm(kCCAlgorithmAES128), blockSize: kCCBlockSizeAES128 @@ -133,7 +133,7 @@ public struct LegacyCryptor: Cryptor { )) } } - + public func decrypt(data: EncryptedStreamData, outputPath: URL) -> Result { do { let cryptoInputStreamCipher = CryptoInputStream.Cipher( diff --git a/Sources/PubNub/Helpers/Crypto/Header/CryptorHeader.swift b/Sources/PubNub/Helpers/Crypto/Header/CryptorHeader.swift index 96701ec7..428c216b 100644 --- a/Sources/PubNub/Helpers/Crypto/Header/CryptorHeader.swift +++ b/Sources/PubNub/Helpers/Crypto/Header/CryptorHeader.swift @@ -16,11 +16,11 @@ private let sentinel = "PNED" enum CryptorHeader: Equatable { case none case v1(cryptorId: CryptorId, dataLength: Int) - + func length() -> Int { toData().count } - + func cryptorId() -> CryptorId { switch self { case .none: @@ -29,16 +29,16 @@ enum CryptorHeader: Equatable { return cryptorId } } - + func toData() -> Data { guard case .v1(let cryptorId, let dataLength) = self else { return Data() } - + var finalData = sentinel.data(using: .ascii) ?? Data() finalData += Data(bytes: [1], count: 1) finalData += Data(bytes: cryptorId, count: cryptorId.count) - + if dataLength < 255 { finalData += Data(bytes: [dataLength], count: 1) } else { @@ -46,34 +46,34 @@ enum CryptorHeader: Equatable { } return finalData } - + static func from(data: Data) throws -> Self { try CryptorHeaderParser(data: data).parse() } } -fileprivate class CryptorHeaderDataScanner { +private class CryptorHeaderDataScanner { private(set) var nextIndex: Int = 0 private let data: Data - + init(data: Data) { self.data = data } - + func nextBytes(_ count: Int) -> Data? { let previousValue = nextIndex let newValue = nextIndex + count - + guard newValue <= data.count else { return nil } nextIndex = newValue - + return data.subdata(in: previousValue.. UInt8? { nextBytes(1)?.first } - + func bytesRead() -> Data { data.suffix(nextIndex) } @@ -82,11 +82,11 @@ fileprivate class CryptorHeaderDataScanner { struct CryptorHeaderParser { private let scanner: CryptorHeaderDataScanner private let supportedVersionsRange: ClosedRange = (1...1) - + init(data: Data) { self.scanner = CryptorHeaderDataScanner(data: data) } - + func parse() throws -> CryptorHeader { guard let possibleSentinelBytes = scanner.nextBytes(4) else { return .none @@ -117,7 +117,7 @@ struct CryptorHeaderParser { dataLength: Int(finalCryptorDataSize) ) } - + private func computeCryptorDataSize(with sizeIndicator: Int) throws -> UInt16 { guard sizeIndicator > 255 else { return UInt16(sizeIndicator) diff --git a/Sources/PubNub/Helpers/Crypto/Header/CryptorHeaderWithinStreamFinder.swift b/Sources/PubNub/Helpers/Crypto/Header/CryptorHeaderWithinStreamFinder.swift index 7f1d9612..fcd566e9 100644 --- a/Sources/PubNub/Helpers/Crypto/Header/CryptorHeaderWithinStreamFinder.swift +++ b/Sources/PubNub/Helpers/Crypto/Header/CryptorHeaderWithinStreamFinder.swift @@ -12,17 +12,18 @@ import Foundation struct CryptorHeaderWithinStreamFinder { let stream: InputStream - + // Attempts to find CryptorHeader in the given InputStream. // Returns InputStream that immediately follows CryptorHeader + // swiftlint:disable:next large_tuple func findHeader() throws -> (header: CryptorHeader, cryptorDefinedData: Data, continuationStream: InputStream) { let buffer = read(maxLength: 1024) let header = try CryptorHeaderParser(data: buffer).parse() let headerLength = header.length() - + let continuationStream: InputStream let cryptorDefinedData: Data - + switch header { case .none: // There is no CryptorHeader, so all supplied buffer bytes belong to the contents of the File @@ -40,19 +41,19 @@ struct CryptorHeaderWithinStreamFinder { // Returns final InputStream that follows CryptorHeader continuationStream = MultipartInputStream(inputStreams: [exceedFileContent, stream]) } - + return ( header: header, cryptorDefinedData: cryptorDefinedData, continuationStream: continuationStream ) } - + private func read(maxLength: Int) -> Data { var buffer = [UInt8](repeating: 0, count: maxLength) var numberOfBytesRead = 0 var content: [UInt8] = [] - + if stream.streamStatus == .notOpen { stream.open() } @@ -62,15 +63,15 @@ struct CryptorHeaderWithinStreamFinder { maxLength: maxLength ) guard numberOfBytesRead > 0 else { - break; + break } if buffer.count != numberOfBytesRead { content += Array(buffer[0 ..< numberOfBytesRead]) } else { content += buffer } - } while numberOfBytesRead < maxLength && stream.hasBytesAvailable; - + } while numberOfBytesRead < maxLength && stream.hasBytesAvailable + return Data( bytes: content, count: content.count diff --git a/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptoInputStream.swift b/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptoInputStream.swift index b27ed002..4ffcb828 100644 --- a/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptoInputStream.swift +++ b/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptoInputStream.swift @@ -20,17 +20,17 @@ public class CryptoInputStream: InputStream { let options: CCOptions let cipher: Cipher } - + public struct Cipher { let algorithm: CCAlgorithm let blockSize: Int } - + public enum Operation { case decrypt case encrypt } - + /// Estimated size of the final crypted output public var estimatedCryptoCount: Int = 0 @@ -56,7 +56,7 @@ public class CryptoInputStream: InputStream { private weak var _delegate: StreamDelegate? private var _streamStatus: Stream.Status = .notOpen private var _streamError: Error? - + // A flag describing whether an IV vector is included at the beginning of encoded/decoded content private let includeInitializationVectorInContent: Bool @@ -70,12 +70,12 @@ public class CryptoInputStream: InputStream { self.operation = operation self.crypto = crypto self.includeInitializationVectorInContent = includeInitializationVectorInContent - + if operation == .encrypt { do { cryptedBufferRead = 0 let ivBuffer = crypto.iv.map { $0 } - + let cryptoStream = try CryptoStream( operation: CCOperation(operation == .decrypt ? kCCDecrypt : kCCEncrypt), algorithm: crypto.cipher.algorithm, @@ -93,16 +93,16 @@ public class CryptoInputStream: InputStream { estimatedCryptoCount = cryptoStream.getOutputLength(inputLength: rawDataLength, isFinal: true) } self.cryptoStream = cryptoStream - + } catch { _streamError = error _streamStatus = .error } } else { - + // Create a buffer to store the IV in that matches the cipher block size var initializationVectorBuffer = [UInt8](repeating: 0, count: crypto.cipher.blockSize) - + if includeInitializationVectorInContent { switch input.read(&initializationVectorBuffer, maxLength: crypto.cipher.blockSize) { case let bytesRead where bytesRead < 0: @@ -116,7 +116,7 @@ public class CryptoInputStream: InputStream { } else { initializationVectorBuffer = crypto.iv.map { $0 } } - + // Init the Crypto Stream do { let decryptStream = try CryptoStream( @@ -127,23 +127,26 @@ public class CryptoInputStream: InputStream { keyLength: crypto.key.count, ivBuffer: initializationVectorBuffer ) - + if includeInitializationVectorInContent { rawDataLength = contentLength - crypto.cipher.blockSize // The estimated content length is the IV length plus the crypted length - estimatedCryptoCount = crypto.cipher.blockSize + decryptStream.getOutputLength(inputLength: rawDataLength, isFinal: true) + estimatedCryptoCount = crypto.cipher.blockSize + decryptStream.getOutputLength( + inputLength: rawDataLength, + isFinal: true + ) } else { rawDataLength = contentLength estimatedCryptoCount = decryptStream.getOutputLength(inputLength: rawDataLength, isFinal: true) } - + self.cryptoStream = decryptStream } catch { _streamError = error _streamStatus = .error } } - + cipherStream = input // required because `init()` is not marked as a designated initializer @@ -274,9 +277,9 @@ public class CryptoInputStream: InputStream { if finalyse { var finalBuffer = writeBuffer let append = cryptedBytesLength > 0 - + writeBuffer = Array(writeBuffer[.., maxLength: Int) -> Int { + guard let cryptoStream = cryptoStream else { + return 0 + } return crypt( outputBuffer: buffer, maxLength: maxLength, inputStream: cipherStream, readByteOffset: 0, - cryptoStream: self.cryptoStream! + cryptoStream: cryptoStream ) } // MARK: - Decrypt func decrypt(_ buffer: UnsafeMutablePointer, maxLength: Int) -> Int { + guard let cryptoStream = cryptoStream else { + return 0 + } return crypt( outputBuffer: buffer, maxLength: maxLength, inputStream: cipherStream, - cryptoStream: self.cryptoStream! + cryptoStream: cryptoStream ) } diff --git a/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptorUtils.swift b/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptorUtils.swift index 8093be7a..a647ca80 100644 --- a/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptorUtils.swift +++ b/Sources/PubNub/Helpers/Crypto/Miscellaneous/CryptorUtils.swift @@ -23,7 +23,7 @@ enum CryptorUtils { } return Data(hash) } - } + } static func hexFrom(_ data: Data) -> String { let midpoint = data.count / 2 return data[.. Data { switch self { case .fixed: @@ -23,7 +23,7 @@ enum CryptorVector { return try randomInitializationVector(with: byteCount) } } - + func isFixed() -> Bool { if case .fixed = self { return true @@ -31,22 +31,22 @@ enum CryptorVector { return false } } - + func isRandom() -> Bool { - if case .random(_) = self { + if case .random = self { return true } else { return false } } - + private func staticInitializationVector() throws -> Data { guard let initializationVector = "0123456789012345".data(using: .utf8) else { throw CryptoError.rngFailure } return initializationVector } - + private func randomInitializationVector(with byteCount: Int) throws -> Data { var bytes: [UInt8] = Array(repeating: UInt8(0), count: byteCount) let status = CCRandomGenerateBytes(&bytes, byteCount) diff --git a/Sources/PubNub/Helpers/Streams/MultipartInputStream.swift b/Sources/PubNub/Helpers/Streams/MultipartInputStream.swift index 753b5b38..7ca65f83 100644 --- a/Sources/PubNub/Helpers/Streams/MultipartInputStream.swift +++ b/Sources/PubNub/Helpers/Streams/MultipartInputStream.swift @@ -14,7 +14,7 @@ import Foundation class MultipartInputStream: InputStream { let inputStreams: [InputStream] let length: Int - + private var currentIndex: Int private var _streamStatus: Stream.Status private var _streamError: Error? diff --git a/Sources/PubNub/Helpers/Typealias+PubNub.swift b/Sources/PubNub/Helpers/Typealias+PubNub.swift index 930ef991..43296aaa 100644 --- a/Sources/PubNub/Helpers/Typealias+PubNub.swift +++ b/Sources/PubNub/Helpers/Typealias+PubNub.swift @@ -28,6 +28,7 @@ typealias QueryResult = Result<[URLQueryItem], Error> /// A closure capable of validating a network response typealias ValidationClosure = (HTTPRouter, URLRequest, HTTPURLResponse, Data?) -> Error? +// swiftlint:disable:next large_tuple public typealias ProgressTuple = (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) /// A snapshot of a File's tranmission progress @@ -37,6 +38,8 @@ public typealias ProgressBlock = (ProgressTuple) -> Void /// A `Tuple` containing the `URLRequest` to upload the `fileURL`, and the fileId/filename the uploaded file will have once uploaded public typealias FileUploadTuple = (request: URLRequest, fileId: String, filename: String) +// swiftlint:disable:previous large_tuple /// A `Tuple` containing the `HTTPFileUploadTask` that completed, the `PubNubFile` that was uploaded, and the `Timetoken` when it was published public typealias FileUploadSendSuccess = (task: HTTPFileUploadTask, file: PubNubFile, publishedAt: Timetoken) +// swiftlint:disable:previous large_tuple diff --git a/Sources/PubNub/Models/PubNubAPNSPayload.swift b/Sources/PubNub/Models/PubNubAPNSPayload.swift index 19580ee6..b9a09016 100644 --- a/Sources/PubNub/Models/PubNubAPNSPayload.swift +++ b/Sources/PubNub/Models/PubNubAPNSPayload.swift @@ -64,7 +64,7 @@ public struct PubNubPushTarget: Codable, Hashable { case excludedDevices = "excluded_devices" case topic } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(self.environment, forKey: .environment) diff --git a/Sources/PubNub/Models/PubNubFCMPayload/FCMAndroidPayload.swift b/Sources/PubNub/Models/PubNubFCMPayload/FCMAndroidPayload.swift index 14b28531..4aa94485 100644 --- a/Sources/PubNub/Models/PubNubFCMPayload/FCMAndroidPayload.swift +++ b/Sources/PubNub/Models/PubNubFCMPayload/FCMAndroidPayload.swift @@ -405,6 +405,5 @@ public struct FCMColor: Codable, Hashable { /// A value of 1.0 corresponds to a solid color, whereas a value of 0.0 corresponds to a completely transparent color. public let alpha: Double - // swiftlint:enable line_length // swiftlint:disable:next file_length } diff --git a/Sources/PubNub/Models/PubNubMessage.swift b/Sources/PubNub/Models/PubNubMessage.swift index d12a070b..dcf6c92c 100644 --- a/Sources/PubNub/Models/PubNubMessage.swift +++ b/Sources/PubNub/Models/PubNubMessage.swift @@ -40,7 +40,7 @@ public protocol PubNubMessage { var messageType: PubNubMessageType { get set } /// An error (if any) occured while getting this message var error: PubNubError? { get set } - + /// Allows for transcoding between different MessageEvent types init(from other: PubNubMessage) throws } @@ -77,11 +77,11 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { public var published: Timetoken public var messageType: PubNubMessageType public var error: PubNubError? - + var concretePayload: AnyJSON var concreteMessageActions: [PubNubMessageActionBase] var concreteMetadata: AnyJSON? - + public var payload: JSONCodable { get { return concretePayload } set { @@ -172,10 +172,10 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { self.messageType = messageType self.error = error } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + try container.encode(self.concretePayload, forKey: .concretePayload) try container.encodeIfPresent(self.publisher, forKey: .publisher) try container.encode(self.concreteMessageActions, forKey: .concreteMessageActions) @@ -185,7 +185,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { try container.encodeIfPresent(self.concreteMetadata, forKey: .concreteMetadata) try container.encode(self.messageType, forKey: .messageType) } - + enum CodingKeys: CodingKey { case concretePayload case publisher @@ -196,10 +196,10 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { case concreteMetadata case messageType } - + public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - + self.concretePayload = try container.decode(AnyJSON.self, forKey: .concretePayload) self.publisher = try container.decodeIfPresent(String.self, forKey: .publisher) self.concreteMessageActions = try container.decode([PubNubMessageActionBase].self, forKey: .concreteMessageActions) diff --git a/Sources/PubNub/Networking/HTTPFileTask.swift b/Sources/PubNub/Networking/HTTPFileTask.swift index 90787c61..ecbfabcc 100644 --- a/Sources/PubNub/Networking/HTTPFileTask.swift +++ b/Sources/PubNub/Networking/HTTPFileTask.swift @@ -73,7 +73,7 @@ public class HTTPFileTask: Hashable { func updateProgress(bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { // Progress is handled automatically on iOS 11+ - if #available(iOS 11.0, macOS 10.13, macCatalyst 13.0, tvOS 11.0, watchOS 4.0, *) { } else { + if #unavailable(iOS 11.0, macOS 10.13, macCatalyst 13.0, tvOS 11.0, watchOS 4.0) { progress.completedUnitCount = totalBytesWritten } @@ -242,11 +242,11 @@ public class HTTPFileDownloadTask: HTTPFileTask { func decrypt(_ encryptedURL: URL, to outpuURL: URL, using cryptoModule: CryptoModule) throws { // If we were provided a Crypto object we should try and decrypt the file - + guard let inputStream = InputStream(url: encryptedURL) else { throw PubNubError(.streamCouldNotBeInitialized, additional: [encryptedURL.absoluteString]) } - + cryptoModule.decrypt( stream: inputStream, contentLength: encryptedURL.sizeOf, @@ -310,11 +310,11 @@ public class HTTPFileDownloadTask: HTTPFileTask { if let cryptoModule = cryptoModule { // Set the encrypted in case something goes wrong encryptedURL = url - + guard let stream = InputStream(url: url) else { throw PubNubError(.streamCouldNotBeInitialized, additional: [url.absoluteString]) } - + cryptoModule.decrypt( stream: stream, contentLength: url.sizeOf, diff --git a/Sources/PubNub/Networking/Request/Operators/AutomaticRetry.swift b/Sources/PubNub/Networking/Request/Operators/AutomaticRetry.swift index 56aa77f8..95269659 100644 --- a/Sources/PubNub/Networking/Request/Operators/AutomaticRetry.swift +++ b/Sources/PubNub/Networking/Request/Operators/AutomaticRetry.swift @@ -28,7 +28,7 @@ public struct AutomaticRetry: RequestOperator, Hashable { ) // The minimum value allowed between retries static let minDelay: UInt = 2 - + /// Provides the action taken when a retry is to be performed public enum ReconnectionPolicy: Hashable, Equatable { /// Exponential backoff with base/scale factor of 2, and a 150s max delay @@ -36,9 +36,6 @@ public struct AutomaticRetry: RequestOperator, Hashable { /// Linear reconnect every 3 seconds public static let defaultLinear: ReconnectionPolicy = .linear(delay: Double(3)) - /// Reconnect with an exponential backoff - @available(*, unavailable, renamed: "legacyExponential(base:scale:maxDelay:)") - case exponential(base: UInt, scale: Double, maxDelay: UInt) /// Reconnect with an exponential backoff case exponential(minDelay: UInt, maxDelay: UInt) /// Attempt to reconnect every X seconds @@ -51,7 +48,7 @@ public struct AutomaticRetry: RequestOperator, Hashable { /// Generates a random interval that's added to the final value /// Mitigates receiving 429 status code that's the result of too many requests in a given amount of time let randomDelay = Double.random(in: 0...1) - + switch self { case let .legacyExponential(base, scale, maxDelay): return legacyExponentialBackoffDelay(for: base, scale: scale, maxDelay: maxDelay, current: retryAttempt) + randomDelay @@ -66,7 +63,7 @@ public struct AutomaticRetry: RequestOperator, Hashable { max(min(pow(Double(base), Double(retryCount)) * scale, Double(maxDelay)), Double(AutomaticRetry.minDelay)) } } - + /// List of known endpoint groups (by context) possible to retry public enum Endpoint { /// Sending a message @@ -140,7 +137,7 @@ public struct AutomaticRetry: RequestOperator, Hashable { replaceOnFailure: UInt(10), warningMessage: "The `retryLimit` must be less than or equal 10" ) - + switch policy { case let .exponential(minDelay, maxDelay): let validatedMinDelay = Self.validate( @@ -183,7 +180,7 @@ public struct AutomaticRetry: RequestOperator, Hashable { maxDelay: maxDelay ) } - + self.retryableHTTPStatusCodes = retryableHTTPStatusCodes self.retryableURLErrorCodes = retryableURLErrorCodes self.excluded = endpoints @@ -199,17 +196,17 @@ public struct AutomaticRetry: RequestOperator, Hashable { completion(.failure(error)) return } - + let urlResponse = request.urlResponse let retryAfterValue = urlResponse?.allHeaderFields[Constant.retryAfterHeaderKey] - + if let retryAfterValue = retryAfterValue as? TimeInterval { return completion(.success(retryAfterValue + Double.random(in: 0...1))) } else { return completion(.success(policy.delay(for: request.retryCount))) } } - + public func retryOperator(for endpoint: AutomaticRetry.Endpoint) -> RequestOperator? { excluded.contains(endpoint) ? nil : self } diff --git a/Sources/PubNub/Networking/Request/Operators/InstanceIdOperator.swift b/Sources/PubNub/Networking/Request/Operators/InstanceIdOperator.swift index 731d349e..657322f0 100644 --- a/Sources/PubNub/Networking/Request/Operators/InstanceIdOperator.swift +++ b/Sources/PubNub/Networking/Request/Operators/InstanceIdOperator.swift @@ -16,10 +16,6 @@ public struct InstanceIdOperator: RequestOperator { /// The instanceID that will be attached to the request public let instanceID: String - init(instanceID: String) { - self.instanceID = instanceID - } - public func mutate( _ urlRequest: URLRequest, for _: SessionReplaceable, diff --git a/Sources/PubNub/Networking/Request/Operators/RequestIdOperator.swift b/Sources/PubNub/Networking/Request/Operators/RequestIdOperator.swift index eaa6a882..e4ad0de2 100644 --- a/Sources/PubNub/Networking/Request/Operators/RequestIdOperator.swift +++ b/Sources/PubNub/Networking/Request/Operators/RequestIdOperator.swift @@ -16,10 +16,6 @@ public struct RequestIdOperator: RequestOperator { /// The requestID that will be attached to the request public let requestID: String - init(requestID: String) { - self.requestID = requestID - } - public func mutate( _ urlRequest: URLRequest, for _: SessionReplaceable, diff --git a/Sources/PubNub/Networking/Request/Request.swift b/Sources/PubNub/Networking/Request/Request.swift index 261a9278..276890b8 100644 --- a/Sources/PubNub/Networking/Request/Request.swift +++ b/Sources/PubNub/Networking/Request/Request.swift @@ -317,7 +317,7 @@ final class Request { if let error = state.error { return .failure(error) } - + if let request = state.urlRequests.last, let response = state.tasks.last?.httpResponse, let data = state.responesData { diff --git a/Sources/PubNub/Networking/Routers/HistoryRouter.swift b/Sources/PubNub/Networking/Routers/HistoryRouter.swift index f4594803..cabafc7c 100644 --- a/Sources/PubNub/Networking/Routers/HistoryRouter.swift +++ b/Sources/PubNub/Networking/Routers/HistoryRouter.swift @@ -218,11 +218,10 @@ struct MessageHistoryResponseDecoder: ResponseDecoder { ) } } - - + return messages } - + // Replace previous payload with decrypted one let decryptedPayload = MessageHistoryResponse(status: response.payload.status, error: response.payload.error, @@ -244,9 +243,9 @@ struct MessageHistoryResponse: Codable { let error: Bool let errorMessage: String let channels: [String: [MessageHistoryMessagePayload]] - + let start: Timetoken? - + enum CodingKeys: String, CodingKey { case errorMessage = "error_message" case error @@ -254,11 +253,11 @@ struct MessageHistoryResponse: Codable { case channels case more } - + enum MoreCodingKeys: String, CodingKey { case start } - + init( status: Int = 200, error: Bool = false, @@ -272,25 +271,25 @@ struct MessageHistoryResponse: Codable { self.channels = channels self.start = start } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) status = try container.decode(Int.self, forKey: .status) error = try container.decode(Bool.self, forKey: .error) errorMessage = try container.decode(String.self, forKey: .errorMessage) channels = try container.decodeIfPresent([String: [MessageHistoryMessagePayload]].self, forKey: .channels) ?? [:] - + let moreContainer = try? container.nestedContainer(keyedBy: MoreCodingKeys.self, forKey: .more) start = Timetoken(try moreContainer?.decodeIfPresent(String.self, forKey: .start) ?? "") } - + func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(status, forKey: .status) try container.encode(error, forKey: .error) try container.encode(errorMessage, forKey: .errorMessage) try container.encode(channels, forKey: .channels) - + var moreContainer = container.nestedContainer(keyedBy: MoreCodingKeys.self, forKey: .more) try moreContainer.encodeIfPresent(start?.description, forKey: .start) } @@ -300,7 +299,7 @@ struct MessageHistoryMessagePayload: Codable { typealias ActionType = String typealias ActionValue = String typealias RawMessageAction = [ActionType: [ActionValue: [MessageHistoryMessageAction]]] - + let message: AnyJSON let timetoken: Timetoken let meta: AnyJSON? @@ -308,7 +307,7 @@ struct MessageHistoryMessagePayload: Codable { let messageType: PubNubMessageType? let actions: RawMessageAction let error: PubNubError? - + init( message: JSONCodable, timetoken: Timetoken = 0, @@ -326,7 +325,7 @@ struct MessageHistoryMessagePayload: Codable { self.actions = actions self.error = error } - + enum CodingKeys: String, CodingKey { case message case timetoken @@ -335,10 +334,10 @@ struct MessageHistoryMessagePayload: Codable { case messageType = "message_type" case actions } - + public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - + message = try container.decode(AnyJSON.self, forKey: .message) meta = try container.decodeIfPresent(AnyJSON.self, forKey: .meta) uuid = try container.decodeIfPresent(String.self, forKey: .uuid) @@ -347,10 +346,10 @@ struct MessageHistoryMessagePayload: Codable { actions = try container.decodeIfPresent(RawMessageAction.self, forKey: .actions) ?? [:] error = nil } - + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + try container.encode(message, forKey: .message) try container.encode(timetoken.description, forKey: .timetoken) try container.encodeIfPresent(meta, forKey: .meta) @@ -363,26 +362,26 @@ struct MessageHistoryMessagePayload: Codable { struct MessageHistoryMessageAction: Codable, Hashable { let uuid: String let actionTimetoken: Timetoken - + init(uuid: String, actionTimetoken: Timetoken) { self.uuid = uuid self.actionTimetoken = actionTimetoken } - + enum CodingKeys: String, CodingKey { case uuid case actionTimetoken } - + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) uuid = try container.decode(String.self, forKey: .uuid) actionTimetoken = Timetoken(try container.decode(String.self, forKey: .actionTimetoken)) ?? 0 } - + func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - + try container.encode(uuid, forKey: .uuid) try container.encode(actionTimetoken.description, forKey: .actionTimetoken) } @@ -399,13 +398,13 @@ struct MessageCountsResponsePayload: Codable, Hashable { let error: Bool let errorMessage: String let channels: [String: Int] - + enum CodingKeys: String, CodingKey { case status case error case errorMessage = "error_message" case channels } - + // swiftlint:disable:next file_length } diff --git a/Sources/PubNub/Networking/Routers/MessageActionsRouter.swift b/Sources/PubNub/Networking/Routers/MessageActionsRouter.swift index 5ae396b3..a9c0e13b 100644 --- a/Sources/PubNub/Networking/Routers/MessageActionsRouter.swift +++ b/Sources/PubNub/Networking/Routers/MessageActionsRouter.swift @@ -34,11 +34,6 @@ struct MessageActionsRouter: HTTPRouter { struct AddRequestBody: Codable, Hashable { let type: String let value: String - - init(type: String, value: String) { - self.type = type - self.value = value - } } // Init diff --git a/Sources/PubNub/Networking/Routers/Subscribe Payloads/SubscribeObjectPayload.swift b/Sources/PubNub/Networking/Routers/Subscribe Payloads/SubscribeObjectPayload.swift index 58f119fb..951224bc 100644 --- a/Sources/PubNub/Networking/Routers/Subscribe Payloads/SubscribeObjectPayload.swift +++ b/Sources/PubNub/Networking/Routers/Subscribe Payloads/SubscribeObjectPayload.swift @@ -27,20 +27,6 @@ struct SubscribeObjectMetadataPayload { case channel case membership } - - init( - source: String, - version: String, - event: Action, - type: MetadataType, - subscribeEvent: SubscriptionEvent - ) { - self.source = source - self.version = version - self.event = event - self.type = type - self.subscribeEvent = subscribeEvent - } } extension SubscribeObjectMetadataPayload: Codable { @@ -277,6 +263,7 @@ extension PubNubChannelMetadataChangeset: Codable { self.changes = changes } + // swiftlint:disable:next cyclomatic_complexity public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(metadataId, forKey: .metadataId) diff --git a/Sources/PubNub/Networking/Routers/SubscribeRouter.swift b/Sources/PubNub/Networking/Routers/SubscribeRouter.swift index 7c8b6022..0f863c14 100644 --- a/Sources/PubNub/Networking/Routers/SubscribeRouter.swift +++ b/Sources/PubNub/Networking/Routers/SubscribeRouter.swift @@ -37,7 +37,7 @@ struct SubscribeRouter: HTTPRouter { var endpoint: Endpoint var configuration: RouterConfiguration - + // Protocol Properties var service: PubNubService { return .subscribe @@ -407,4 +407,5 @@ public struct SubscribeMessagePayload: Codable, Hashable { try container.encode(messageType, forKey: .messageType) } } + // swiftlint:disable:next file_length } diff --git a/Sources/PubNub/PubNub.swift b/Sources/PubNub/PubNub.swift index e9426e66..466b7b56 100644 --- a/Sources/PubNub/PubNub.swift +++ b/Sources/PubNub/PubNub.swift @@ -1399,7 +1399,6 @@ public extension PubNub { func setConsumer(identifier: String, value: String) { configuration.consumerIdentifiers[identifier] = value } - // swiftlint:disable:next file_length } // MARK: - Global EventEmitter diff --git a/Sources/PubNub/PubNubConfiguration.swift b/Sources/PubNub/PubNubConfiguration.swift index 6e978556..c17db4cb 100644 --- a/Sources/PubNub/PubNubConfiguration.swift +++ b/Sources/PubNub/PubNubConfiguration.swift @@ -98,14 +98,12 @@ public struct PubNubConfiguration: Hashable { guard userId.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 else { preconditionFailure("UserId should not be empty.") } - if let cryptoModule = cryptoModule { + if let cryptoModule { self.cryptoModule = cryptoModule + } else if let cipherKey { + self.cryptoModule = CryptoModule.legacyCryptoModule(with: cipherKey.key, withRandomIV: cipherKey.randomizeIV) } else { - if let cipherKey = cipherKey { - self.cryptoModule = CryptoModule.legacyCryptoModule(with: cipherKey.key, withRandomIV: cipherKey.randomizeIV) - // Preserves cipherKey for backward compatibility if anyone has already accessed it before - self.cipherKey = cipherKey - } + self.cryptoModule = nil } self.publishKey = publishKey @@ -189,9 +187,6 @@ public struct PubNubConfiguration: Hashable { public var subscribeKey: String /// If set, all communication will be encrypted with this key public var cryptoModule: CryptoModule? - /// If set, all communication will be encrypted with this key - @available(*, deprecated, message: "Use 'cryptoModule' instead") - public var cipherKey: Crypto? /// If Access Manager (PAM) is enabled, client will use `authKey` on all requests public var authKey: String? /// If Access Manager (PAM) is enabled, client will use `authToken` instead of `authKey` on all requests diff --git a/Sources/PubNub/Subscription/ConnectionStatus.swift b/Sources/PubNub/Subscription/ConnectionStatus.swift index 53128af4..4ddb5d56 100644 --- a/Sources/PubNub/Subscription/ConnectionStatus.swift +++ b/Sources/PubNub/Subscription/ConnectionStatus.swift @@ -45,7 +45,8 @@ public enum ConnectionStatus: Equatable { return false } } - + + // swiftlint:disable:next cyclomatic_complexity func canTransition(to state: ConnectionStatus) -> Bool { switch (self, state) { case (.connecting, .connected): diff --git a/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift b/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift index d3be17da..5de71e72 100644 --- a/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift +++ b/Sources/PubNub/Subscription/Strategy/EventEngineSubscriptionSessionStrategy.swift @@ -24,7 +24,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { onFilterExpressionChanged() } } - + internal init( configuration: PubNubConfiguration, subscribeEngine: SubscribeEngine, @@ -42,23 +42,23 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { var subscribedChannels: [String] { subscribeEngine.state.input.subscribedChannelNames } - + var subscribedChannelGroups: [String] { subscribeEngine.state.input.subscribedGroupNames } - + var subscriptionCount: Int { subscribeEngine.state.input.totalSubscribedCount } - + var connectionStatus: ConnectionStatus { subscribeEngine.state.connectionStatus } - + deinit { PubNub.log.debug("SubscriptionSession Destroyed") } - + private func listenForStateUpdates() { subscribeEngine.onStateUpdated = { [weak self] state in if state is Subscribe.ReceivingState && state.hasTimetoken { @@ -66,7 +66,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { } } } - + private func updateSubscribeEngineDependencies() { subscribeEngine.dependencies = EventEngineDependencies( value: Subscribe.Dependencies( @@ -75,12 +75,12 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { ) ) } - + private func sendSubscribeEvent(event: Subscribe.Event) { updateSubscribeEngineDependencies() subscribeEngine.send(event: event) } - + private func updatePresenceEngineDependencies() { presenceEngine.dependencies = EventEngineDependencies( value: Presence.Dependencies( @@ -88,12 +88,12 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { ) ) } - + private func sendPresenceEvent(event: Presence.Event) { updatePresenceEngineDependencies() presenceEngine.send(event: event) } - + private func onFilterExpressionChanged() { let currentState = subscribeEngine.state let channels = currentState.input.allSubscribedChannelNames @@ -110,7 +110,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { let currentChannelsAndGroups = subscribeEngine.state.input let insertionResult = currentChannelsAndGroups.adding(channels: channels, and: groups) let newChannelsAndGroups = insertionResult.newInput - + if let cursor = cursor, cursor.timetoken != 0 { sendSubscribeEvent(event: .subscriptionRestored( channels: newChannelsAndGroups.allSubscribedChannelNames, @@ -145,13 +145,13 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { } } } - + func unsubscribeFrom( mainChannels: [PubNubChannel], presenceChannelsOnly: [PubNubChannel], mainGroups: [PubNubChannel], presenceGroupsOnly: [PubNubChannel] - ) { + ) { // Retrieve the current list of subscribed channels and channel groups let currentChannelsAndGroups = subscribeEngine.state.input // Provides the outcome after updating the list of channels and channel groups @@ -159,7 +159,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { mainChannels: mainChannels, presenceChannelsOnly: presenceChannelsOnly, mainGroups: mainGroups, presenceGroupsOnly: presenceGroupsOnly ) - + // Exits if there are no differences for channels or channel groups guard removingResult.newInput != currentChannelsAndGroups else { return @@ -201,7 +201,7 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { func unsubscribeAll() { let currentInput = subscribeEngine.state.input - + // Dispatch local event first to guarantee the expected order of events. // An event indicating unsubscribing from channels and channel groups // should be emitted before an event related to disconnecting @@ -215,11 +215,11 @@ class EventEngineSubscriptionSessionStrategy: SubscriptionSessionStrategy { ) )) } - + sendSubscribeEvent(event: .unsubscribeAll) sendPresenceEvent(event: .leftAll) } - + private func notify(listeners closure: (BaseSubscriptionListener) -> Void) { listeners.allObjects.forEach { closure($0) } } diff --git a/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy+Presence.swift b/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy+Presence.swift index 39aadaa6..65dac7b3 100644 --- a/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy+Presence.swift +++ b/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy+Presence.swift @@ -11,7 +11,7 @@ import Foundation extension LegacySubscriptionSessionStrategy { - + // MARK: - Heartbeat Loop func registerHeartbeatTimer() { @@ -69,7 +69,11 @@ extension LegacySubscriptionSessionStrategy { switch result { case .success: // If the connection is active register a new heartbeat otherwise stop the timer - self?.connectionStatus.isActive ?? false ? self?.registerHeartbeatTimer() : self?.stopHeartbeatTimer() + if self?.connectionStatus.isActive ?? false { + self?.registerHeartbeatTimer() + } else { + self?.stopHeartbeatTimer() + } case .failure: self?.stopHeartbeatTimer() } diff --git a/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy.swift b/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy.swift index da2c4ac7..a33384f0 100644 --- a/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy.swift +++ b/Sources/PubNub/Subscription/Strategy/LegacySubscriptionSessionStrategy.swift @@ -16,7 +16,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { let longPollingSession: SessionReplaceable let sessionStream: SessionListener let responseQueue: DispatchQueue - + var configuration: PubNubConfiguration var listeners: WeakSet = WeakSet([]) var filterExpression: String? @@ -84,7 +84,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { // Add listener to session mutableSession.sessionStream = sessionStream longPollingSession = mutableSession - + sessionStream.didRetryRequest = { [weak self] _ in self?.connectionStatus = .reconnecting } @@ -125,7 +125,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { reconnect(at: cursor) } } - + /// Reconnect a disconnected subscription stream /// - parameter timetoken: The timetoken to subscribe with func reconnect(at cursor: SubscribeCursor? = nil) { @@ -169,19 +169,19 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { channels: channels, groups: groups, channelStates: [:], timetoken: cursor?.timetoken, region: cursor?.region.description, heartbeat: configuration.durationUntilTimeout, filter: filterExpression - ),configuration: configuration + ), configuration: configuration ) - + // Cancel previous request before starting new one stopSubscribeLoop(.longPollingRestart) - + // Will compare this in the error response to see if we need to restart let nextSubscribe = longPollingSession.request( with: router, requestOperator: configuration.automaticRetry?.retryOperator(for: .subscribe) ) let currentSubscribeID = nextSubscribe.requestID - + request = nextSubscribe request? .validate() @@ -217,7 +217,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { pubnubGroups[$0] = PubNubChannel(channel: $0) } } - + listener.emit(subscribe: .responseReceived( SubscribeResponseHeader( channels: pubnubChannels.values.map { $0 }, @@ -286,7 +286,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { } // MARK: - Unsubscribe - + func unsubscribeFrom( mainChannels: [PubNubChannel], presenceChannelsOnly: [PubNubChannel], @@ -378,7 +378,7 @@ class LegacySubscriptionSessionStrategy: SubscriptionSessionStrategy { reconnect(at: previousTokenResponse) } } - + private func notify(listeners closure: (BaseSubscriptionListener) -> Void) { listeners.allObjects.forEach { closure($0) } } diff --git a/Sources/PubNub/Subscription/SubscriptionSession.swift b/Sources/PubNub/Subscription/SubscriptionSession.swift index 5e910a85..ebcd8aca 100644 --- a/Sources/PubNub/Subscription/SubscriptionSession.swift +++ b/Sources/PubNub/Subscription/SubscriptionSession.swift @@ -17,7 +17,7 @@ class SubscriptionSession: EventEmitter, StatusEmitter { var uuid: UUID { strategy.uuid } // The `Timetoken` used for the last successful subscription request var previousTokenResponse: SubscribeCursor? { strategy.previousTokenResponse } - + // PSV2 feature to subscribe with a custom filter expression. var filterExpression: String? { get { @@ -34,7 +34,7 @@ class SubscriptionSession: EventEmitter, StatusEmitter { strategy.configuration = newValue } } - + var onEvent: ((PubNubEvent) -> Void)? var onEvents: (([PubNubEvent]) -> Void)? var onMessage: ((PubNubMessage) -> Void)? @@ -44,13 +44,13 @@ class SubscriptionSession: EventEmitter, StatusEmitter { var onFileEvent: ((PubNubFileChangeEvent) -> Void)? var onAppContext: ((PubNubAppContextEvent) -> Void)? var onConnectionStateChange: ((ConnectionStatus) -> Void)? - + private lazy var globalEventsListener: BaseSubscriptionListenerAdapter = .init( receiver: self, uuid: uuid, queue: queue ) - + private lazy var globalStatusListener: BaseSubscriptionListener = { // Creates legacy listener under the hood to capture status changes let statusListener = SubscriptionListener(queue: queue) @@ -63,11 +63,11 @@ class SubscriptionSession: EventEmitter, StatusEmitter { } return statusListener }() - + private var globalChannelSubscriptions: [String: Subscription] = [:] private var globalGroupSubscriptions: [String: Subscription] = [:] private let strategy: any SubscriptionSessionStrategy - + init( strategy: any SubscriptionSessionStrategy, eventsQueue queue: DispatchQueue = .main @@ -84,7 +84,7 @@ class SubscriptionSession: EventEmitter, StatusEmitter { var subscribedChannels: [String] { strategy.subscribedChannels } - + // List of actively subscribed groups var subscribedChannelGroups: [String] { strategy.subscribedChannelGroups @@ -94,12 +94,12 @@ class SubscriptionSession: EventEmitter, StatusEmitter { var subscriptionCount: Int { strategy.subscriptionCount } - + // Current connection status var connectionStatus: ConnectionStatus { strategy.connectionStatus } - + // MARK: - Subscription Loop func subscribe( @@ -138,13 +138,13 @@ class SubscriptionSession: EventEmitter, StatusEmitter { } // MARK: - Reconnect - + func reconnect(at cursor: SubscribeCursor? = nil) { strategy.reconnect(at: cursor) } // MARK: - Disconnect - + func disconnect() { strategy.disconnect() } @@ -184,7 +184,7 @@ extension SubscriptionSession: SubscribeReceiver { func hasRegisteredAdapter(with uuid: UUID) -> Bool { strategy.listeners.contains { $0?.uuid == uuid } } - + // Registers a subscription adapter to translate events from a legacy listener // into the new Listeners API. // @@ -193,7 +193,7 @@ extension SubscriptionSession: SubscribeReceiver { func registerAdapter(_ adapter: BaseSubscriptionListenerAdapter) { add(adapter) } - + // Maps the raw channel/channel group array to collections of PubNubChannel that should be subscribed to // with and without Presence, respectively. private typealias SubscribeRetrievalRes = ( @@ -205,7 +205,7 @@ extension SubscriptionSession: SubscribeReceiver { presenceOnlyItems: [PubNubChannel], mainItems: [PubNubChannel] ) - + // Composes final PubNubChannel lists the user should subscribe to // according to provided raw input and forwards the result to the underlying Subscription strategy. func internalSubscribe( @@ -216,10 +216,10 @@ extension SubscriptionSession: SubscribeReceiver { if channels.isEmpty, groups.isEmpty { return } - + let extractingChannelsRes = retrieveItemsToSubscribe(from: channels) let extractingGroupsRes = retrieveItemsToSubscribe(from: groups) - + for channelSubscription in channels { registerAdapter(channelSubscription.adapter) } @@ -232,7 +232,7 @@ extension SubscriptionSession: SubscribeReceiver { at: SubscribeCursor(timetoken: timetoken) ) } - + private func retrieveItemsToSubscribe(from subscriptions: [Subscription]) -> SubscribeRetrievalRes { // Detects all Presence channels from provided String array and maps them into PubNubChannel // containing the main channel name and the flag indicating the resulting PubNubChannel is subscribed @@ -245,7 +245,7 @@ extension SubscriptionSession: SubscribeReceiver { }).map { PubNubChannel(channel: $0) } - + // Detects remaining main channel names without Presence enabled from provided input and ensuring // there are no duplicates with the result received from the previous step let channelsWithoutPresence = Set(subscriptions.flatMap { @@ -257,13 +257,13 @@ extension SubscriptionSession: SubscribeReceiver { }).map { PubNubChannel(id: $0, withPresence: false) } - + return SubscribeRetrievalRes( itemsWithPresenceIncluded: channelsWithPresenceIncluded, itemsWithoutPresence: channelsWithoutPresence ) } - + func internalUnsubscribe( from channels: [Subscription], and channelGroups: [Subscription], @@ -290,7 +290,7 @@ extension SubscriptionSession: SubscribeReceiver { presenceGroupsOnly: extractingGroupsRes.presenceOnlyItems ) } - + // Returns an array of subscriptions that subscribe to at least one name in common with the given Subscription func matchingSubscriptions(for subscription: Subscription, presenceOnly: Bool) -> [SubscribeMessagesReceiver] { let allSubscriptions = strategy.listeners.compactMap { @@ -299,7 +299,7 @@ extension SubscriptionSession: SubscribeReceiver { let namesToFind = subscription.subscriptionNames.filter { presenceOnly ? $0.isPresenceChannelName : true } - + return allSubscriptions.filter { $0.uuid != subscription.uuid && $0.uuid != globalEventsListener.uuid }.compactMap { @@ -332,7 +332,7 @@ extension SubscriptionSession: SubscribeReceiver { }.map { PubNubChannel(channel: $0) } - + let channels = presenceItemsOnly ? [] : Set(subscriptions.filter { matchingSubscriptions( for: $0, @@ -349,7 +349,7 @@ extension SubscriptionSession: SubscribeReceiver { }).map { PubNubChannel(id: $0, withPresence: false) } - + return UnsubscribeRetrievalRes( presenceOnlyItems: presenceItems, mainItems: channels @@ -363,15 +363,15 @@ extension SubscriptionSession: EntityCreator { public func channel(_ name: String) -> ChannelRepresentation { ChannelRepresentation(name: name, receiver: self) } - + public func channelGroup(_ name: String) -> ChannelGroupRepresentation { ChannelGroupRepresentation(name: name, receiver: self) } - + public func userMetadata(_ name: String) -> UserMetadataRepresentation { UserMetadataRepresentation(id: name, receiver: self) } - + public func channelMetadata(_ name: String) -> ChannelMetadataRepresentation { ChannelMetadataRepresentation(id: name, receiver: self) } @@ -381,7 +381,7 @@ extension SubscriptionSession: EntityCreator { extension SubscriptionSession: EventStreamEmitter { public typealias ListenerType = BaseSubscriptionListener - + public var listeners: [ListenerType] { strategy.listeners.allObjects } @@ -389,7 +389,7 @@ extension SubscriptionSession: EventStreamEmitter { public func notify(listeners closure: (ListenerType) -> Void) { listeners.forEach { closure($0) } } - + public func add(_ listener: ListenerType) { // Ensure that we cancel the previously attached token listener.token?.cancel() @@ -425,10 +425,12 @@ extension SubscriptionSession: SubscribeMessagesReceiver { var subscriptionTopology: [SubscribableType: [String]] { [.channel: subscribedChannels, .channelGroup: subscribedChannelGroups] } - + func onPayloadsReceived(payloads: [SubscribeMessagePayload]) -> [PubNubEvent] { let events = payloads.map { $0.asPubNubEvent() } emit(events: events) return events } + + // swiftlint:disable:next file_length }