├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── stale.yml └── workflows │ ├── ci.yml │ ├── prepare.yml │ └── release.yml ├── .gitignore ├── .swiftlint.yml ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── CHANGELOG.md ├── Cartfile ├── Cartfile.resolved ├── Consumption-Tests ├── .gitignore ├── .swiftlint.yml ├── Carthage-Latest │ ├── Carthage-Latest.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ └── config.xcconfig ├── Carthage-Minimum │ ├── Carthage-Minimum.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ └── config.xcconfig ├── Cocoapods-Latest │ ├── Cocoapods-Latest.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Podfile.template │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ └── config.xcconfig ├── Cocoapods-Minimum │ ├── Cocoapods-Minimum.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Podfile.template │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ └── config.xcconfig ├── LATEST_SUPPORTED_VERSIONS.xcconfig ├── LATEST_SUPPORTED_XCODE_VERSION ├── MINIMUM_SUPPORTED_VERSIONS.xcconfig ├── MINIMUM_SUPPORTED_XCODE_VERSION ├── README.md ├── Shared │ ├── Objective-C │ │ ├── ViewController+Extensions.h │ │ ├── ViewController+Extensions.m │ │ ├── iOS │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Main.storyboard │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ │ ├── macOS │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Main.storyboard │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ │ └── tvOS │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj │ │ │ └── Main.storyboard │ │ │ ├── ViewController.h │ │ │ ├── ViewController.m │ │ │ └── main.m │ ├── Swift │ │ ├── ViewController+Extensions.swift │ │ ├── iOS │ │ │ ├── AppDelegate.swift │ │ │ ├── Main.storyboard │ │ │ └── ViewController.swift │ │ ├── macOS │ │ │ ├── AppDelegate.swift │ │ │ ├── Main.storyboard │ │ │ └── ViewController.swift │ │ └── tvOS │ │ │ ├── AppDelegate.swift │ │ │ ├── Main.storyboard │ │ │ └── ViewController.swift │ ├── assignXcodeAppPathFor.sh │ ├── carthage-checkout.sh │ ├── carthage-copy-platform-specific-frameworks.sh │ ├── carthage.sh │ ├── cocoapods-checkout.sh │ ├── getXcodeVersionFor.sh │ ├── iOS │ │ └── Info.plist │ ├── macOS │ │ └── Info.plist │ ├── performTests.sh │ ├── readAllXcconfigVersionValuesFor.sh │ └── tvOS │ │ └── Info.plist ├── SwiftPackageManager-Latest │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ ├── SwiftPackageManager-Latest.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── config.xcconfig ├── SwiftPackageManager-Minimum │ ├── ObjectiveC.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── ObjectiveC-iOS-WithEncryption.xcscheme │ │ │ ├── ObjectiveC-macOS-WithEncryption.xcscheme │ │ │ └── ObjectiveC-tvOS-WithEncryption.xcscheme │ ├── Swift.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── Swift-iOS-WithEncryption.xcscheme │ │ │ ├── Swift-macOS-WithEncryption.xcscheme │ │ │ └── Swift-tvOS-WithEncryption.xcscheme │ ├── SwiftPackageManager-Minimum.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── config.xcconfig ├── run-tests-CI-latest.sh ├── run-tests-CI-minimum.sh └── run-tests-LOCALLY.sh ├── LICENSE.md ├── Package.resolved ├── Package.swift ├── PusherSwift.podspec ├── PusherSwift.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── PusherSwift.xcscheme ├── PusherSwift.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── PusherSwiftWithEncryption.podspec ├── README.md ├── Scripts └── generate-api-docs.sh ├── Sources ├── Extensions │ ├── PusherChannel+EncryptionHelpers.swift │ ├── PusherConnection+WebsocketDelegate.swift │ └── URL+Pusher.swift ├── Helpers │ ├── Crypto.swift │ ├── EventParser.swift │ └── Logger.swift ├── Info.plist ├── Models │ ├── AuthError.swift │ ├── AuthMethod.swift │ ├── ChannelsProtocolCloseCode.swift │ ├── ConnectionState.swift │ ├── Constants.swift │ ├── EventError.swift │ ├── EventHandler.swift │ ├── PusherAuth.swift │ ├── PusherChannel.swift │ ├── PusherChannelType.swift │ ├── PusherChannels.swift │ ├── PusherClientOptions.swift │ ├── PusherError.swift │ ├── PusherEvent.swift │ ├── PusherGlobalChannel.swift │ ├── PusherHost.swift │ ├── PusherPresenceChannel.swift │ ├── PusherPresenceChannelMember.swift │ └── QueuedClientEvent.swift ├── ObjC │ ├── AuthMethod+ObjectiveC.swift │ ├── OCAuthMethod.swift │ ├── OCPusherHost.swift │ ├── Pusher+ObjectiveC.swift │ ├── PusherClientOptions+ObjectiveC.swift │ ├── PusherConnection+ObjectiveC.swift │ ├── PusherError+ObjectiveC.swift │ └── PusherHost+ObjectiveC.swift ├── Protocols │ ├── AuthRequestBuilderProtocol.swift │ ├── Authorizer.swift │ ├── EventFactory.swift │ ├── EventQueue.swift │ ├── EventQueueDelegate.swift │ └── PusherDelegate.swift ├── PusherSwift.h ├── PusherSwift.swift └── Services │ ├── ChannelEventFactory.swift │ ├── ChannelEventQueue.swift │ └── PusherConnection.swift ├── Tests ├── .swiftlint.yml ├── Extensions │ ├── String+Extensions.swift │ └── XCTest+Assertions.swift ├── Helpers │ ├── Helpers.swift │ ├── Mocks.swift │ └── TestObjects.swift ├── Info.plist ├── Integration │ ├── AuthenticationTests.swift │ ├── PusherClientInitializationTests.swift │ ├── PusherIncomingEventHandlingTests.swift │ └── PusherTopLevelAPITests.swift └── Unit │ ├── Helpers │ ├── ChannelEventFactory+DecryptionTests.swift │ ├── ChannelEventFactoryTests.swift │ └── CryptoTests.swift │ ├── Models │ ├── ClientEventTests.swift │ ├── PresenceChannelTests.swift │ ├── PrivateEncryptedChannelTests.swift │ └── PusherChannelTests.swift │ ├── Protocols │ └── PusherConnectionDelegateTests.swift │ └── Services │ ├── ChannelEventQueue+DecryptionTests.swift │ ├── ChannelEventQueueTests.swift │ └── PusherConnectionTests.swift ├── docs ├── Classes.html ├── Classes │ ├── GlobalChannel.html │ ├── OCAuthMethod.html │ ├── OCPusherHost.html │ ├── Pusher.html │ ├── PusherAuth.html │ ├── PusherChannel.html │ ├── PusherChannels.html │ ├── PusherClientOptions.html │ ├── PusherConnection.html │ ├── PusherError.html │ ├── PusherEvent.html │ ├── PusherPresenceChannel.html │ └── PusherPresenceChannelMember.html ├── Enums.html ├── Enums │ ├── AuthMethod.html │ ├── ConnectionState.html │ ├── PusherChannelType.html │ └── PusherHost.html ├── Protocols.html ├── Protocols │ ├── AuthRequestBuilderProtocol.html │ ├── Authorizer.html │ └── PusherDelegate.html ├── Structs.html ├── Structs │ └── QueuedClientEvent.html ├── Typealiases.html ├── badge.svg ├── css │ ├── highlight.css │ └── jazzy.css ├── docsets │ ├── PusherSwift.docset │ │ └── Contents │ │ │ ├── Info.plist │ │ │ └── Resources │ │ │ ├── Documents │ │ │ ├── Classes.html │ │ │ ├── Classes │ │ │ │ ├── GlobalChannel.html │ │ │ │ ├── OCAuthMethod.html │ │ │ │ ├── OCPusherHost.html │ │ │ │ ├── Pusher.html │ │ │ │ ├── PusherAuth.html │ │ │ │ ├── PusherChannel.html │ │ │ │ ├── PusherChannels.html │ │ │ │ ├── PusherClientOptions.html │ │ │ │ ├── PusherConnection.html │ │ │ │ ├── PusherError.html │ │ │ │ ├── PusherEvent.html │ │ │ │ ├── PusherPresenceChannel.html │ │ │ │ └── PusherPresenceChannelMember.html │ │ │ ├── Enums.html │ │ │ ├── Enums │ │ │ │ ├── AuthMethod.html │ │ │ │ ├── ConnectionState.html │ │ │ │ ├── PusherChannelType.html │ │ │ │ └── PusherHost.html │ │ │ ├── Protocols.html │ │ │ ├── Protocols │ │ │ │ ├── AuthRequestBuilderProtocol.html │ │ │ │ ├── Authorizer.html │ │ │ │ └── PusherDelegate.html │ │ │ ├── Structs.html │ │ │ ├── Structs │ │ │ │ └── QueuedClientEvent.html │ │ │ ├── Typealiases.html │ │ │ ├── badge.svg │ │ │ ├── css │ │ │ │ ├── highlight.css │ │ │ │ └── jazzy.css │ │ │ ├── img │ │ │ │ ├── carat.png │ │ │ │ ├── dash.png │ │ │ │ ├── gh.png │ │ │ │ └── spinner.gif │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── jazzy.js │ │ │ │ ├── jazzy.search.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── lunr.min.js │ │ │ │ └── typeahead.jquery.js │ │ │ ├── search.json │ │ │ └── undocumented.json │ │ │ └── docSet.dsidx │ └── PusherSwift.tgz ├── img │ ├── carat.png │ ├── dash.png │ ├── gh.png │ └── spinner.gif ├── index.html ├── js │ ├── jazzy.js │ ├── jazzy.search.js │ ├── jquery.min.js │ ├── lunr.min.js │ └── typeahead.jquery.js ├── search.json └── undocumented.json ├── iOS Example Obj-C ├── iOS Example Obj-C.xcodeproj │ └── project.pbxproj └── iOS Example Obj-C │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ ├── iOS Example Obj-C.entitlements │ └── main.m └── iOS Example Swift ├── .swiftlint.yml ├── iOS Example Swift.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── iOS Example Swift ├── AppDelegate.swift ├── Base.lproj ├── LaunchScreen.xib └── Main.storyboard ├── Carthage.xcconfig ├── Images.xcassets └── AppIcon.appiconset │ ├── Contents.json │ ├── pusher-logo-20@2x.png │ ├── pusher-logo-20@3x.png │ ├── pusher-logo-60@2x.png │ └── pusher-logo-60@3x.png ├── Info.plist ├── Main.storyboard ├── ViewController.swift └── iOS Example.entitlements /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Steps to reproduce 2 | 3 | What must I do to reproduce the bug? 4 | 5 | ### Expected behavior 6 | 7 | What did you expect to happen? 8 | 9 | ### Actual behavior 10 | 11 | What actually happened? Submit stack traces or anything that you think would help. 12 | 13 | ### Any improvements you suggest 14 | 15 | ... 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description of the pull request 2 | 3 | ... 4 | 5 | #### Why is the change necessary? 6 | 7 | ... 8 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 90 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - pinned 16 | - security 17 | 18 | # Set to true to ignore issues with an assignee (defaults to false) 19 | exemptAssignees: true 20 | 21 | # Comment to post when marking as stale. Set to `false` to disable 22 | markComment: > 23 | This issue has been automatically marked as stale because it has not had 24 | recent activity. It will be closed if no further activity occurs. If you'd 25 | like this issue to stay open please leave a comment indicating how this issue 26 | is affecting you. Thank you. 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | run-tests: 9 | runs-on: macos-latest 10 | strategy: 11 | matrix: 12 | os: ['tvOS', 'iOS'] 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: maxim-lobanov/setup-xcode@v1 16 | with: 17 | xcode-version: '13.2.1' 18 | - uses: actions/cache@v4 19 | id: carthage-cache 20 | with: 21 | path: Carthage 22 | key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }} 23 | - name: Build 24 | if: steps.carthage-cache.outputs.cache-hit != 'true' 25 | run: | 26 | sh ./Consumption-Tests/Shared/carthage.sh bootstrap --cache-builds --use-xcframeworks 27 | - uses: futureware-tech/simulator-action@v1 28 | id: simulator 29 | with: 30 | os: ${{ matrix.os }} 31 | - name: "Run ${{ matrix.os }} Tests" 32 | run: | 33 | set -o pipefail && env NSUnbufferedIO=YES xcodebuild \ 34 | -project PusherSwift.xcodeproj \ 35 | -scheme PusherSwift \ 36 | build \ 37 | COMPILER_INDEX_STORE_ENABLE=NO \ 38 | test \ 39 | -destination "id=${{ steps.simulator.outputs.udid }}" \ 40 | | xcpretty --color 41 | -------------------------------------------------------------------------------- /.github/workflows/prepare.yml: -------------------------------------------------------------------------------- 1 | name: Prepare release 2 | 3 | on: 4 | pull_request: 5 | types: [ labeled ] 6 | branches: 7 | - master 8 | 9 | jobs: 10 | prepare-release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | - name: Fetch the lastest release version 18 | id: fetch_latest_release 19 | uses: pozetroninc/github-action-get-latest-release@master 20 | with: 21 | repository: ${{ github.repository }} 22 | excludes: prerelease, draft 23 | - uses: actions/checkout@v2 24 | with: 25 | repository: pusher/actions 26 | token: ${{ secrets.PUSHER_CI_GITHUB_PRIVATE_TOKEN }} 27 | path: .github/actions 28 | - uses: ./.github/actions/prepare-version-bump 29 | id: bump 30 | with: 31 | current_version: ${{ steps.fetch_latest_release.outputs.release }} 32 | - uses: actions/setup-node@v3 33 | with: 34 | node-version: 16.x 35 | - name: "Bump podspec versions" 36 | shell: bash 37 | run: | 38 | npm install --location=global podspec-bump 39 | 40 | sed -i 's/${{ steps.bump.outputs.current_version }}/${{ steps.bump.outputs.new_version }}/1' Tests/Integration/PusherClientInitializationTests.swift 41 | sed -i 's/${{ steps.bump.outputs.current_version }}/${{ steps.bump.outputs.new_version }}/1' Tests/Info.plist 42 | sed -i 's/${{ steps.bump.outputs.current_version }}/${{ steps.bump.outputs.new_version }}/1' Sources/PusherSwift.swift 43 | sed -i 's/${{ steps.bump.outputs.current_version }}/${{ steps.bump.outputs.new_version }}/1' Sources/Info.plist 44 | 45 | podspec-bump -i ${{ steps.bump.outputs.new_version }} -w -p PusherSwift.podspec 46 | podspec-bump -i ${{ steps.bump.outputs.new_version }} -w -p PusherSwiftWithEncryption.podspec 47 | 48 | git add Tests/Integration/PusherClientInitializationTests.swift Tests/Info.plist Sources/PusherSwift.swift Sources/Info.plist PusherSwift.podspec PusherSwiftWithEncryption.podspec 49 | 50 | git commit -m "Bump to version ${{ steps.bump.outputs.new_version }}" 51 | git push 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # Swift Package Manager 31 | # 32 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 33 | # Packages/ 34 | .build/ 35 | 36 | # CocoaPods 37 | # 38 | # We recommend against adding the Pods directory to your .gitignore. However 39 | # you should judge for yourself, the pros and cons are mentioned at: 40 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 41 | # 42 | Pods/ 43 | 44 | # Carthage 45 | # 46 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 47 | Carthage/Checkouts 48 | 49 | Carthage/Build 50 | 51 | # fastlane 52 | # 53 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 54 | # screenshots whenever they are needed. 55 | # For more information about the recommended setup visit: 56 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 57 | 58 | fastlane/report.xml 59 | fastlane/screenshots 60 | 61 | .swift-version 62 | test_push.rb 63 | SwiftLibExampleCertificate.pem 64 | 65 | # macOS 66 | 67 | .DS_Store -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: 2 | - .build 3 | - Carthage 4 | - Package.swift 5 | - Consumption-Tests/*/Carthage 6 | - Consumption-Tests/*/Pods 7 | 8 | opt_in_rules: 9 | - anyobject_protocol 10 | - closure_end_indentation 11 | - closure_spacing 12 | - explicit_init 13 | - modifier_order 14 | - prefer_self_type_over_type_of_self 15 | - sorted_imports 16 | - test_case_accessibility 17 | - unneeded_parentheses_in_closure_argument 18 | - vertical_whitespace_between_cases 19 | - vertical_whitespace_closing_braces 20 | - redundant_objc_attribute 21 | 22 | disabled_rules: 23 | - redundant_objc_attribute 24 | 25 | identifier_name: 26 | excluded: 27 | - id 28 | - ex 29 | - to 30 | - ws 31 | 32 | # This generates a compiler error if more than this many SwiftLint warnings are present 33 | # (This threshold can become more restrictive as remaining warnings are resolved via refactoring) 34 | warning_threshold: 100 -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "bitmark-inc/tweetnacl-swiftwrap" ~> 1.0 2 | github "pusher/NWWebSocket" ~> 0.5.4 3 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "bitmark-inc/tweetnacl-swiftwrap" "1.1.0" 2 | github "pusher/NWWebSocket" "0.5.4" 3 | -------------------------------------------------------------------------------- /Consumption-Tests/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Cartfile's are autogenerated with the `checkout.sh` script 4 | # We do not want to version anything Carthage related to emulate a fresh Carthage checkout 5 | Cartfile 6 | Cartfile.resolved 7 | Carthage 8 | 9 | 10 | # Podfile's are autogenerated with the `checkout.sh` script 11 | # We do not want to version anything Cocoapods related to emulate a fresh Cocoapods checkout 12 | Podfile 13 | Podfile.lock 14 | Pods 15 | 16 | # We do not want to version anything SPM related to emulate a fresh SPM checkout 17 | Package.resolved 18 | 19 | -------------------------------------------------------------------------------- /Consumption-Tests/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/Carthage-Latest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/Carthage-Latest.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Latest/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../LATEST_SUPPORTED_VERSIONS.xcconfig" 2 | 3 | FRAMEWORK_SEARCH_PATHS[sdk=iphone*] = $(SRCROOT)/Carthage/Build/iOS/ $(inherited) 4 | FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SRCROOT)/Carthage/Build/Mac/ $(inherited) 5 | FRAMEWORK_SEARCH_PATHS[sdk=appletv*] = $(SRCROOT)/Carthage/Build/tvOS/ $(inherited) 6 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/Carthage-Minimum.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/Carthage-Minimum.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Carthage-Minimum/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../MINIMUM_SUPPORTED_VERSIONS.xcconfig" 2 | 3 | FRAMEWORK_SEARCH_PATHS[sdk=iphone*] = $(SRCROOT)/Carthage/Build/iOS/ $(inherited) 4 | FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SRCROOT)/Carthage/Build/Mac/ $(inherited) 5 | FRAMEWORK_SEARCH_PATHS[sdk=appletv*] = $(SRCROOT)/Carthage/Build/tvOS/ $(inherited) 6 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Cocoapods-Latest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Cocoapods-Latest.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Podfile.template: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | use_frameworks! 3 | 4 | workspace 'Cocoapods-Latest.xcworkspace' 5 | 6 | 7 | IOS_VERSION='{IOS_VERSION}' 8 | MAC_VERSION='{MAC_VERSION}' 9 | TVOS_VERSION='{TVOS_VERSION}' 10 | 11 | target 'Swift-iOS-WithEncryption' do 12 | platform :ios, IOS_VERSION 13 | project 'Swift.xcodeproj' 14 | pod 'PusherSwift', :path => '../../' 15 | end 16 | target 'Swift-macOS-WithEncryption' do 17 | platform :osx, MAC_VERSION 18 | project 'Swift.xcodeproj' 19 | pod 'PusherSwift', :path => '../../' 20 | end 21 | target 'Swift-tvOS-WithEncryption' do 22 | platform :tvos, TVOS_VERSION 23 | project 'Swift.xcodeproj' 24 | pod 'PusherSwift', :path => '../../' 25 | end 26 | target 'ObjectiveC-iOS-WithEncryption' do 27 | platform :ios, IOS_VERSION 28 | project 'ObjectiveC.xcodeproj' 29 | pod 'PusherSwift', :path => '../../' 30 | end 31 | target 'ObjectiveC-macOS-WithEncryption' do 32 | platform :osx, MAC_VERSION 33 | project 'ObjectiveC.xcodeproj' 34 | pod 'PusherSwift', :path => '../../' 35 | end 36 | target 'ObjectiveC-tvOS-WithEncryption' do 37 | platform :tvos, TVOS_VERSION 38 | project 'ObjectiveC.xcodeproj' 39 | pod 'PusherSwift', :path => '../../' 40 | end 41 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Latest/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../LATEST_SUPPORTED_VERSIONS.xcconfig" 2 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Cocoapods-Minimum.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Cocoapods-Minimum.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/ObjectiveC.xcodeproj/xcshareddata/xcschemes/ObjectiveC-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Podfile.template: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | use_frameworks! 3 | 4 | workspace 'Cocoapods-Minimum.xcworkspace' 5 | 6 | 7 | IOS_VERSION='{IOS_VERSION}' 8 | MAC_VERSION='{MAC_VERSION}' 9 | TVOS_VERSION='{TVOS_VERSION}' 10 | 11 | target 'Swift-iOS-WithEncryption' do 12 | platform :ios, IOS_VERSION 13 | project 'Swift.xcodeproj' 14 | pod 'PusherSwift', :path => '../../' 15 | end 16 | target 'Swift-macOS-WithEncryption' do 17 | platform :osx, MAC_VERSION 18 | project 'Swift.xcodeproj' 19 | pod 'PusherSwift', :path => '../../' 20 | end 21 | target 'Swift-tvOS-WithEncryption' do 22 | platform :tvos, TVOS_VERSION 23 | project 'Swift.xcodeproj' 24 | pod 'PusherSwift', :path => '../../' 25 | end 26 | target 'ObjectiveC-iOS-WithEncryption' do 27 | platform :ios, IOS_VERSION 28 | project 'ObjectiveC.xcodeproj' 29 | pod 'PusherSwift', :path => '../../' 30 | end 31 | target 'ObjectiveC-macOS-WithEncryption' do 32 | platform :osx, MAC_VERSION 33 | project 'ObjectiveC.xcodeproj' 34 | pod 'PusherSwift', :path => '../../' 35 | end 36 | target 'ObjectiveC-tvOS-WithEncryption' do 37 | platform :tvos, TVOS_VERSION 38 | project 'ObjectiveC.xcodeproj' 39 | pod 'PusherSwift', :path => '../../' 40 | end 41 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/Cocoapods-Minimum/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../MINIMUM_SUPPORTED_VERSIONS.xcconfig" 2 | -------------------------------------------------------------------------------- /Consumption-Tests/LATEST_SUPPORTED_VERSIONS.xcconfig: -------------------------------------------------------------------------------- 1 | SWIFT_VERSION = 5.3 2 | IPHONEOS_DEPLOYMENT_TARGET = 14.1 3 | MACOSX_DEPLOYMENT_TARGET = 10.15 4 | TVOS_DEPLOYMENT_TARGET = 14.0 5 | -------------------------------------------------------------------------------- /Consumption-Tests/LATEST_SUPPORTED_XCODE_VERSION: -------------------------------------------------------------------------------- 1 | Xcode 12.1 -------------------------------------------------------------------------------- /Consumption-Tests/MINIMUM_SUPPORTED_VERSIONS.xcconfig: -------------------------------------------------------------------------------- 1 | SWIFT_VERSION = 5.0 2 | IPHONEOS_DEPLOYMENT_TARGET = 13.0 3 | MACOSX_DEPLOYMENT_TARGET = 10.15 4 | TVOS_DEPLOYMENT_TARGET = 13.0 5 | -------------------------------------------------------------------------------- /Consumption-Tests/MINIMUM_SUPPORTED_XCODE_VERSION: -------------------------------------------------------------------------------- 1 | Xcode 11.0 -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/ViewController+Extensions.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #if TARGET_OS_IOS 4 | #import "iOS/ViewController.h" 5 | #elif TARGET_OS_TV 6 | #import "tvOS/ViewController.h" 7 | #else 8 | #import "macOS/ViewController.h" 9 | #endif 10 | 11 | @import PusherSwift; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface AuthRequestBuilder : NSObject 16 | 17 | - (NSMutableURLRequest *)requestForSocketID:(NSString *)socketID channel:(PusherChannel *)channel; 18 | - (NSURLRequest *)requestForSocketID:(NSString *)socketID channelName:(NSString *)channelName; 19 | 20 | @end 21 | 22 | @interface ViewController (Extensions) 23 | 24 | - (Pusher *)makeAndLaunchPusher; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppDelegate : UIResponder 4 | 5 | @property (strong, nonatomic) UIWindow *window; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | @interface AppDelegate () 4 | 5 | @end 6 | 7 | @implementation AppDelegate 8 | 9 | 10 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 11 | return YES; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/ViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @import PusherSwift; 4 | 5 | @interface ViewController : UIViewController 6 | 7 | @property (nonatomic, strong, readwrite) Pusher *client; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/ViewController.m: -------------------------------------------------------------------------------- 1 | #import "ViewController.h" 2 | #import "ViewController+Extensions.h" 3 | 4 | @implementation ViewController 5 | 6 | - (void)viewDidLoad { 7 | [super viewDidLoad]; 8 | self.client = [self makeAndLaunchPusher]; 9 | } 10 | 11 | 12 | @end 13 | 14 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/iOS/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "AppDelegate.h" 3 | 4 | int main(int argc, char * argv[]) { 5 | @autoreleasepool { 6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/macOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppDelegate : NSObject 4 | 5 | 6 | @end 7 | 8 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/macOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | @interface AppDelegate () 4 | 5 | @end 6 | 7 | @implementation AppDelegate 8 | 9 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 10 | // Insert code here to initialize your application 11 | } 12 | 13 | 14 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 15 | // Insert code here to tear down your application 16 | } 17 | 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/macOS/ViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @import PusherSwift; 4 | 5 | @interface ViewController : NSViewController 6 | 7 | @property (nonatomic, strong, readwrite) Pusher *client; 8 | 9 | @end 10 | 11 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/macOS/ViewController.m: -------------------------------------------------------------------------------- 1 | #import "ViewController.h" 2 | #import "ViewController+Extensions.h" 3 | 4 | @implementation ViewController 5 | 6 | - (void)viewDidLoad { 7 | [super viewDidLoad]; 8 | self.client = [self makeAndLaunchPusher]; 9 | } 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/macOS/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int main(int argc, const char * argv[]) { 4 | @autoreleasepool { 5 | // Setup code that might create autoreleased objects goes here. 6 | } 7 | return NSApplicationMain(argc, argv); 8 | } 9 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/AppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | @interface AppDelegate : UIResponder 5 | 6 | @property (strong, nonatomic) UIWindow *window; 7 | 8 | 9 | @end 10 | 11 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/AppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | #import "AppDelegate.h" 3 | 4 | @interface AppDelegate () 5 | 6 | @end 7 | 8 | @implementation AppDelegate 9 | 10 | 11 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 12 | // Override point for customization after application launch. 13 | return YES; 14 | } 15 | 16 | 17 | - (void)applicationWillResignActive:(UIApplication *)application { 18 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 19 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 20 | } 21 | 22 | 23 | - (void)applicationDidEnterBackground:(UIApplication *)application { 24 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 25 | } 26 | 27 | 28 | - (void)applicationWillEnterForeground:(UIApplication *)application { 29 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 30 | } 31 | 32 | 33 | - (void)applicationDidBecomeActive:(UIApplication *)application { 34 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 35 | } 36 | 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/ViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @import PusherSwift; 4 | 5 | @interface ViewController : UIViewController 6 | 7 | @property (nonatomic, strong, readwrite) Pusher *client; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/ViewController.m: -------------------------------------------------------------------------------- 1 | #import "ViewController.h" 2 | #import "ViewController+Extensions.h" 3 | 4 | @implementation ViewController 5 | 6 | - (void)viewDidLoad { 7 | [super viewDidLoad]; 8 | self.client = [self makeAndLaunchPusher]; 9 | } 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Objective-C/tvOS/main.m: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | NSString * appDelegateClassName; 7 | @autoreleasepool { 8 | // Setup code that might create autoreleased objects goes here. 9 | appDelegateClassName = NSStringFromClass([AppDelegate class]); 10 | } 11 | return UIApplicationMain(argc, argv, nil, appDelegateClassName); 12 | } 13 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | #if swift(>=4.2) 9 | 10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 11 | 12 | return true 13 | } 14 | 15 | #else 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool { 18 | 19 | return true 20 | } 21 | 22 | #endif 23 | } 24 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/iOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | import PusherSwift 4 | 5 | class ViewController: UIViewController { 6 | var pusher: Pusher! = nil 7 | 8 | @IBAction func connectButton(_ sender: AnyObject) { 9 | pusher.connect() 10 | } 11 | 12 | @IBAction func disconnectButton(_ sender: AnyObject) { 13 | pusher.disconnect() 14 | } 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | self.pusher = makeAndLaunchPusher() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/macOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | @NSApplicationMain 4 | class AppDelegate: NSObject, NSApplicationDelegate { 5 | 6 | func applicationDidFinishLaunching(_ aNotification: Notification) { 7 | // Insert code here to initialize your application 8 | } 9 | 10 | func applicationWillTerminate(_ aNotification: Notification) { 11 | // Insert code here to tear down your application 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/macOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | 3 | import PusherSwift 4 | 5 | class ViewController: NSViewController { 6 | var pusher: Pusher! = nil 7 | 8 | override func viewDidLoad() { 9 | super.viewDidLoad() 10 | self.pusher = makeAndLaunchPusher() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/tvOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 9 | // Override point for customization after application launch. 10 | return true 11 | } 12 | 13 | func applicationWillResignActive(_ application: UIApplication) { 14 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 15 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 16 | } 17 | 18 | func applicationDidEnterBackground(_ application: UIApplication) { 19 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 20 | } 21 | 22 | func applicationWillEnterForeground(_ application: UIApplication) { 23 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 24 | } 25 | 26 | func applicationDidBecomeActive(_ application: UIApplication) { 27 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/tvOS/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/Swift/tvOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | import PusherSwift 4 | 5 | class ViewController: UIViewController { 6 | var pusher: Pusher! = nil 7 | 8 | @IBAction func connectButton(_ sender: AnyObject) { 9 | pusher.connect() 10 | } 11 | 12 | @IBAction func disconnectButton(_ sender: AnyObject) { 13 | pusher.disconnect() 14 | } 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | self.pusher = makeAndLaunchPusher() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/assignXcodeAppPathFor.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # Usage `assignXcodeAppPathFor XCODE_VERSION` 4 | function assignXcodeAppPathFor { # outputs path to $XCODE_APP_PATH var 5 | 6 | echo "------ BEGIN: $FUNCNAME $@ ------" 7 | 8 | local SCRIPT_DIRECTORY="$(dirname $0)" 9 | echo "SCRIPT_DIRECTORY=$SCRIPT_DIRECTORY" 10 | 11 | local DESIRED_XCODE_VERSION="$1" 12 | echo "DESIRED_XCODE_VERSION=$DESIRED_XCODE_VERSION" 13 | 14 | echo "*** Attempting to identify Xcode (xcodebuild) with version '$DESIRED_XCODE_VERSION' ***" 15 | 16 | for CANDIDATE_XCODE_APP_PATH in /Applications/*Xcode*.app/; do 17 | echo $CANDIDATE_XCODE_APP_PATH; 18 | local CANDIDATE_XCODEBUILD_PATH="${CANDIDATE_XCODE_APP_PATH}Contents/Developer/usr/bin/xcodebuild" 19 | if [ -e "$CANDIDATE_XCODEBUILD_PATH" ]; then 20 | echo " xcodebuild exists ($CANDIDATE_XCODEBUILD_PATH)" 21 | local XCODE_VERSION=$( "$CANDIDATE_XCODEBUILD_PATH" -version | head -n 1 ) 22 | echo " VERSION: $XCODE_VERSION" 23 | 24 | if [ "$XCODE_VERSION" == "$DESIRED_XCODE_VERSION" ]; then 25 | echo "***** FOUND '$DESIRED_XCODE_VERSION' at $CANDIDATE_XCODE_APP_PATH *****" 26 | XCODE_APP_PATH="$CANDIDATE_XCODE_APP_PATH" 27 | echo "------ END: $FUNCNAME $@ ------" 28 | return 0 # Return with zero code to indicate success 29 | fi 30 | else 31 | echo " xcodebuild missing ($XCODEBUILD_PATH)" 32 | fi 33 | done 34 | 35 | # If we got here the DESIRED_XCODE_VERSION was not found 36 | echo "ERROR: No Xcode (xcodebuild) found for version '$DESIRED_XCODE_VERSION' as defined in '$DESIRED_XCODE_VERSION_FILENAME'" >&2 37 | echo "------ END: $FUNCNAME $@ ------" 38 | say "Failure. Unable to find ex code application for version $DESIRED_XCODE_VERSION" 39 | exit 1 # Exit with a non-zero code to indicate failure and kill the script 40 | } -------------------------------------------------------------------------------- /Consumption-Tests/Shared/carthage-copy-platform-specific-frameworks.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | case "$PLATFORM_NAME" in 4 | macosx) plat=Mac;; 5 | iphone*) plat=iOS;; 6 | watch*) plat=watchOS;; 7 | tv*) plat=tvOS;; 8 | appletv*) plat=tvOS;; 9 | *) echo "error: Unknown PLATFORM_NAME: $PLATFORM_NAME"; exit 1;; 10 | esac 11 | for (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do 12 | VAR=SCRIPT_INPUT_FILE_$n 13 | framework=$(basename "${!VAR}") 14 | input_file_path="$SRCROOT/Carthage/Build/$plat/$framework.framework" 15 | echo "exporting SCRIPT_INPUT_FILE_$n=$input_file_path" 16 | export SCRIPT_INPUT_FILE_$n="$input_file_path" 17 | done 18 | 19 | /usr/local/bin/carthage copy-frameworks || exit 20 | 21 | for (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do 22 | VAR=SCRIPT_INPUT_FILE_$n 23 | source=${!VAR}.dSYM 24 | dest=${BUILT_PRODUCTS_DIR}/$(basename "$source") 25 | echo "$source" 26 | echo " -> $dest" 27 | ditto "$source" "$dest" || exit 28 | done 29 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/carthage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # carthage.sh 4 | # Usage example: ./carthage.sh build --platform iOS 5 | 6 | set -euo pipefail 7 | 8 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) 9 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT 10 | 11 | # For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise 12 | # the build will fail on lipo due to duplicate architectures. 13 | 14 | CURRENT_XCODE_VERSION=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3) 15 | echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig 16 | 17 | echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig 18 | echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig 19 | 20 | export XCODE_XCCONFIG_FILE="$xcconfig" 21 | carthage "$@" -------------------------------------------------------------------------------- /Consumption-Tests/Shared/getXcodeVersionFor.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e # Ensure Script Exits immediately if any command exits with a non-zero status 4 | 5 | function getXcodeVersionFor { # outputs value to $XCODE_VERSION var 6 | 7 | echo "------ BEGIN: $FUNCNAME $@ ------" 8 | 9 | local WORKING_DIRECTORY="$1" 10 | echo "WORKING_DIRECTORY=$WORKING_DIRECTORY" 11 | 12 | # Remove trailing slashs 13 | local WORKING_DIRECTORY_TRIMMED=$(echo $WORKING_DIRECTORY | sed 's:/*$::') 14 | echo "WORKING_DIRECTORY_TRIMMED=$WORKING_DIRECTORY_TRIMMED" 15 | 16 | if [[ "$WORKING_DIRECTORY_TRIMMED" == *"-Latest" ]]; then 17 | XCODE_VERSION_FILENAME="LATEST_SUPPORTED_XCODE_VERSION" 18 | elif [[ "$WORKING_DIRECTORY_TRIMMED" == *"-Minimum" ]]; then 19 | XCODE_VERSION_FILENAME="MINIMUM_SUPPORTED_XCODE_VERSION" 20 | else 21 | echo "ERROR: Unable to determine Xcode version requirements because the working directory does not end with either '-Latest' or '-Minimum'." >&2 22 | echo "------ END: $FUNCNAME $@ ------" 23 | say "Failure. Unable to determine Xcode version" 24 | exit 1 25 | fi 26 | 27 | local XCODE_VERSION_FILEPATH="$WORKING_DIRECTORY/../$XCODE_VERSION_FILENAME" 28 | echo "XCODE_VERSION_FILEPATH=$XCODE_VERSION_FILEPATH" 29 | 30 | XCODE_VERSION=$( head -n 1 "$XCODE_VERSION_FILEPATH" ) 31 | echo "XCODE_VERSION=$XCODE_VERSION" 32 | 33 | echo "------ END: $FUNCNAME $@ ------" 34 | } 35 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | NSMainStoryboardFile 31 | Main 32 | UILaunchStoryboardName 33 | LaunchScreen 34 | UIMainStoryboardFile 35 | Main 36 | UIRequiredDeviceCapabilities 37 | 38 | armv7 39 | 40 | UISupportedInterfaceOrientations 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UISupportedInterfaceOrientations~ipad 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationPortraitUpsideDown 50 | UIInterfaceOrientationLandscapeLeft 51 | UIInterfaceOrientationLandscapeRight 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2020 Pusher. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | NSSupportsAutomaticTermination 32 | 33 | NSSupportsSuddenTermination 34 | 35 | NSAppTransportSecurity 36 | 37 | NSAllowsArbitraryLoads 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/readAllXcconfigVersionValuesFor.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e # Ensure Script Exits immediately if any command exits with a non-zero status 4 | 5 | # calling this function will ultimately set the following variables 6 | # SWIFT_VERSION 7 | # IPHONEOS_DEPLOYMENT_TARGET 8 | # MACOSX_DEPLOYMENT_TARGET 9 | # TVOS_DEPLOYMENT_TARGET 10 | # 11 | # by reading them from the appropriate xcconfig file, either 12 | # MINIMUM_SUPPORTED_VERSIONS.xconfig 13 | # LATEST_SUPPORTED_VERSIONS.xconfig 14 | # 15 | # depending on the WORKING_DIRECTORY arg passed 16 | 17 | 18 | # Usage: `getXcconfigValueFor WORKING_DIRECTORY` 19 | function readAllXcconfigVersionValuesFor { 20 | 21 | echo "------ BEGIN: $FUNCNAME $@ ------" 22 | 23 | local WORKING_DIRECTORY="$1" 24 | echo "WORKING_DIRECTORY=$WORKING_DIRECTORY" 25 | 26 | # Remove trailing slashs 27 | local WORKING_DIRECTORY_TRIMMED=$(echo $WORKING_DIRECTORY | sed 's:/*$::') 28 | echo "WORKING_DIRECTORY_TRIMMED=$WORKING_DIRECTORY_TRIMMED" 29 | 30 | if [[ "$WORKING_DIRECTORY_TRIMMED" == *"-Latest" ]]; then 31 | XCCONFIG_FILENAME="LATEST_SUPPORTED_VERSIONS.xcconfig" 32 | elif [[ "$WORKING_DIRECTORY_TRIMMED" == *"-Minimum" ]]; then 33 | XCCONFIG_FILENAME="MINIMUM_SUPPORTED_VERSIONS.xcconfig" 34 | else 35 | echo "ERROR: Unable to determine version requirements because the working directory does not end with either '-Latest' or '-Minimum'." >&2 36 | echo "------ END: $FUNCNAME $@ ------" 37 | say "Failure. Unable to determine version requirements" 38 | exit 1 39 | fi 40 | 41 | local XCCONFIG_FILEPATH="$WORKING_DIRECTORY/../$XCCONFIG_FILENAME" 42 | echo "XCCONFIG_FILEPATH=$XCCONFIG_FILEPATH" 43 | 44 | while read -r LINE || [ -n "$LINE" ]; do 45 | LINE_TRIMMED="${LINE/ = /=}" 46 | echo $LINE_TRIMMED 47 | if [[ "$LINE_TRIMMED" == "//"* ]]; then 48 | echo " ...looks like a comment ignoring" 49 | else 50 | echo " ... setting varaiable" 51 | eval "$LINE_TRIMMED" 52 | fi 53 | done < "$XCCONFIG_FILEPATH" 54 | 55 | echo "SWIFT_VERSION=$SWIFT_VERSION" 56 | echo "IPHONEOS_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET" 57 | echo "MACOSX_DEPLOYMENT_TARGET=$MACOSX_DEPLOYMENT_TARGET" 58 | echo "TVOS_DEPLOYMENT_TARGET=$TVOS_DEPLOYMENT_TARGET" 59 | 60 | echo "------ END: $FUNCNAME $@ ------" 61 | } 62 | -------------------------------------------------------------------------------- /Consumption-Tests/Shared/tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | arm64 30 | 31 | UIUserInterfaceStyle 32 | Automatic 33 | 34 | 35 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/SwiftPackageManager-Latest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/SwiftPackageManager-Latest.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Latest/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../LATEST_SUPPORTED_VERSIONS.xcconfig" 2 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-iOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-macOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/Swift.xcodeproj/xcshareddata/xcschemes/Swift-tvOS-WithEncryption.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/SwiftPackageManager-Minimum.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/SwiftPackageManager-Minimum.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Consumption-Tests/SwiftPackageManager-Minimum/config.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../MINIMUM_SUPPORTED_VERSIONS.xcconfig" 2 | -------------------------------------------------------------------------------- /Consumption-Tests/run-tests-CI-latest.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ############################################################################### 4 | # Ensure Script Exits immediately if any command exits with a non-zero status # 5 | ############################################################################### 6 | # http://stackoverflow.com/questions/1378274/in-a-bash-script-how-can-i-exit-the-entire-script-if-a-certain-condition-occurs#1379904 7 | set -e 8 | 9 | 10 | #################### 11 | # Define Variables # 12 | #################### 13 | 14 | SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | echo "SCRIPT_DIRECTORY=$SCRIPT_DIRECTORY" 16 | 17 | SUMMARY_LOG_OUTPUT="" 18 | 19 | 20 | #################### 21 | # Import Functions # 22 | #################### 23 | 24 | source "$SCRIPT_DIRECTORY/Shared/performTests.sh" 25 | 26 | 27 | ##################### 28 | # Extract Arguments # 29 | ##################### 30 | 31 | extractArgs $@ 32 | 33 | 34 | ################# 35 | # Perform Tests # 36 | ################# 37 | 38 | performTests "Carthage-Latest" 39 | performTests "Cocoapods-Latest" 40 | performTests "SwiftPackageManager-Latest" 41 | 42 | 43 | ############ 44 | # Conclude # 45 | ############ 46 | 47 | echo "$SUMMARY_LOG_OUTPUT" 48 | say "All targets built successfully" 49 | -------------------------------------------------------------------------------- /Consumption-Tests/run-tests-CI-minimum.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ############################################################################### 4 | # Ensure Script Exits immediately if any command exits with a non-zero status # 5 | ############################################################################### 6 | # http://stackoverflow.com/questions/1378274/in-a-bash-script-how-can-i-exit-the-entire-script-if-a-certain-condition-occurs#1379904 7 | set -e 8 | 9 | 10 | #################### 11 | # Define Variables # 12 | #################### 13 | 14 | SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | echo "SCRIPT_DIRECTORY=$SCRIPT_DIRECTORY" 16 | 17 | SUMMARY_LOG_OUTPUT="" 18 | 19 | 20 | #################### 21 | # Import Functions # 22 | #################### 23 | 24 | source "$SCRIPT_DIRECTORY/Shared/performTests.sh" 25 | 26 | 27 | ##################### 28 | # Extract Arguments # 29 | ##################### 30 | 31 | extractArgs $@ 32 | 33 | 34 | ################# 35 | # Perform Tests # 36 | ################# 37 | 38 | performTests "Carthage-Minimum" 39 | performTests "Cocoapods-Minimum" 40 | performTests "SwiftPackageManager-Minimum" 41 | 42 | 43 | ############ 44 | # Conclude # 45 | ############ 46 | 47 | echo "$SUMMARY_LOG_OUTPUT" 48 | say "All targets built successfully" 49 | -------------------------------------------------------------------------------- /Consumption-Tests/run-tests-LOCALLY.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ############################################################################### 4 | # Ensure Script Exits immediately if any command exits with a non-zero status # 5 | ############################################################################### 6 | # http://stackoverflow.com/questions/1378274/in-a-bash-script-how-can-i-exit-the-entire-script-if-a-certain-condition-occurs#1379904 7 | set -e 8 | 9 | 10 | #################### 11 | # Define Variables # 12 | #################### 13 | 14 | SCRIPT_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 15 | echo "SCRIPT_DIRECTORY=$SCRIPT_DIRECTORY" 16 | 17 | SUMMARY_LOG_OUTPUT="" 18 | 19 | 20 | #################### 21 | # Import Functions # 22 | #################### 23 | 24 | source "$SCRIPT_DIRECTORY/Shared/performTests.sh" 25 | 26 | 27 | ##################### 28 | # Extract Arguments # 29 | ##################### 30 | 31 | extractArgs $@ 32 | 33 | 34 | ################# 35 | # Perform Tests # 36 | ################# 37 | 38 | performTests "Carthage-Minimum" 39 | performTests "Cocoapods-Minimum" 40 | performTests "SwiftPackageManager-Minimum" 41 | performTests "Carthage-Latest" 42 | performTests "Cocoapods-Latest" 43 | performTests "SwiftPackageManager-Latest" 44 | 45 | 46 | ############ 47 | # Conclude # 48 | ############ 49 | 50 | echo "$SUMMARY_LOG_OUTPUT" 51 | say "All targets built successfully" 52 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Pusher Ltd. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "NWWebSocket", 6 | "repositoryURL": "https://github.com/pusher/NWWebSocket.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "19d23951c8099304ad98e2fc762fa23d6bfab0b9", 10 | "version": "0.5.3" 11 | } 12 | }, 13 | { 14 | "package": "TweetNacl", 15 | "repositoryURL": "https://github.com/bitmark-inc/tweetnacl-swiftwrap", 16 | "state": { 17 | "branch": null, 18 | "revision": "d1552db4d907f2c5cb3d1bf1336496b2e16c8ecf", 19 | "version": "1.0.2" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "PusherSwift", 7 | platforms: [.iOS("13.0"), .macOS("10.15"), .tvOS("13.0")], 8 | products: [ 9 | .library(name: "PusherSwift", targets: ["PusherSwift"]) 10 | ], 11 | dependencies: [ 12 | .package(url: "https://github.com/pusher/NWWebSocket.git", .upToNextMajor(from: "0.5.4")), 13 | .package(url: "https://github.com/bitmark-inc/tweetnacl-swiftwrap", .upToNextMajor(from: "1.0.0")), 14 | ], 15 | targets: [ 16 | .target( 17 | name: "PusherSwift", 18 | dependencies: [ 19 | "NWWebSocket", 20 | "TweetNacl", 21 | ], 22 | path: "Sources" 23 | ), 24 | .testTarget( 25 | name: "PusherSwiftTests", 26 | dependencies: ["PusherSwift"], 27 | path: "Tests" 28 | ) 29 | ], 30 | swiftLanguageVersions: [.v5] 31 | ) 32 | -------------------------------------------------------------------------------- /PusherSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'PusherSwift' 3 | s.version = '10.1.5' 4 | s.summary = 'A Pusher client library in Swift' 5 | s.homepage = 'https://github.com/pusher/pusher-websocket-swift' 6 | s.license = 'MIT' 7 | s.author = { "Pusher Limited" => "support@pusher.com" } 8 | s.source = { git: "https://github.com/pusher/pusher-websocket-swift.git", tag: s.version.to_s } 9 | s.social_media_url = 'https://twitter.com/pusher' 10 | 11 | s.swift_version = '5.0' 12 | s.requires_arc = true 13 | s.source_files = ['Sources/**/*.swift'] 14 | 15 | s.dependency 'TweetNacl', '~> 1.0.0' 16 | s.dependency 'NWWebSocket', '~> 0.5.4' 17 | 18 | s.ios.deployment_target = '13.0' 19 | s.osx.deployment_target = '10.15' 20 | s.tvos.deployment_target = '13.0' 21 | end 22 | -------------------------------------------------------------------------------- /PusherSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PusherSwift.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /PusherSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PusherSwiftWithEncryption.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'PusherSwiftWithEncryption' 3 | s.version = '10.1.5' 4 | s.summary = 'A Pusher client library in Swift that supports encrypted channels' 5 | s.homepage = 'https://github.com/pusher/pusher-websocket-swift' 6 | s.license = 'MIT' 7 | s.author = { "Pusher Limited" => "support@pusher.com" } 8 | s.source = { git: "https://github.com/pusher/pusher-websocket-swift.git", tag: s.version.to_s } 9 | s.social_media_url = 'https://twitter.com/pusher' 10 | 11 | s.swift_version = '5.0' 12 | s.requires_arc = true 13 | s.source_files = ['Sources/**/*.swift'] 14 | 15 | s.dependency 'TweetNacl', '~> 1.0.0' 16 | s.dependency 'NWWebSocket', '~> 0.5.4' 17 | 18 | s.ios.deployment_target = '13.0' 19 | s.osx.deployment_target = '10.15' 20 | s.tvos.deployment_target = '13.0' 21 | s.watchos.deployment_target = '6.0' 22 | end 23 | -------------------------------------------------------------------------------- /Scripts/generate-api-docs.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | set -e 4 | 5 | if ! which jazzy >/dev/null; then 6 | echo "Error: Jazzy not installed, see https://github.com/realm/Jazzy or run 'gem install jazzy' to install it" 7 | exit 1 8 | fi 9 | 10 | if ! which jq >/dev/null; then 11 | echo "Error: jq not installed, run 'brew install jq' to install it" 12 | exit 1 13 | fi 14 | 15 | read -p 'Enter release tag (without quotes): ' RELEASE_TAG 16 | 17 | AUTHOR_NAME="Pusher Limited" 18 | AUTHOR_URL="https://pusher.com" 19 | GITHUB_ORIGIN="https://github.com/pusher/pusher-websocket-swift" 20 | GITHUB_URL=${GITHUB_ORIGIN%".git"} 21 | MODULE_NAME=$(swift package dump-package | jq --raw-output '.name') 22 | 23 | echo "Generating public API docs from release tag $RELEASE_TAG" 24 | 25 | # The 'arch -x86_64' command is redundant on Intel Macs, and runs Jazzy under Rosetta 2 on Apple Silicon Macs for compatibility 26 | arch -x86_64 jazzy \ 27 | --module $MODULE_NAME \ 28 | --module_version $RELEASE_TAG \ 29 | --swift-build-tool spm \ 30 | --author $AUTHOR_NAME \ 31 | --author_url $AUTHOR_URL \ 32 | --github_url $GITHUB_URL \ 33 | --github-file-prefix $GITHUB_URL/tree/$RELEASE_TAG -------------------------------------------------------------------------------- /Sources/Extensions/PusherChannel+EncryptionHelpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension PusherChannel { 4 | 5 | /// Determines whether or not a message should be decrypted, based on channel and event attributes. 6 | /// - Parameters: 7 | /// - name: The name of the channel. 8 | /// - eventName: The name of the event received on the channel. 9 | /// - Returns: A `Bool` indicating whether the message should be decrypted or not. 10 | static func decryptsMessage(name: String?, eventName: String) -> Bool { 11 | return isEncrypted(name: name) && !isSystemEvent(eventName: eventName) 12 | } 13 | 14 | /// Determines if a channel is a private encrypted or not, based on its name. 15 | /// - Parameter name: The name of the channel. 16 | /// - Returns: A `Bool` indicating whether the channel is encrypted or not. 17 | static func isEncrypted(name: String?) -> Bool { 18 | return name?.starts(with: "\(Constants.ChannelTypes.privateEncrypted)-") ?? false 19 | } 20 | 21 | /// Determines if an event is a system event or not, based on its name. 22 | /// - Parameter eventName: The name of the event. 23 | /// - Returns: A `Bool` indicating whether the event is a system event or not. 24 | private static func isSystemEvent(eventName: String) -> Bool { 25 | return eventName.starts(with: "\(Constants.EventTypes.pusher):") 26 | || eventName.starts(with: "\(Constants.EventTypes.pusherInternal):") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Extensions/URL+Pusher.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension URL { 4 | 5 | /// Creates a valid URL string that can be used in a connection attempt. 6 | /// - Parameters: 7 | /// - key: The app key to be inserted into the URL. 8 | /// - options: The collection of options needed to correctly construct the URL. 9 | /// - Returns: The constructed URL string, ready to use in a connection attempt. 10 | static func channelsSocketUrl(key: String, options: PusherClientOptions) -> String { 11 | var url = "" 12 | let additionalPathComponents = options.path ?? "" 13 | 14 | if options.useTLS { 15 | url = "wss://\(options.host):\(options.port)\(additionalPathComponents)/app/\(key)" 16 | } else { 17 | url = "ws://\(options.host):\(options.port)\(additionalPathComponents)/app/\(key)" 18 | } 19 | 20 | return "\(url)?client=\(CLIENT_NAME)&version=\(VERSION)&protocol=\(PROTOCOL)" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Helpers/EventParser.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct EventParser { 4 | 5 | /** 6 | Parse a string to extract Pusher event information from it 7 | 8 | - parameter string: The string received over the websocket connection containing 9 | Pusher event information 10 | 11 | - returns: A dictionary of Pusher-relevant event data 12 | */ 13 | 14 | static func getPusherEventJSON(from string: String) -> [String: AnyObject]? { 15 | let data = (string as NSString).data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false) 16 | 17 | do { 18 | if let jsonData = data, 19 | let jsonObject = try JSONSerialization.jsonObject(with: jsonData, 20 | options: []) as? [String: AnyObject] { 21 | return jsonObject 22 | } else { 23 | Logger.shared.debug(for: .unableToParseStringAsJSON, 24 | context: string) 25 | } 26 | } catch let error as NSError { 27 | Logger.shared.error(for: .genericError, 28 | context: error.localizedDescription) 29 | } 30 | return nil 31 | } 32 | 33 | /** 34 | Parse a string to extract Pusher event data from it 35 | 36 | - parameter string: The data string received as part of a Pusher message 37 | 38 | - returns: The object sent as the payload part of the Pusher message 39 | */ 40 | static func getEventDataJSON(from string: String) -> Any? { 41 | let data = (string as NSString).data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false) 42 | 43 | do { 44 | if let jsonData = data, let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []) { 45 | return jsonObject 46 | } else { 47 | Logger.shared.debug(for: .unableToParseStringAsJSON, 48 | context: string) 49 | } 50 | } 51 | return nil 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 10.1.5 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/Models/AuthError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct AuthError: Error { 4 | enum Kind { 5 | case notConnected 6 | case noMethod 7 | case couldNotBuildRequest 8 | case invalidAuthResponse 9 | case requestFailure 10 | } 11 | 12 | let kind: Kind 13 | 14 | var message: String? 15 | 16 | var response: URLResponse? 17 | var data: String? 18 | var error: NSError? 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Models/AuthMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum AuthMethod { 4 | case endpoint(authEndpoint: String) 5 | case authRequestBuilder(authRequestBuilder: AuthRequestBuilderProtocol) 6 | case authorizer(authorizer: Authorizer) 7 | case inline(secret: String) 8 | case noMethod 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Models/ConnectionState.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public enum ConnectionState: Int { 4 | case connecting 5 | case connected 6 | case disconnecting 7 | case disconnected 8 | case reconnecting 9 | 10 | static let connectionStates = [ 11 | connecting: "connecting", 12 | connected: "connected", 13 | disconnecting: "disconnecting", 14 | disconnected: "disconnected", 15 | reconnecting: "reconnecting" 16 | ] 17 | 18 | public func stringValue() -> String { 19 | return ConnectionState.connectionStates[self]! 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Models/Constants.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // swiftlint:disable nesting 4 | 5 | enum Constants { 6 | 7 | enum API { 8 | static let defaultHost = "ws.pusherapp.com" 9 | static let pusherDomain = "pusher.com" 10 | } 11 | 12 | enum ChannelTypes { 13 | static let presence = "presence" 14 | static let `private` = "private" 15 | static let privateEncrypted = "private-encrypted" 16 | } 17 | 18 | enum Events { 19 | enum Pusher { 20 | static let connectionEstablished = "pusher:connection_established" 21 | static let error = "pusher:error" 22 | static let subscribe = "pusher:subscribe" 23 | static let unsubscribe = "pusher:unsubscribe" 24 | static let subscriptionError = "pusher:subscription_error" 25 | static let subscriptionSucceeded = "pusher:subscription_succeeded" 26 | } 27 | 28 | enum PusherInternal { 29 | static let memberAdded = "pusher_internal:member_added" 30 | static let memberRemoved = "pusher_internal:member_removed" 31 | static let subscriptionSucceeded = "pusher_internal:subscription_succeeded" 32 | static let subscriptionCount = "pusher_internal:subscription_count" 33 | } 34 | } 35 | 36 | enum EventTypes { 37 | static let client = "client" 38 | static let pusher = "pusher" 39 | static let pusherInternal = "pusher_internal" 40 | } 41 | 42 | enum JSONKeys { 43 | static let activityTimeout = "activity_timeout" 44 | static let auth = "auth" 45 | static let channel = "channel" 46 | static let channelData = "channel_data" 47 | static let ciphertext = "ciphertext" 48 | static let code = "code" 49 | static let data = "data" 50 | static let event = "event" 51 | static let hash = "hash" 52 | static let message = "message" 53 | static let nonce = "nonce" 54 | static let presence = "presence" 55 | static let socketId = "socket_id" 56 | static let sharedSecret = "shared_secret" 57 | static let userId = "user_id" 58 | static let userInfo = "user_info" 59 | static let subscriptionCount = "subscription_count" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/Models/EventError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum EventError: Error { 4 | 5 | case invalidFormat 6 | case invalidDecryptionKey 7 | case invalidEncryptedData 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Models/EventHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct EventHandler { 4 | let id: String 5 | let callback: (PusherEvent) -> Void 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Models/PusherAuth.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public class PusherAuth: NSObject { 4 | public let auth: String 5 | public let channelData: String? 6 | public let sharedSecret: String? 7 | 8 | public init(auth: String, channelData: String? = nil, sharedSecret: String? = nil) { 9 | self.auth = auth 10 | self.channelData = channelData 11 | self.sharedSecret = sharedSecret 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Models/PusherChannelType.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum PusherChannelType { 4 | case `private` 5 | case presence 6 | case normal 7 | 8 | public init(name: String) { 9 | self = Self.type(forName: name) 10 | } 11 | 12 | public static func type(forName name: String) -> PusherChannelType { 13 | if name.components(separatedBy: "-")[0] == Constants.ChannelTypes.presence { 14 | return .presence 15 | } else if name.components(separatedBy: "-")[0] == Constants.ChannelTypes.private { 16 | return .private 17 | } else { 18 | return .normal 19 | } 20 | } 21 | 22 | public static func isPresenceChannel(name: String) -> Bool { 23 | return PusherChannelType(name: name) == .presence 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Models/PusherClientOptions.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | @objc public class PusherClientOptions: NSObject { 5 | public var authMethod: AuthMethod 6 | public let attemptToReturnJSONObject: Bool 7 | public let autoReconnect: Bool 8 | public let host: String 9 | public let port: Int 10 | public let path: String? 11 | public let useTLS: Bool 12 | public let activityTimeout: TimeInterval? 13 | 14 | @nonobjc public init( 15 | authMethod: AuthMethod = .noMethod, 16 | attemptToReturnJSONObject: Bool = true, 17 | autoReconnect: Bool = true, 18 | host: PusherHost = .defaultHost, 19 | port: Int? = nil, 20 | path: String? = nil, 21 | useTLS: Bool = true, 22 | activityTimeout: TimeInterval? = nil 23 | ) { 24 | self.authMethod = authMethod 25 | self.attemptToReturnJSONObject = attemptToReturnJSONObject 26 | self.autoReconnect = autoReconnect 27 | self.host = host.stringValue 28 | self.path = path 29 | self.port = port ?? (useTLS ? 443 : 80) 30 | self.useTLS = useTLS 31 | self.activityTimeout = activityTimeout 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Models/PusherError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | open class PusherError: NSObject { 5 | 6 | /// Code is optional, message is not: 7 | /// https://pusher.com/docs/channels/library_auth_reference/pusher-websockets-protocol#-pusher-error-channels-client- 8 | /// The error code. 9 | public let code: Int? 10 | /// The error message. 11 | public let message: String 12 | 13 | @nonobjc internal init?(jsonObject: [String: Any]) { 14 | guard let data = jsonObject[Constants.JSONKeys.data] as? [String: Any] else { 15 | return nil 16 | } 17 | 18 | guard let message = data[Constants.JSONKeys.message] as? String else { 19 | return nil 20 | } 21 | 22 | self.code = data[Constants.JSONKeys.code] as? Int 23 | self.message = message 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Models/PusherGlobalChannel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | @objc open class GlobalChannel: PusherChannel { 5 | open var globalCallbacks: [String: (PusherEvent) -> Void] = [:] 6 | 7 | /** 8 | Initializes a new GlobalChannel instance 9 | 10 | - parameter connection: The connection associated with the global channel 11 | 12 | - returns: A new GlobalChannel instance 13 | */ 14 | init(connection: PusherConnection) { 15 | super.init(name: "pusher_global_internal_channel", connection: connection) 16 | } 17 | 18 | /** 19 | Calls the appropriate callbacks for the given event name in the scope of the global channel 20 | 21 | - parameter event: The event received from the websocket 22 | */ 23 | internal func handleGlobalEvent(event: PusherEvent) { 24 | for (_, callback) in self.globalCallbacks { 25 | // swiftlint:disable:next force_cast 26 | callback(event.copy() as! PusherEvent) 27 | } 28 | } 29 | 30 | /** 31 | Binds a callback to the global channel 32 | 33 | - parameter callback: The function to call when a message is received 34 | 35 | - returns: A unique callbackId that can be used to unbind the callback at a later time 36 | */ 37 | internal func bind(_ callback: @escaping (PusherEvent) -> Void) -> String { 38 | let randomId = UUID().uuidString 39 | self.globalCallbacks[randomId] = callback 40 | return randomId 41 | } 42 | 43 | /** 44 | Unbinds the callback with the given callbackId from the global channel 45 | 46 | - parameter callbackId: The unique callbackId string used to identify which callback to unbind 47 | */ 48 | internal func unbind(callbackId: String) { 49 | globalCallbacks.removeValue(forKey: callbackId) 50 | } 51 | 52 | /** 53 | Unbinds all callbacks from the channel 54 | */ 55 | override open func unbindAll() { 56 | globalCallbacks = [:] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sources/Models/PusherHost.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum PusherHost { 4 | case host(String) 5 | case cluster(String) 6 | 7 | public static var defaultHost: Self { 8 | return .host(Constants.API.defaultHost) 9 | } 10 | 11 | public var stringValue: String { 12 | switch self { 13 | case .host(let host): return host 14 | case .cluster(let cluster): return "ws-\(cluster).\(Constants.API.pusherDomain)" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Models/PusherPresenceChannelMember.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | @objc public class PusherPresenceChannelMember: NSObject { 5 | public let userId: String 6 | public let userInfo: Any? 7 | 8 | public init(userId: String, userInfo: Any? = nil) { 9 | self.userId = userId 10 | self.userInfo = userInfo 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Models/QueuedClientEvent.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public struct QueuedClientEvent { 4 | public let name: String 5 | public let data: Any 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ObjC/AuthMethod+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension AuthMethod { 4 | func toObjc() -> OCAuthMethod { 5 | switch self { 6 | case let .endpoint(authEndpoint): 7 | return OCAuthMethod(authEndpoint: authEndpoint) 8 | 9 | case let .authRequestBuilder(authRequestBuilder): 10 | return OCAuthMethod(authRequestBuilder: authRequestBuilder) 11 | 12 | case let .inline(secret): 13 | return OCAuthMethod(secret: secret) 14 | 15 | case let .authorizer(authorizer): 16 | return OCAuthMethod(authorizer: authorizer) 17 | 18 | case .noMethod: 19 | return OCAuthMethod(type: 4) 20 | } 21 | } 22 | 23 | static func fromObjc(source: OCAuthMethod) -> AuthMethod { 24 | switch source.type { 25 | case 0: return AuthMethod.endpoint(authEndpoint: source.authEndpoint!) 26 | case 1: return AuthMethod.authRequestBuilder(authRequestBuilder: source.authRequestBuilder!) 27 | case 2: return AuthMethod.inline(secret: source.secret!) 28 | case 3: return AuthMethod.authorizer(authorizer: source.authorizer!) 29 | case 4: return AuthMethod.noMethod 30 | default: return AuthMethod.noMethod 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/ObjC/OCAuthMethod.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | @objc public class OCAuthMethod: NSObject { 5 | var type: Int 6 | var secret: String? 7 | var authEndpoint: String? 8 | var authRequestBuilder: AuthRequestBuilderProtocol? 9 | var authorizer: Authorizer? 10 | 11 | public init(type: Int) { 12 | self.type = type 13 | } 14 | 15 | public init(authEndpoint: String) { 16 | self.type = 0 17 | self.authEndpoint = authEndpoint 18 | } 19 | 20 | public init(authRequestBuilder: AuthRequestBuilderProtocol) { 21 | self.type = 1 22 | self.authRequestBuilder = authRequestBuilder 23 | } 24 | 25 | public init(secret: String) { 26 | self.type = 2 27 | self.secret = secret 28 | } 29 | 30 | public init(authorizer: Authorizer) { 31 | self.type = 3 32 | self.authorizer = authorizer 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/ObjC/OCPusherHost.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objcMembers 4 | @objc public class OCPusherHost: NSObject { 5 | var type: Int 6 | var host: String? 7 | var cluster: String? 8 | 9 | override public init() { 10 | self.type = 2 11 | } 12 | 13 | public init(host: String) { 14 | self.type = 0 15 | self.host = host 16 | } 17 | 18 | public init(cluster: String) { 19 | self.type = 1 20 | self.cluster = cluster 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ObjC/Pusher+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public extension Pusher { 4 | func subscribe(channelName: String) -> PusherChannel { 5 | return self.subscribe(channelName, onMemberAdded: nil, onMemberRemoved: nil) 6 | } 7 | 8 | func subscribe( 9 | channelName: String, 10 | onMemberAdded: ((PusherPresenceChannelMember) -> Void)? = nil, 11 | onMemberRemoved: ((PusherPresenceChannelMember) -> Void)? = nil, 12 | onSubscriptionCountChanged: ((Int) -> Void)? = nil 13 | ) -> PusherChannel { 14 | return self.subscribe(channelName, 15 | auth: nil, 16 | onMemberAdded: onMemberAdded, 17 | onMemberRemoved: onMemberRemoved, 18 | onSubscriptionCountChanged: onSubscriptionCountChanged) 19 | } 20 | 21 | func subscribeToPresenceChannel(channelName: String) -> PusherPresenceChannel { 22 | return self.subscribeToPresenceChannel(channelName: channelName, 23 | auth: nil, 24 | onMemberAdded: nil, 25 | onMemberRemoved: nil, 26 | onSubscriptionCountChanged: nil) 27 | } 28 | 29 | func subscribeToPresenceChannel( 30 | channelName: String, 31 | onMemberAdded: ((PusherPresenceChannelMember) -> Void)? = nil, 32 | onMemberRemoved: ((PusherPresenceChannelMember) -> Void)? = nil, 33 | onSubscriptionCountChanged: ((Int) -> Void)? = nil 34 | ) -> PusherPresenceChannel { 35 | return self.subscribeToPresenceChannel(channelName: channelName, 36 | auth: nil, 37 | onMemberAdded: onMemberAdded, 38 | onMemberRemoved: onMemberRemoved, 39 | onSubscriptionCountChanged: onSubscriptionCountChanged) 40 | } 41 | 42 | convenience init(withAppKey key: String, options: PusherClientOptions) { 43 | self.init(key: key, options: options) 44 | } 45 | 46 | convenience init(withKey key: String) { 47 | self.init(key: key) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/ObjC/PusherClientOptions+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public extension PusherClientOptions { 4 | 5 | // initializer without legacy "attemptToReturnJSONObject" 6 | convenience init( 7 | ocAuthMethod authMethod: OCAuthMethod, 8 | autoReconnect: Bool = true, 9 | ocHost host: OCPusherHost = PusherHost.defaultHost.toObjc(), 10 | port: NSNumber? = nil, 11 | useTLS: Bool = true, 12 | activityTimeout: NSNumber? = nil 13 | ) { 14 | self.init( 15 | ocAuthMethod: authMethod, 16 | attemptToReturnJSONObject: true, 17 | autoReconnect: autoReconnect, 18 | ocHost: host, 19 | port: port, 20 | useTLS: useTLS, 21 | activityTimeout: activityTimeout 22 | ) 23 | } 24 | 25 | convenience init( 26 | ocAuthMethod authMethod: OCAuthMethod, 27 | attemptToReturnJSONObject: Bool = true, 28 | autoReconnect: Bool = true, 29 | ocHost host: OCPusherHost = PusherHost.defaultHost.toObjc(), 30 | port: NSNumber? = nil, 31 | useTLS: Bool = true, 32 | activityTimeout: NSNumber? = nil 33 | ) { 34 | self.init( 35 | authMethod: AuthMethod.fromObjc(source: authMethod), 36 | attemptToReturnJSONObject: attemptToReturnJSONObject, 37 | autoReconnect: autoReconnect, 38 | host: PusherHost.fromObjc(source: host), 39 | port: port as? Int, 40 | useTLS: useTLS, 41 | activityTimeout: activityTimeout as? TimeInterval 42 | ) 43 | } 44 | 45 | convenience init(authMethod: OCAuthMethod) { 46 | self.init(authMethod: AuthMethod.fromObjc(source: authMethod)) 47 | } 48 | 49 | func setAuthMethod(authMethod: OCAuthMethod) { 50 | self.authMethod = AuthMethod.fromObjc(source: authMethod) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/ObjC/PusherConnection+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public extension PusherConnection { 4 | var OCReconnectAttemptsMax: NSNumber? { 5 | get { 6 | return reconnectAttemptsMax as NSNumber? 7 | } 8 | set(newValue) { 9 | reconnectAttemptsMax = newValue?.intValue 10 | } 11 | } 12 | 13 | var OCMaxReconnectGapInSeconds: NSNumber? { 14 | get { 15 | return maxReconnectGapInSeconds as NSNumber? 16 | } 17 | set(newValue) { 18 | maxReconnectGapInSeconds = newValue?.doubleValue 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ObjC/PusherError+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension PusherError { 4 | /// The error code as an NSNumber (for Objective-C compatibility). 5 | var codeOC: NSNumber? { 6 | guard let code = code else { 7 | return nil 8 | } 9 | 10 | return NSNumber(value: code) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ObjC/PusherHost+ObjectiveC.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public extension PusherHost { 4 | func toObjc() -> OCPusherHost { 5 | switch self { 6 | case let .host(host): 7 | return OCPusherHost(host: host) 8 | 9 | case let .cluster(cluster): 10 | return OCPusherHost(cluster: "ws-\(cluster).\(Constants.API.pusherDomain)") 11 | } 12 | } 13 | 14 | static func fromObjc(source: OCPusherHost) -> PusherHost { 15 | switch source.type { 16 | case 0: return PusherHost.host(source.host!) 17 | case 1: return PusherHost.cluster(source.cluster!) 18 | default: return PusherHost.defaultHost 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Protocols/AuthRequestBuilderProtocol.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public protocol AuthRequestBuilderProtocol { 4 | @objc optional func requestFor(socketID: String, channelName: String) -> URLRequest? 5 | } 6 | -------------------------------------------------------------------------------- /Sources/Protocols/Authorizer.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public protocol Authorizer { 4 | @objc func fetchAuthValue(socketID: String, channelName: String, completionHandler: @escaping (PusherAuth?) -> Void) 5 | } 6 | -------------------------------------------------------------------------------- /Sources/Protocols/EventFactory.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol EventFactory { 4 | 5 | func makeEvent(fromJSON json: ChannelEventPayload, withDecryptionKey decryptionKey: String?) throws -> PusherEvent 6 | } 7 | -------------------------------------------------------------------------------- /Sources/Protocols/EventQueue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol EventQueue { 4 | 5 | var delegate: EventQueueDelegate? { get set } 6 | 7 | func enqueue(json: ChannelEventPayload) 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Protocols/EventQueueDelegate.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | protocol EventQueueDelegate: AnyObject { 4 | 5 | func eventQueue(_ eventQueue: EventQueue, 6 | didReceiveEvent event: PusherEvent, 7 | forChannelName channelName: String?) 8 | func eventQueue(_ eventQueue: EventQueue, 9 | didFailToDecryptEventWithPayload payload: ChannelEventPayload, 10 | forChannelName channelName: String) 11 | func eventQueue(_ eventQueue: EventQueue, 12 | didReceiveInvalidEventWithPayload payload: ChannelEventPayload) 13 | func eventQueue(_ eventQueue: EventQueue, 14 | reloadDecryptionKeySyncForChannel channel: PusherChannel) 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Protocols/PusherDelegate.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @objc public protocol PusherDelegate: AnyObject { 4 | @objc optional func debugLog(message: String) 5 | 6 | @objc optional func changedConnectionState(from old: ConnectionState, to new: ConnectionState) 7 | @objc optional func subscribedToChannel(name: String) 8 | @objc optional func failedToSubscribeToChannel(name: String, response: URLResponse?, data: String?, error: NSError?) 9 | @objc optional func failedToDecryptEvent(eventName: String, channelName: String, data: String?) 10 | @objc(receivedError:) optional func receivedError(error: PusherError) 11 | } 12 | -------------------------------------------------------------------------------- /Sources/PusherSwift.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for PusherSwift. 4 | FOUNDATION_EXPORT double PusherSwiftVersionNumber; 5 | 6 | //! Project version string for PusherSwift. 7 | FOUNDATION_EXPORT const unsigned char PusherSwiftVersionString[]; 8 | -------------------------------------------------------------------------------- /Sources/Services/ChannelEventFactory.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // MARK: - Types 4 | 5 | typealias ChannelEventPayload = [String: Any] 6 | 7 | struct ChannelEventFactory: EventFactory { 8 | 9 | // MARK: - Event factory 10 | 11 | func makeEvent(fromJSON json: ChannelEventPayload, 12 | withDecryptionKey decryptionKey: String? = nil) throws -> PusherEvent { 13 | guard let eventName = json[Constants.JSONKeys.event] as? String else { 14 | throw EventError.invalidFormat 15 | } 16 | 17 | let channelName = json[Constants.JSONKeys.channel] as? String 18 | let data = try self.data(fromJSON: json, 19 | eventName: eventName, 20 | channelName: channelName, decryptionKey: decryptionKey) 21 | let userId = json[Constants.JSONKeys.userId] as? String 22 | 23 | return PusherEvent(eventName: eventName, channelName: channelName, data: data, userId: userId, raw: json) 24 | } 25 | 26 | // MARK: - Private methods 27 | 28 | private func data(fromJSON json: ChannelEventPayload, 29 | eventName: String, 30 | channelName: String?, 31 | decryptionKey: String?) throws -> String? { 32 | let data = json[Constants.JSONKeys.data] as? String 33 | 34 | if PusherChannel.decryptsMessage(name: channelName, eventName: eventName) { 35 | return try Crypto.decrypt(data: data, decryptionKey: decryptionKey) 36 | } else { 37 | return data 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Services/ChannelEventQueue.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class ChannelEventQueue: EventQueue { 4 | 5 | // MARK: - Properties 6 | 7 | private let eventFactory: EventFactory 8 | private let channels: PusherChannels 9 | private var queue = DispatchQueue(label: "com.pusher.pusherswift-event-queue-\(UUID().uuidString)") 10 | 11 | weak var delegate: EventQueueDelegate? 12 | 13 | // MARK: - Initializers 14 | 15 | init(eventFactory: EventFactory, channels: PusherChannels) { 16 | self.eventFactory = eventFactory 17 | self.channels = channels 18 | } 19 | 20 | // MARK: - Event queue 21 | public func enqueue(json: ChannelEventPayload) { 22 | var channel: PusherChannel? 23 | 24 | // If this event is for a particular channel, find the channel 25 | if let channelName = json[Constants.JSONKeys.channel] as? String { 26 | channel = channels.find(name: channelName) 27 | if channel == nil { 28 | // If we can't find the channel then we have unsubscribed, drop the event 29 | return 30 | } 31 | } 32 | 33 | queue.async { 34 | self.processEventWithRetries(json: json, channel: channel) 35 | } 36 | } 37 | 38 | // MARK: - Private methods 39 | 40 | private func processEventWithRetries(json: ChannelEventPayload, channel: PusherChannel?) { 41 | do { 42 | try self.processEvent(json: json, channel: channel) 43 | } catch EventError.invalidDecryptionKey { 44 | // Reload decryption key if we could not decrypt the payload due to the key 45 | // Only events on encrypted channels throw this error, which have a channel 46 | guard let channel = channel else { 47 | return 48 | } 49 | 50 | self.delegate?.eventQueue(self, reloadDecryptionKeySyncForChannel: channel) 51 | do { 52 | try self.processEvent(json: json, channel: channel) 53 | } catch { 54 | self.delegate?.eventQueue(self, 55 | didFailToDecryptEventWithPayload: json, 56 | forChannelName: channel.name) 57 | } 58 | } catch EventError.invalidEncryptedData { 59 | // If there was a problem with the payload, e.g. nonce missing, then we cannot retry 60 | guard let channelName = channel?.name else { 61 | return 62 | } 63 | 64 | self.delegate?.eventQueue(self, didFailToDecryptEventWithPayload: json, forChannelName: channelName) 65 | } catch { 66 | self.delegate?.eventQueue(self, didReceiveInvalidEventWithPayload: json) 67 | } 68 | } 69 | 70 | private func processEvent(json: ChannelEventPayload, channel: PusherChannel? = nil) throws { 71 | let event = try self.eventFactory.makeEvent(fromJSON: json, withDecryptionKey: channel?.decryptionKey) 72 | self.delegate?.eventQueue(self, didReceiveEvent: event, forChannelName: channel?.name) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Tests/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_cast 3 | - line_length 4 | - type_body_length 5 | - file_length -------------------------------------------------------------------------------- /Tests/Extensions/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | extension String { 4 | 5 | func removing(_ set: CharacterSet) -> String { 6 | var newString = self 7 | newString.removeAll { char -> Bool in 8 | guard let scalar = char.unicodeScalars.first else { return false } 9 | return set.contains(scalar) 10 | } 11 | return newString 12 | } 13 | 14 | var escaped: String { 15 | return self.debugDescription 16 | } 17 | 18 | func toJsonData(validate: Bool = true, file: StaticString = #file, line: UInt = #line) -> Data { 19 | do { 20 | let data = try self.toData() 21 | if validate { 22 | // Verify the string is valid JSON (either a dict or an array) before returning 23 | _ = try toJsonAny() 24 | } 25 | return data 26 | } catch { 27 | XCTFail("\(error)", file: file, line: line) 28 | } 29 | return Data() 30 | } 31 | 32 | func toJsonDict(file: StaticString = #file, line: UInt = #line) -> [String: Any] { 33 | do { 34 | let json = try toJsonAny() 35 | 36 | guard let jsonDict = json as? [String: Any] else { 37 | XCTFail("Not a dictionary", file: file, line: line) 38 | return [:] 39 | } 40 | return jsonDict 41 | } catch { 42 | XCTFail("\(error)", file: file, line: line) 43 | } 44 | return [:] 45 | } 46 | 47 | // MARK: - Private methods 48 | 49 | private func toJsonAny() throws -> Any { 50 | return try JSONSerialization.jsonObject(with: self.toData(), options: .allowFragments) 51 | } 52 | 53 | private func toData() throws -> Data { 54 | guard let data = self.data(using: .utf8) else { 55 | throw JSONError.conversionFailed 56 | } 57 | return data 58 | } 59 | } 60 | 61 | // MARK: - Error handling 62 | 63 | enum JSONError: Error { 64 | case conversionFailed 65 | } 66 | -------------------------------------------------------------------------------- /Tests/Extensions/XCTest+Assertions.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | private func executeAndAssignResult(_ expression: () throws -> T?, to: inout T?) rethrows { 4 | to = try expression() 5 | } 6 | 7 | private func executeAndAssignEquatableResult(_ expression: @autoclosure () throws -> T?, to: inout T?) rethrows where T: Equatable { 8 | to = try expression() 9 | } 10 | 11 | func XCTAssertNotNil(_ expression: @autoclosure () throws -> T?, _ message: String = "", file: StaticString = #file, line: UInt = #line, also validateResult: (T) -> Void) { 12 | 13 | var result: T? 14 | 15 | XCTAssertNoThrow(try executeAndAssignResult(expression, to: &result), message, file: file, line: line) 16 | XCTAssertNotNil(result, message, file: file, line: line) 17 | 18 | if let result = result { 19 | validateResult(result) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/Helpers/Helpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | @testable import PusherSwift 4 | 5 | func convertStringToDictionary(_ text: String) -> [String: AnyObject]? { 6 | guard let data = text.data(using: .utf8) else { 7 | return nil 8 | } 9 | 10 | do { 11 | let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: AnyObject] 12 | return json 13 | } catch { 14 | print("Something went wrong") 15 | 16 | return nil 17 | } 18 | } 19 | 20 | extension AuthMethod: Equatable { 21 | 22 | public static func == (lhs: AuthMethod, rhs: AuthMethod) -> Bool { 23 | switch (lhs, rhs) { 24 | case (let .endpoint(authEndpoint1), let .endpoint(authEndpoint2)): 25 | return authEndpoint1 == authEndpoint2 26 | 27 | case (let .inline(secret1), let .inline(secret2)): 28 | return secret1 == secret2 29 | 30 | case (.noMethod, .noMethod): 31 | return true 32 | 33 | default: 34 | return false 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 10.1.5 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/Unit/Helpers/CryptoTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @testable import PusherSwift 4 | 5 | class CryptoTests: XCTestCase { 6 | 7 | private let testMessage = "{\"user\":\"my user data\"}" 8 | private let testSecret = "mysecret" 9 | 10 | func testHMACGeneratorGeneratesCorrectMAC() { 11 | let digest = Crypto.generateSHA256HMAC(secret: testSecret, message: testMessage) 12 | 13 | let expectedDigest = "7705bb9a7934fe4ceee2325e23750f35752899448c2fe5b064d93326c98fd5b3" 14 | XCTAssertEqual(digest, expectedDigest) 15 | } 16 | 17 | func testHMACGeneratorEmptySecret() { 18 | let digest = Crypto.generateSHA256HMAC(secret: "", message: testMessage) 19 | 20 | let expectedDigest = "a31926f3c0e20c8fd6174ac08c0057708590b6a6bb081a04560ea60b4500738a" 21 | XCTAssertEqual(digest, expectedDigest) 22 | } 23 | 24 | func testHMACGeneratorEmptyMessage() { 25 | let digest = Crypto.generateSHA256HMAC(secret: testSecret, message: "") 26 | 27 | let expectedDigest = "9074a74de0f34ece3f046403ae88d2eea400281da0ed6ebfa76c949016fa672d" 28 | XCTAssertEqual(digest, expectedDigest) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/Unit/Services/PusherConnectionTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @testable import PusherSwift 4 | 5 | class PusherConnectionTests: XCTestCase { 6 | private var key: String! 7 | private var pusher: Pusher! 8 | 9 | override func setUp() { 10 | super.setUp() 11 | 12 | key = "testKey123" 13 | pusher = Pusher(key: key) 14 | } 15 | 16 | func testUserDataFetcherIsNilByDefault() { 17 | XCTAssertNil(pusher.connection.userDataFetcher, "userDataFetcher should be nil") 18 | } 19 | 20 | func testDelegateIsNilByDefault() { 21 | XCTAssertNil(pusher.connection.delegate, "delegate should be nil") 22 | } 23 | 24 | func testSettingADelegate() { 25 | class DummyDelegate: PusherDelegate {} 26 | let dummyDelegate = DummyDelegate() 27 | pusher.delegate = dummyDelegate 28 | XCTAssertNotNil(pusher.connection.delegate, "delegate should not be nil") 29 | } 30 | 31 | func testSettingAUserDataFetcher() { 32 | func fetchFunc() -> PusherPresenceChannelMember { 33 | return PusherPresenceChannelMember(userId: "1") 34 | } 35 | pusher.connection.userDataFetcher = fetchFunc 36 | XCTAssertNotNil(pusher.connection.userDataFetcher, "userDataFetcher should not be nil") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 24% 23 | 24 | 25 | 24% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.pusherswift 7 | CFBundleName 8 | PusherSwift 9 | DocSetPlatformFamily 10 | pusherswift 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/badge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | documentation 17 | 18 | 19 | documentation 20 | 21 | 22 | 24% 23 | 24 | 25 | 24% 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.docset/Contents/Resources/Documents/img/spinner.gif -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/Documents/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/PusherSwift.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/docsets/PusherSwift.tgz -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/img/carat.png -------------------------------------------------------------------------------- /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/docs/img/spinner.gif -------------------------------------------------------------------------------- /docs/js/jazzy.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | window.jazzy = {'docset': false} 6 | if (typeof window.dash != 'undefined') { 7 | document.documentElement.className += ' dash' 8 | window.jazzy.docset = true 9 | } 10 | if (navigator.userAgent.match(/xcode/i)) { 11 | document.documentElement.className += ' xcode' 12 | window.jazzy.docset = true 13 | } 14 | 15 | function toggleItem($link, $content) { 16 | var animationDuration = 300; 17 | $link.toggleClass('token-open'); 18 | $content.slideToggle(animationDuration); 19 | } 20 | 21 | function itemLinkToContent($link) { 22 | return $link.parent().parent().next(); 23 | } 24 | 25 | // On doc load + hash-change, open any targetted item 26 | function openCurrentItemIfClosed() { 27 | if (window.jazzy.docset) { 28 | return; 29 | } 30 | var $link = $(`a[name="${location.hash.substring(1)}"]`).nextAll('.token'); 31 | $content = itemLinkToContent($link); 32 | if ($content.is(':hidden')) { 33 | toggleItem($link, $content); 34 | } 35 | } 36 | 37 | $(openCurrentItemIfClosed); 38 | $(window).on('hashchange', openCurrentItemIfClosed); 39 | 40 | // On item link ('token') click, toggle its discussion 41 | $('.token').on('click', function(event) { 42 | if (window.jazzy.docset) { 43 | return; 44 | } 45 | var $link = $(this); 46 | toggleItem($link, itemLinkToContent($link)); 47 | 48 | // Keeps the document from jumping to the hash. 49 | var href = $link.attr('href'); 50 | if (history.pushState) { 51 | history.pushState({}, '', href); 52 | } else { 53 | location.hash = href; 54 | } 55 | event.preventDefault(); 56 | }); 57 | 58 | // Clicks on links to the current, closed, item need to open the item 59 | $("a:not('.token')").on('click', function() { 60 | if (location == this.href) { 61 | openCurrentItemIfClosed(); 62 | } 63 | }); 64 | 65 | // KaTeX rendering 66 | if ("katex" in window) { 67 | $($('.math').each( (_, element) => { 68 | katex.render(element.textContent, element, { 69 | displayMode: $(element).hasClass('m-block'), 70 | throwOnError: false, 71 | trust: true 72 | }); 73 | })) 74 | } 75 | -------------------------------------------------------------------------------- /docs/js/jazzy.search.js: -------------------------------------------------------------------------------- 1 | // Jazzy - https://github.com/realm/jazzy 2 | // Copyright Realm Inc. 3 | // SPDX-License-Identifier: MIT 4 | 5 | $(function(){ 6 | var $typeahead = $('[data-typeahead]'); 7 | var $form = $typeahead.parents('form'); 8 | var searchURL = $form.attr('action'); 9 | 10 | function displayTemplate(result) { 11 | return result.name; 12 | } 13 | 14 | function suggestionTemplate(result) { 15 | var t = '
'; 16 | t += '' + result.name + ''; 17 | if (result.parent_name) { 18 | t += '' + result.parent_name + ''; 19 | } 20 | t += '
'; 21 | return t; 22 | } 23 | 24 | $typeahead.one('focus', function() { 25 | $form.addClass('loading'); 26 | 27 | $.getJSON(searchURL).then(function(searchData) { 28 | const searchIndex = lunr(function() { 29 | this.ref('url'); 30 | this.field('name'); 31 | this.field('abstract'); 32 | for (const [url, doc] of Object.entries(searchData)) { 33 | this.add({url: url, name: doc.name, abstract: doc.abstract}); 34 | } 35 | }); 36 | 37 | $typeahead.typeahead( 38 | { 39 | highlight: true, 40 | minLength: 3, 41 | autoselect: true 42 | }, 43 | { 44 | limit: 10, 45 | display: displayTemplate, 46 | templates: { suggestion: suggestionTemplate }, 47 | source: function(query, sync) { 48 | const lcSearch = query.toLowerCase(); 49 | const results = searchIndex.query(function(q) { 50 | q.term(lcSearch, { boost: 100 }); 51 | q.term(lcSearch, { 52 | boost: 10, 53 | wildcard: lunr.Query.wildcard.TRAILING 54 | }); 55 | }).map(function(result) { 56 | var doc = searchData[result.ref]; 57 | doc.url = result.ref; 58 | return doc; 59 | }); 60 | sync(results); 61 | } 62 | } 63 | ); 64 | $form.removeClass('loading'); 65 | $typeahead.trigger('focus'); 66 | }); 67 | }); 68 | 69 | var baseURL = searchURL.slice(0, -"search.json".length); 70 | 71 | $typeahead.on('typeahead:select', function(e, result) { 72 | window.location = baseURL + result.url; 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // iOS Example Obj-C 4 | // 5 | 6 | #import 7 | 8 | @interface AppDelegate : UIResponder 9 | 10 | @property (strong, nonatomic) UIWindow *window; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // iOS Example Obj-C 4 | // 5 | 6 | #import "AppDelegate.h" 7 | 8 | @interface AppDelegate () 9 | 10 | @end 11 | 12 | @implementation AppDelegate 13 | 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 16 | return YES; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | NSAppTransportSecurity 38 | 39 | NSAllowsArbitraryLoads 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // iOS Example Obj-C 4 | // 5 | 6 | #import 7 | #import "PusherSwift/PusherSwift-Swift.h" 8 | 9 | @interface ViewController : UIViewController 10 | 11 | @property (nonatomic, strong, readwrite) Pusher *client; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/iOS Example Obj-C.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /iOS Example Obj-C/iOS Example Obj-C/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iOS Example Obj-C 4 | // 5 | 6 | #import 7 | #import "AppDelegate.h" 8 | 9 | int main(int argc, char * argv[]) { 10 | @autoreleasepool { 11 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /iOS Example Swift/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS Example 4 | // 5 | 6 | import UIKit 7 | 8 | @UIApplicationMain 9 | class AppDelegate: UIResponder, UIApplicationDelegate { 10 | 11 | var window: UIWindow? 12 | 13 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { 14 | 15 | return true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Carthage.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS[sdk=iphone*] = $(SRCROOT)/../Carthage/Build/iOS/ $(inherited) 2 | -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "pusher-logo-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "pusher-logo-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "idiom" : "iphone", 17 | "size" : "29x29", 18 | "scale" : "2x" 19 | }, 20 | { 21 | "idiom" : "iphone", 22 | "size" : "29x29", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "idiom" : "iphone", 27 | "size" : "40x40", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "idiom" : "iphone", 32 | "size" : "40x40", 33 | "scale" : "3x" 34 | }, 35 | { 36 | "size" : "60x60", 37 | "idiom" : "iphone", 38 | "filename" : "pusher-logo-60@2x.png", 39 | "scale" : "2x" 40 | }, 41 | { 42 | "size" : "60x60", 43 | "idiom" : "iphone", 44 | "filename" : "pusher-logo-60@3x.png", 45 | "scale" : "3x" 46 | }, 47 | { 48 | "idiom" : "ipad", 49 | "size" : "20x20", 50 | "scale" : "1x" 51 | }, 52 | { 53 | "idiom" : "ipad", 54 | "size" : "20x20", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "idiom" : "ipad", 59 | "size" : "29x29", 60 | "scale" : "1x" 61 | }, 62 | { 63 | "idiom" : "ipad", 64 | "size" : "29x29", 65 | "scale" : "2x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "40x40", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "40x40", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "idiom" : "ipad", 79 | "size" : "76x76", 80 | "scale" : "1x" 81 | }, 82 | { 83 | "idiom" : "ipad", 84 | "size" : "76x76", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "idiom" : "ipad", 89 | "size" : "83.5x83.5", 90 | "scale" : "2x" 91 | } 92 | ], 93 | "info" : { 94 | "version" : 1, 95 | "author" : "xcode" 96 | } 97 | } -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-20@2x.png -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-20@3x.png -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-60@2x.png -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pusher/pusher-websocket-swift/48e71f918754df0c7e714f35d88e62c1b125ff6e/iOS Example Swift/iOS Example Swift/Images.xcassets/AppIcon.appiconset/pusher-logo-60@3x.png -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /iOS Example Swift/iOS Example Swift/iOS Example.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------