From fedd77ba8e85ce0c73a5631917af6b3872e85578 Mon Sep 17 00:00:00 2001 From: moogle Date: Thu, 14 May 2020 15:56:57 +0200 Subject: [PATCH 01/36] Stop reading when error is encountered --- Sources/Engine/NativeEngine.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/Engine/NativeEngine.swift b/Sources/Engine/NativeEngine.swift index 7294e364..1bd5b6a8 100644 --- a/Sources/Engine/NativeEngine.swift +++ b/Sources/Engine/NativeEngine.swift @@ -72,6 +72,7 @@ public class NativeEngine: NSObject, Engine, URLSessionDataDelegate, URLSessionW break case .failure(let error): self?.broadcast(event: .error(error)) + return } self?.doRead() } From 263b9419bba704264b3615a8fcc946510c64b871 Mon Sep 17 00:00:00 2001 From: Andrew Mayers Date: Mon, 22 Jun 2020 17:23:47 -0400 Subject: [PATCH 02/36] Fix compile error on Xcode 12 Now you can build on both Xcode 11.5 & 12.0 b1. On 12, the unit tests would fail to compile because it wasn't finding the `Starscream` framework. So I added `Starscream` as a dependency of the test target. In `FoundationHTTPServerHandler` the `method` is of type `CFString`, while `getVerb` is `NSString`. Looks like Xcode 12 doesn't like equality comparison between those types without a cast as `NSString`. --- .../Framer/FoundationHTTPServerHandler.swift | 2 +- Starscream.xcodeproj/project.pbxproj | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Sources/Framer/FoundationHTTPServerHandler.swift b/Sources/Framer/FoundationHTTPServerHandler.swift index 7783ed62..62283b1b 100644 --- a/Sources/Framer/FoundationHTTPServerHandler.swift +++ b/Sources/Framer/FoundationHTTPServerHandler.swift @@ -74,7 +74,7 @@ public class FoundationHTTPServerHandler: HTTPServerHandler { return false //not enough data, wait for more } if let method = CFHTTPMessageCopyRequestMethod(response)?.takeRetainedValue() { - if method != getVerb { + if (method as NSString) != getVerb { delegate?.didReceive(event: .failure(HTTPUpgradeError.invalidData)) return true } diff --git a/Starscream.xcodeproj/project.pbxproj b/Starscream.xcodeproj/project.pbxproj index ec1a293e..1ddd55f1 100644 --- a/Starscream.xcodeproj/project.pbxproj +++ b/Starscream.xcodeproj/project.pbxproj @@ -38,6 +38,16 @@ BBB5ABE8215E2217005B48B6 /* WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = BBB5ABE4215E2217005B48B6 /* WebSocket.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 6B0BE7AA24A157BB0051F7A7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6B3E79DD19D48B7F006071F7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CCF0841F5DDC030099B092; + remoteInfo = Starscream; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ 335FA2021F5DF71D00F6D2EC /* Starscream Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Starscream Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CCF0921F5DDC030099B092 /* Starscream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Starscream.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -250,6 +260,7 @@ buildRules = ( ); dependencies = ( + 6B0BE7AB24A157BB0051F7A7 /* PBXTargetDependency */, ); name = "Starscream Tests"; productName = StarscreamTests; @@ -372,6 +383,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 6B0BE7AB24A157BB0051F7A7 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CCF0841F5DDC030099B092 /* Starscream */; + targetProxy = 6B0BE7AA24A157BB0051F7A7 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 335FA2001F5DF71D00F6D2EC /* Debug */ = { isa = XCBuildConfiguration; From fe5769f2ae5a7473261ef3c3f3ecc76f1218c601 Mon Sep 17 00:00:00 2001 From: Mykola Varahash Date: Mon, 13 Jul 2020 01:16:45 +0300 Subject: [PATCH 03/36] Conditionally include 'swift-nio-zlib-support' dependency to avoid warning on macOS --- Package.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 9b78501f..f45b4cbd 100644 --- a/Package.swift +++ b/Package.swift @@ -27,11 +27,13 @@ let package = Package( products: [ .library(name: "Starscream", targets: ["Starscream"]) ], - dependencies: [ - .package(url: "https://github.com/apple/swift-nio-zlib-support.git", from: "1.0.0") - ], + dependencies: [], targets: [ .target(name: "Starscream", path: "Sources") ] ) + +#if os(Linux) + package.dependencies.append(.package(url: "https://github.com/apple/swift-nio-zlib-support.git", from: "1.0.0")) +#endif From 5987db1605c41453008c2b148f21be059611ccbc Mon Sep 17 00:00:00 2001 From: Daniel Shelley Date: Thu, 16 Jul 2020 16:50:35 -0600 Subject: [PATCH 04/36] move deployment target to iOS 9 to fix compile for archive with Xcode 12 --- Starscream.xcodeproj/project.pbxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Starscream.xcodeproj/project.pbxproj b/Starscream.xcodeproj/project.pbxproj index ec1a293e..4813c6e0 100644 --- a/Starscream.xcodeproj/project.pbxproj +++ b/Starscream.xcodeproj/project.pbxproj @@ -298,8 +298,8 @@ developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, + Base, ); mainGroup = 6B3E79DC19D48B7F006071F7; productRefGroup = 6B3E79E719D48B7F006071F7 /* Products */; @@ -428,7 +428,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 4.0.3; @@ -456,7 +456,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; MARKETING_VERSION = 4.0.3; @@ -521,7 +521,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos"; @@ -574,7 +574,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos"; SWIFT_VERSION = 5.0; From df8d82047f6654d8e4b655d1b1525c64e1059d21 Mon Sep 17 00:00:00 2001 From: daltoniam Date: Sat, 1 Aug 2020 15:04:10 -0500 Subject: [PATCH 05/36] 4.0.4 release --- CHANGELOG.md | 15 +++++++++++++++ Starscream.podspec | 2 +- Starscream.xcodeproj/project.pbxproj | 4 ++-- .../UserInterfaceState.xcuserstate | Bin 134228 -> 135108 bytes 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6488ce11..1819fbb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. `Starscream` adheres to [Semantic Versioning](http://semver.org/). +### [4.0.4](https://github.com/daltoniam/Starscream/tree/4.0.4) + +Bug fixes for 4.0.3. + +[#808](https://github.com/daltoniam/Starscream/pull/808) +[#807](https://github.com/daltoniam/Starscream/pull/807) +[#799](https://github.com/daltoniam/Starscream/pull/799) +[#797](https://github.com/daltoniam/Starscream/pull/797) +[#790](https://github.com/daltoniam/Starscream/pull/790) +[#788](https://github.com/daltoniam/Starscream/pull/788) +[#777](https://github.com/daltoniam/Starscream/pull/777) +[#768](https://github.com/daltoniam/Starscream/pull/768) +[#766](https://github.com/daltoniam/Starscream/pull/766) +[#764](https://github.com/daltoniam/Starscream/pull/764) + ### [4.0.3](https://github.com/daltoniam/Starscream/tree/4.0.3) Bug fixes for 4.0.2. diff --git a/Starscream.podspec b/Starscream.podspec index c657d261..e470d01f 100644 --- a/Starscream.podspec +++ b/Starscream.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Starscream" - s.version = "4.0.3" + s.version = "4.0.4" s.summary = "A conforming WebSocket RFC 6455 client library in Swift." s.homepage = "https://github.com/daltoniam/Starscream" s.license = 'Apache License, Version 2.0' diff --git a/Starscream.xcodeproj/project.pbxproj b/Starscream.xcodeproj/project.pbxproj index 23dc0c9d..4379a960 100644 --- a/Starscream.xcodeproj/project.pbxproj +++ b/Starscream.xcodeproj/project.pbxproj @@ -450,7 +450,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; - MARKETING_VERSION = 4.0.3; + MARKETING_VERSION = 4.0.4; OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -478,7 +478,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; - MARKETING_VERSION = 4.0.3; + MARKETING_VERSION = 4.0.4; OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate b/examples/SimpleTest/SimpleTest.xcodeproj/project.xcworkspace/xcuserdata/dalton.xcuserdatad/UserInterfaceState.xcuserstate index 68722bd444aef811ca42eb1c3a93a21520a09ac4..6b47527a7e2c41a04d2f1c8c9dd3748086a159a3 100644 GIT binary patch literal 135108 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 O{_kJ^|9=m+O#Xia;9120 literal 134228 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
#9D&E&`)=G95nKv@YxPX)MQt(WLE=eZFa3 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 From e95db8ff2984884288f8b2e8232766c02e93082d Mon Sep 17 00:00:00 2001 From: Jonathan Downing Date: Tue, 28 Jul 2020 13:59:30 -0700 Subject: [PATCH 06/36] Tweak WebSocketDelegate method signature --- Sources/Starscream/WebSocket.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Starscream/WebSocket.swift b/Sources/Starscream/WebSocket.swift index 1d3545c3..2b666310 100644 --- a/Sources/Starscream/WebSocket.swift +++ b/Sources/Starscream/WebSocket.swift @@ -88,7 +88,7 @@ public enum WebSocketEvent { } public protocol WebSocketDelegate: class { - func didReceive(event: WebSocketEvent, client: WebSocket) + func didReceive(event: WebSocketEvent, client: WebSocketClient) } open class WebSocket: WebSocketClient, EngineDelegate { From a55720bd9a0577d9289261ae4406a51768e5b668 Mon Sep 17 00:00:00 2001 From: Minhyuk Kim Date: Sat, 22 Aug 2020 23:43:24 +0900 Subject: [PATCH 07/36] Add .pong to be counted as control frame. --- Sources/Framer/Framer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Framer/Framer.swift b/Sources/Framer/Framer.swift index f77d5b80..9e7cf5c7 100644 --- a/Sources/Framer/Framer.swift +++ b/Sources/Framer/Framer.swift @@ -159,7 +159,7 @@ public class WSFramer: Framer { let errCode = CloseCode.protocolError.rawValue return .failed(WSError(type: .protocolError, message: "masked and rsv data is not currently supported", code: errCode)) } - let isControlFrame = (opcode == .connectionClose || opcode == .ping) + let isControlFrame = (opcode == .connectionClose || opcode == .ping || opcode == .pong) if !isControlFrame && (opcode != .binaryFrame && opcode != .continueFrame && opcode != .textFrame && opcode != .pong) { let errCode = CloseCode.protocolError.rawValue From 4ae4531e7a578420b76c7b1bc25ada1220226dd8 Mon Sep 17 00:00:00 2001 From: Minhyuk Kim Date: Sat, 12 Sep 2020 22:25:43 +0900 Subject: [PATCH 08/36] Add Issue templates and PR templates. --- .github/ISSUE_TEMPLATE/bug_report.md | 25 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 1 + .github/ISSUE_TEMPLATE/feature_request.md | 23 ++++++++++++++++++++ .github/ISSUE_TEMPLATE/general-question.md | 16 ++++++++++++++ .github/pull_request_template.md | 8 +++++++ 5 files changed, 73 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/general-question.md create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..415c8be0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,25 @@ +--- +name: Bug report +about: Create a report about a bug +title: '' +labels: bug +assignees: '' + +--- + +### Describe the bug +> A clear and concise description of what the bug is. + +### Steps to Reproduce +> Detailed steps to reproduce the problematic behavior: + +### Expected behavior +> A clear and concise description of what you expected to happen. + +### Environment: +- OS/Version: [e.g. iOS/13.3] +- Starscream Version [e.g. 4.0.4] +- Xcode version [e.g. 11.5] + +### Additional context +> Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..da239762 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,23 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: feature_request +assignees: '' + +--- + +### What do you want to happen? +> Please replace this with the general overview of the feature that you'd like to have. + +### What happens now? +> Please replace this with of what is happening currently. + +### Demo Code +> Any demo code that may used to implement/use the desired feature. + +### Describe alternatives you've considered +> A clear and concise description of any alternative solutions or features you've considered. + +### Additional context +> Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/general-question.md b/.github/ISSUE_TEMPLATE/general-question.md new file mode 100644 index 00000000..e8e9e095 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/general-question.md @@ -0,0 +1,16 @@ +--- +name: General Question +about: 'Ask any question about the framework. ' +title: '' +labels: question +assignees: '' + +--- + +### Question +> A description of what you want to know. + +### Environment: +- OS/Version: [e.g. iOS/13.3] +- Starscream Version [e.g. 4.0.4] +- Xcode version [e.g. 11.5] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..30122cb9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,8 @@ +### Issue Link 🔗 +> Please attach the link to an issue if it exists. + +### Goals ⚽ +> What you hope to address within this PR. + +### Implementation Details 🚧 +> Additional details about the PR. From e73800e668a42051a1c8e48b8df9b2f3091a469d Mon Sep 17 00:00:00 2001 From: Joey Date: Wed, 21 Oct 2020 17:40:28 +0800 Subject: [PATCH 09/36] Remove three unused properties --- Sources/Starscream/WebSocket.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Sources/Starscream/WebSocket.swift b/Sources/Starscream/WebSocket.swift index 1d3545c3..b6d48884 100644 --- a/Sources/Starscream/WebSocket.swift +++ b/Sources/Starscream/WebSocket.swift @@ -110,11 +110,6 @@ open class WebSocket: WebSocketClient, EngineDelegate { } } - // serial write queue to ensure writes happen in order - private let writeQueue = DispatchQueue(label: "com.vluxe.starscream.writequeue") - private var canSend = false - private let mutex = DispatchSemaphore(value: 1) - public init(request: URLRequest, engine: Engine) { self.request = request self.engine = engine From cebca639eeb6b2898af82f37e4a7ad27c01415f3 Mon Sep 17 00:00:00 2001 From: Matthaus Woolard Date: Tue, 26 Jan 2021 09:24:30 +1300 Subject: [PATCH 10/36] Add Headers to `notAnUpgrade` error. --- Sources/Framer/FoundationHTTPHandler.swift | 13 +++++++------ Sources/Framer/HTTPHandler.swift | 2 +- Sources/Framer/StringHTTPHandler.swift | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Sources/Framer/FoundationHTTPHandler.swift b/Sources/Framer/FoundationHTTPHandler.swift index fb024aaa..805a548a 100644 --- a/Sources/Framer/FoundationHTTPHandler.swift +++ b/Sources/Framer/FoundationHTTPHandler.swift @@ -76,12 +76,6 @@ public class FoundationHTTPHandler: HTTPHandler { return false //not enough data, wait for more } - let code = CFHTTPMessageGetResponseStatusCode(response) - if code != HTTPWSHeader.switchProtocolCode { - delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code))) - return true - } - if let cfHeaders = CFHTTPMessageCopyAllHeaderFields(response) { let nsHeaders = cfHeaders.takeRetainedValue() as NSDictionary var headers = [String: String]() @@ -90,6 +84,13 @@ public class FoundationHTTPHandler: HTTPHandler { headers[key] = value } } + + let code = CFHTTPMessageGetResponseStatusCode(response) + if code != HTTPWSHeader.switchProtocolCode { + delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code, headers))) + return true + } + delegate?.didReceiveHTTP(event: .success(headers)) return true } diff --git a/Sources/Framer/HTTPHandler.swift b/Sources/Framer/HTTPHandler.swift index 70941e75..d7ebc5a8 100644 --- a/Sources/Framer/HTTPHandler.swift +++ b/Sources/Framer/HTTPHandler.swift @@ -23,7 +23,7 @@ import Foundation public enum HTTPUpgradeError: Error { - case notAnUpgrade(Int) + case notAnUpgrade(Int, [String: String]) case invalidData } diff --git a/Sources/Framer/StringHTTPHandler.swift b/Sources/Framer/StringHTTPHandler.swift index 33f5f9be..ed8e32d5 100644 --- a/Sources/Framer/StringHTTPHandler.swift +++ b/Sources/Framer/StringHTTPHandler.swift @@ -110,7 +110,7 @@ public class StringHTTPHandler: HTTPHandler { } if code != HTTPWSHeader.switchProtocolCode { - delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code))) + delegate?.didReceiveHTTP(event: .failure(HTTPUpgradeError.notAnUpgrade(code, headers))) return true } From b7f15e63c3e74313096f80c2ab35a6eaa419cbbb Mon Sep 17 00:00:00 2001 From: Jonas Schmid Date: Sat, 29 May 2021 03:08:37 +0200 Subject: [PATCH 11/36] Fixed documentation on compression (#883) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 634723aa..1e742311 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ TODO: Update docs on how to load certificates and public keys into an app bundle ### Compression Extensions -Compression Extensions ([RFC 7692](https://tools.ietf.org/html/rfc7692)) is supported in Starscream. Compression is enabled by default, however compression will only be used if it is supported by the server as well. You may enable or disable compression via the `.enableCompression` property: +Compression Extensions ([RFC 7692](https://tools.ietf.org/html/rfc7692)) is supported in Starscream. Compression is enabled by default, however compression will only be used if it is supported by the server as well. You may enable compression by adding a `compressionHandler`: ```swift var request = URLRequest(url: URL(string: "ws://localhost:8080/")!) From a0ba26b7de9591eaed0f1796d575a411074021a8 Mon Sep 17 00:00:00 2001 From: Eric Rowe <31042085+eric-clover@users.noreply.github.com> Date: Fri, 28 May 2021 19:08:53 -0600 Subject: [PATCH 12/36] Explicitly set domain to the passed value (#890) --- Sources/Security/FoundationSecurity.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/Security/FoundationSecurity.swift b/Sources/Security/FoundationSecurity.swift index c4dde8ce..a9a9505a 100644 --- a/Sources/Security/FoundationSecurity.swift +++ b/Sources/Security/FoundationSecurity.swift @@ -44,9 +44,7 @@ extension FoundationSecurity: CertificatePinning { return } - if let validateDomain = domain { - SecTrustSetPolicies(trust, SecPolicyCreateSSL(true, validateDomain as NSString?)) - } + SecTrustSetPolicies(trust, SecPolicyCreateSSL(true, domain as NSString?)) handleSecurityTrust(trust: trust, completion: completion) } From 2c476c7582f59a80963d83a73a604ca708ef5aa9 Mon Sep 17 00:00:00 2001 From: Emad Ghorbaninia Date: Tue, 8 Jun 2021 10:52:05 +0200 Subject: [PATCH 13/36] Replace all the class with AnyObject due to the deprication. --- Sources/Engine/Engine.swift | 2 +- Sources/Framer/FrameCollector.swift | 2 +- Sources/Framer/Framer.swift | 2 +- Sources/Framer/HTTPHandler.swift | 4 ++-- Sources/Security/Security.swift | 4 ++-- Sources/Server/Server.swift | 2 +- Sources/Starscream/WebSocket.swift | 4 ++-- Sources/Transport/Transport.swift | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Sources/Engine/Engine.swift b/Sources/Engine/Engine.swift index a60ef7e8..71a4d06a 100644 --- a/Sources/Engine/Engine.swift +++ b/Sources/Engine/Engine.swift @@ -8,7 +8,7 @@ import Foundation -public protocol EngineDelegate: class { +public protocol EngineDelegate: AnyObject { func didReceive(event: WebSocketEvent) } diff --git a/Sources/Framer/FrameCollector.swift b/Sources/Framer/FrameCollector.swift index 3ec1084c..1822b0d6 100644 --- a/Sources/Framer/FrameCollector.swift +++ b/Sources/Framer/FrameCollector.swift @@ -22,7 +22,7 @@ import Foundation -public protocol FrameCollectorDelegate: class { +public protocol FrameCollectorDelegate: AnyObject { func didForm(event: FrameCollector.Event) func decompress(data: Data, isFinal: Bool) -> Data? } diff --git a/Sources/Framer/Framer.swift b/Sources/Framer/Framer.swift index 9e7cf5c7..049e4e17 100644 --- a/Sources/Framer/Framer.swift +++ b/Sources/Framer/Framer.swift @@ -71,7 +71,7 @@ public enum FrameEvent { case error(Error) } -public protocol FramerEventClient: class { +public protocol FramerEventClient: AnyObject { func frameProcessed(event: FrameEvent) } diff --git a/Sources/Framer/HTTPHandler.swift b/Sources/Framer/HTTPHandler.swift index d7ebc5a8..bddf04b7 100644 --- a/Sources/Framer/HTTPHandler.swift +++ b/Sources/Framer/HTTPHandler.swift @@ -94,7 +94,7 @@ public enum HTTPEvent { case failure(Error) } -public protocol HTTPHandlerDelegate: class { +public protocol HTTPHandlerDelegate: AnyObject { func didReceiveHTTP(event: HTTPEvent) } @@ -104,7 +104,7 @@ public protocol HTTPHandler { func parse(data: Data) -> Int } -public protocol HTTPServerDelegate: class { +public protocol HTTPServerDelegate: AnyObject { func didReceive(event: HTTPEvent) } diff --git a/Sources/Security/Security.swift b/Sources/Security/Security.swift index a64a7713..d83a6bda 100644 --- a/Sources/Security/Security.swift +++ b/Sources/Security/Security.swift @@ -34,12 +34,12 @@ public enum PinningState { // CertificatePinning protocol provides an interface for Transports to handle Certificate // or Public Key Pinning. -public protocol CertificatePinning: class { +public protocol CertificatePinning: AnyObject { func evaluateTrust(trust: SecTrust, domain: String?, completion: ((PinningState) -> ())) } // validates the "Sec-WebSocket-Accept" header as defined 1.3 of the RFC 6455 // https://tools.ietf.org/html/rfc6455#section-1.3 -public protocol HeaderValidator: class { +public protocol HeaderValidator: AnyObject { func validate(headers: [String: String], key: String) -> Error? } diff --git a/Sources/Server/Server.swift b/Sources/Server/Server.swift index 527c851d..64cf561d 100644 --- a/Sources/Server/Server.swift +++ b/Sources/Server/Server.swift @@ -36,7 +36,7 @@ public protocol Connection { func write(data: Data, opcode: FrameOpCode) } -public protocol ConnectionDelegate: class { +public protocol ConnectionDelegate: AnyObject { func didReceive(event: ServerEvent) } diff --git a/Sources/Starscream/WebSocket.swift b/Sources/Starscream/WebSocket.swift index f09df584..f3597294 100644 --- a/Sources/Starscream/WebSocket.swift +++ b/Sources/Starscream/WebSocket.swift @@ -41,7 +41,7 @@ public struct WSError: Error { } } -public protocol WebSocketClient: class { +public protocol WebSocketClient: AnyObject { func connect() func disconnect(closeCode: UInt16) func write(string: String, completion: (() -> ())?) @@ -87,7 +87,7 @@ public enum WebSocketEvent { case cancelled } -public protocol WebSocketDelegate: class { +public protocol WebSocketDelegate: AnyObject { func didReceive(event: WebSocketEvent, client: WebSocketClient) } diff --git a/Sources/Transport/Transport.swift b/Sources/Transport/Transport.swift index e645651f..e0e74085 100644 --- a/Sources/Transport/Transport.swift +++ b/Sources/Transport/Transport.swift @@ -42,11 +42,11 @@ public enum ConnectionState { case receive(Data) } -public protocol TransportEventClient: class { +public protocol TransportEventClient: AnyObject { func connectionChanged(state: ConnectionState) } -public protocol Transport: class { +public protocol Transport: AnyObject { func register(delegate: TransportEventClient) func connect(url: URL, timeout: Double, certificatePinning: CertificatePinning?) func disconnect() From f3548815504647b22375c1e9448a439b2a4b178d Mon Sep 17 00:00:00 2001 From: NachoSoto Date: Wed, 16 Aug 2023 15:18:19 -0700 Subject: [PATCH 14/36] Added support for `xrOS` (#973) --- Starscream.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Starscream.xcodeproj/project.pbxproj b/Starscream.xcodeproj/project.pbxproj index 4379a960..b35ead4a 100644 --- a/Starscream.xcodeproj/project.pbxproj +++ b/Starscream.xcodeproj/project.pbxproj @@ -543,10 +543,10 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos xros xrsimulator"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TARGETED_DEVICE_FAMILY = "1,2,3,4,7"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -595,9 +595,9 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 9.0; MTL_ENABLE_DEBUG_INFO = NO; - SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos xros xrsimulator"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3,4"; + TARGETED_DEVICE_FAMILY = "1,2,3,4,7"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; From 060600f3434b5ec1d7e3a835e21bae798b9f4149 Mon Sep 17 00:00:00 2001 From: Ste Prescott Date: Wed, 16 Aug 2023 23:19:18 +0100 Subject: [PATCH 15/36] Conditionally include 'swift-nio-zlib-support' dependency to avoid warning on macOS (#964) Co-authored-by: Mykola Varahash From 5ab0d5a5416fe63d74b6eb906cb39c213ceeeb06 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:19:37 -0500 Subject: [PATCH 16/36] Bump addressable from 2.7.0 to 2.8.1 (#963) Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.1. - [Release notes](https://github.com/sporkmonger/addressable/releases) - [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md) - [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.1) --- updated-dependencies: - dependency-name: addressable dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 989fe592..589e80ad 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,8 +7,8 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.1) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) From 3c5a48404933905e382c5e3f49bd435b838ef402 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:19:45 -0500 Subject: [PATCH 17/36] Bump tzinfo from 1.2.6 to 1.2.10 (#955) Bumps [tzinfo](https://github.com/tzinfo/tzinfo) from 1.2.6 to 1.2.10. - [Release notes](https://github.com/tzinfo/tzinfo/releases) - [Changelog](https://github.com/tzinfo/tzinfo/blob/master/CHANGES.md) - [Commits](https://github.com/tzinfo/tzinfo/compare/v1.2.6...v1.2.10) --- updated-dependencies: - dependency-name: tzinfo dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 589e80ad..f89b7c82 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -187,7 +187,7 @@ GEM tty-screen (0.7.0) tty-spinner (0.9.2) tty-cursor (~> 0.7) - tzinfo (1.2.6) + tzinfo (1.2.10) thread_safe (~> 0.1) uber (0.1.0) unf (0.1.4) From cb131f8ea33a27461b09894c843c2a2dcdde56f9 Mon Sep 17 00:00:00 2001 From: Hugin Date: Thu, 17 Aug 2023 06:20:26 +0800 Subject: [PATCH 18/36] Update README.md (#950) Modify the version reference to prevent user copy errors --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1e742311..43f0ee84 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ To use Starscream in your project add the following 'Podfile' to your project platform :ios, '9.0' use_frameworks! - pod 'Starscream', '~> 4.0.0' + pod 'Starscream', '~> 4.0.4' Then run: @@ -227,7 +227,7 @@ $ brew install carthage To integrate Starscream into your Xcode project using Carthage, specify it in your `Cartfile`: ``` -github "daltoniam/Starscream" >= 4.0.0 +github "daltoniam/Starscream" >= 4.0.4 ``` ### Accio @@ -237,7 +237,7 @@ Check out the [Accio](https://github.com/JamitLabs/Accio) docs on how to add a i Add the following to your Package.swift: ```swift -.package(url: "https://github.com/daltoniam/Starscream.git", .upToNextMajor(from: "4.0.0")), +.package(url: "https://github.com/daltoniam/Starscream.git", .upToNextMajor(from: "4.0.4")), ``` Next, add `Starscream` to your App targets dependencies like so: From f900d67759cdd11df3dcca34af21f40f59fe4e79 Mon Sep 17 00:00:00 2001 From: Jenea Vranceanu <36865532+JeneaVranceanu@users.noreply.github.com> Date: Thu, 17 Aug 2023 01:21:37 +0300 Subject: [PATCH 19/36] fix: added peerClosed case for WebSocketEvent enum (#946) --- Sources/Engine/WSEngine.swift | 2 ++ Sources/Server/WebSocketServer.swift | 2 ++ Sources/Starscream/WebSocket.swift | 1 + Sources/Transport/TCPTransport.swift | 7 +++++++ Sources/Transport/Transport.swift | 20 +++++++++++++++----- Tests/FuzzingTests.swift | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Sources/Engine/WSEngine.swift b/Sources/Engine/WSEngine.swift index decca641..4ae5e44f 100644 --- a/Sources/Engine/WSEngine.swift +++ b/Sources/Engine/WSEngine.swift @@ -140,6 +140,8 @@ FrameCollectorDelegate, HTTPHandlerDelegate { } case .cancelled: broadcast(event: .cancelled) + case .peerClosed: + broadcast(event: .peerClosed) } } diff --git a/Sources/Server/WebSocketServer.swift b/Sources/Server/WebSocketServer.swift index 4d3b9af5..78657806 100644 --- a/Sources/Server/WebSocketServer.swift +++ b/Sources/Server/WebSocketServer.swift @@ -138,6 +138,8 @@ public class ServerConnection: Connection, HTTPServerDelegate, FramerEventClient case .cancelled: print("server connection cancelled!") //broadcast(event: .cancelled) + case .peerClosed: + delegate?.didReceive(event: .disconnected(self, "Connection closed by peer", UInt16(FrameOpCode.connectionClose.rawValue))) } } diff --git a/Sources/Starscream/WebSocket.swift b/Sources/Starscream/WebSocket.swift index f3597294..2f529a5c 100644 --- a/Sources/Starscream/WebSocket.swift +++ b/Sources/Starscream/WebSocket.swift @@ -85,6 +85,7 @@ public enum WebSocketEvent { case viabilityChanged(Bool) case reconnectSuggested(Bool) case cancelled + case peerClosed } public protocol WebSocketDelegate: AnyObject { diff --git a/Sources/Transport/TCPTransport.swift b/Sources/Transport/TCPTransport.swift index 459cb2ed..3f0a1757 100644 --- a/Sources/Transport/TCPTransport.swift +++ b/Sources/Transport/TCPTransport.swift @@ -144,6 +144,13 @@ public class TCPTransport: Transport { // Refer to https://developer.apple.com/documentation/network/implementing_netcat_with_network_framework if let context = context, context.isFinal, isComplete { + if let delegate = s.delegate { + // Let the owner of this TCPTransport decide what to do next: disconnect or reconnect? + delegate.connectionChanged(state: .peerClosed) + } else { + // No use to keep connection alive + s.disconnect() + } return } diff --git a/Sources/Transport/Transport.swift b/Sources/Transport/Transport.swift index e0e74085..f954b484 100644 --- a/Sources/Transport/Transport.swift +++ b/Sources/Transport/Transport.swift @@ -25,21 +25,31 @@ import Foundation public enum ConnectionState { + /// Ready connections can send and receive data case connected + + /// Waiting connections have not yet been started, or do not have a viable network case waiting + + /// Cancelled connections have been invalidated by the client and will send no more events case cancelled + + /// Failed connections are disconnected and can no longer send or receive data case failed(Error?) - //the viability (connection status) of the connection has updated - //e.g. connection is down, connection came back up, etc + /// Viability (connection status) of the connection has updated + /// e.g. connection is down, connection came back up, etc. case viability(Bool) - //the connection has upgrade to wifi from cellular. - //you should consider reconnecting to take advantage of this + /// Connection ca be upgraded to wifi from cellular. + /// You should consider reconnecting to take advantage of this. case shouldReconnect(Bool) - //the connection receive data + /// Received data case receive(Data) + + /// Remote peer has closed the network connection. + case peerClosed } public protocol TransportEventClient: AnyObject { diff --git a/Tests/FuzzingTests.swift b/Tests/FuzzingTests.swift index a6c94451..23db35a0 100644 --- a/Tests/FuzzingTests.swift +++ b/Tests/FuzzingTests.swift @@ -66,6 +66,8 @@ class FuzzingTests: XCTestCase { break case .cancelled: break + case .peerClosed: + break } } websocket.connect() From cdb61a3624d8af3f5520f0dac20d23f3f434275e Mon Sep 17 00:00:00 2001 From: newloran2 Date: Wed, 16 Aug 2023 19:22:28 -0300 Subject: [PATCH 20/36] Fix for start websocket with cookies in initial request (#942) --- Sources/Framer/HTTPHandler.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Sources/Framer/HTTPHandler.swift b/Sources/Framer/HTTPHandler.swift index bddf04b7..488dd030 100644 --- a/Sources/Framer/HTTPHandler.swift +++ b/Sources/Framer/HTTPHandler.swift @@ -67,12 +67,14 @@ public struct HTTPWSHeader { req.setValue(HTTPWSHeader.versionValue, forHTTPHeaderField: HTTPWSHeader.versionName) req.setValue(secKeyValue, forHTTPHeaderField: HTTPWSHeader.keyName) - if let cookies = HTTPCookieStorage.shared.cookies(for: url), !cookies.isEmpty { - let headers = HTTPCookie.requestHeaderFields(with: cookies) - for (key, val) in headers { - req.setValue(val, forHTTPHeaderField: key) + if req.allHTTPHeaderFields?["Cookie"] == nil { + if let cookies = HTTPCookieStorage.shared.cookies(for: url), !cookies.isEmpty { + let headers = HTTPCookie.requestHeaderFields(with: cookies) + for (key, val) in headers { + req.setValue(val, forHTTPHeaderField: key) + } } - } + } if supportsCompression { let val = "permessage-deflate; client_max_window_bits; server_max_window_bits=15" From 826008daab578d9f182d6de9d61bee3944208658 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:24:08 -0500 Subject: [PATCH 21/36] Bump cocoapods-downloader from 1.3.0 to 1.6.3 (#948) Bumps [cocoapods-downloader](https://github.com/CocoaPods/cocoapods-downloader) from 1.3.0 to 1.6.3. - [Release notes](https://github.com/CocoaPods/cocoapods-downloader/releases) - [Changelog](https://github.com/CocoaPods/cocoapods-downloader/blob/master/CHANGELOG.md) - [Commits](https://github.com/CocoaPods/cocoapods-downloader/compare/1.3.0...1.6.3) --- updated-dependencies: - dependency-name: cocoapods-downloader dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index f89b7c82..182eff8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,7 +41,7 @@ GEM fuzzy_match (~> 2.0.4) nap (~> 1.0) cocoapods-deintegrate (1.0.4) - cocoapods-downloader (1.3.0) + cocoapods-downloader (1.6.3) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.0) From 04acf17f4cf55d24bdc920cc6950d5e80be60f1b Mon Sep 17 00:00:00 2001 From: Mustapha Qadri <43132553+MustaphaQadri@users.noreply.github.com> Date: Thu, 17 Aug 2023 00:25:49 +0200 Subject: [PATCH 22/36] Added support for connection error (#912) --- Sources/Engine/NativeEngine.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Engine/NativeEngine.swift b/Sources/Engine/NativeEngine.swift index 1bd5b6a8..63455091 100644 --- a/Sources/Engine/NativeEngine.swift +++ b/Sources/Engine/NativeEngine.swift @@ -94,4 +94,8 @@ public class NativeEngine: NSObject, Engine, URLSessionDataDelegate, URLSessionW } broadcast(event: .disconnected(r, UInt16(closeCode.rawValue))) } + + public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + broadcast(event: .error(error)) + } } From 66a441a9174fdd72b6d5353627701d7b1dc367d4 Mon Sep 17 00:00:00 2001 From: Muhammad Adil Date: Thu, 17 Aug 2023 03:29:37 +0500 Subject: [PATCH 23/36] rfc6455 link fixed (#952) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43f0ee84..fac1963e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![starscream](https://raw.githubusercontent.com/daltoniam/starscream/assets/starscream.jpg) -Starscream is a conforming WebSocket ([RFC 6455](http://tools.ietf.org/html/rfc6455)) library in Swift. +Starscream is a conforming WebSocket ([RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455)) library in Swift. ## Features From ea9a6ff27e32134e816ac522fae4d4d76e67e88a Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 13:03:25 -0500 Subject: [PATCH 24/36] feat: cleanup, update for latest xcode/swift, add release workflow --- .github/workflows/release.yml | 23 ++ .travis.yml | 7 - Gemfile.lock | 291 +++++++++++------- LICENSE | 2 +- Package.resolved | 16 - Sources/Engine/Engine.swift | 16 +- Sources/Engine/NativeEngine.swift | 16 +- Sources/Engine/WSEngine.swift | 16 +- Sources/Starscream.h | 18 +- Sources/Transport/Transport.swift | 2 - Starscream.podspec | 6 +- Starscream.xcodeproj/project.pbxproj | 81 +++-- .../xcschemes/Starscream.xcscheme | 28 +- Tests/FuzzingTests.swift | 14 + Tests/MockServer.swift | 14 + Tests/MockTransport.swift | 16 +- Tests/StarscreamTests/StarscreamTests.swift | 16 +- build.sh | 6 - .../Autobahn.xcodeproj/project.pbxproj | 52 +++- examples/AutobahnTest/Autobahn/Info.plist | 2 +- .../SimpleTest/ViewController.swift | 17 +- fastlane/Fastfile | 23 +- fastlane/README.md | 38 ++- release.sh | 4 - 24 files changed, 484 insertions(+), 240 deletions(-) create mode 100644 .github/workflows/release.yml delete mode 100644 .travis.yml delete mode 100644 Package.resolved delete mode 100755 build.sh delete mode 100755 release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..5c5f0dae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,23 @@ +name: Release + +on: + push: + tags: + - "*.*.*" +jobs: + release: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v3 + - name: Set Latest Tag + id: vars + run: echo "tag=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_OUTPUT + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - run: bundle exec fastlane test + - run: bundle exec fastlane release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.vars.outputs.tag }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8bd0dce0..00000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -osx_image: xcode11.3 -language: objective-c -before_install: - - gem install cocoapods --pre - - gem cleanup -script: -- ./build.sh diff --git a/Gemfile.lock b/Gemfile.lock index 182eff8e..efcccf01 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,106 +1,151 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.2) - activesupport (4.2.11.1) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.8.1) + CFPropertyList (3.0.6) + rexml + activesupport (7.0.7) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) - algoliasearch (1.27.1) + algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) + artifactory (3.0.15) atomos (0.1.3) - babosa (1.0.3) - claide (1.0.3) - cocoapods (1.8.4) - activesupport (>= 4.0.2, < 5) + aws-eventstream (1.2.0) + aws-partitions (1.807.0) + aws-sdk-core (3.180.3) + aws-eventstream (~> 1, >= 1.0.2) + aws-partitions (~> 1, >= 1.651.0) + aws-sigv4 (~> 1.5) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.71.0) + aws-sdk-core (~> 3, >= 3.177.0) + aws-sigv4 (~> 1.1) + aws-sdk-s3 (1.132.1) + aws-sdk-core (~> 3, >= 3.179.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.6) + aws-sigv4 (1.6.0) + aws-eventstream (~> 1, >= 1.0.2) + babosa (1.0.4) + claide (1.1.0) + cocoapods (1.12.1) + addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.8.4) + cocoapods-core (= 1.12.1) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.2.2, < 2.0) + cocoapods-downloader (>= 1.6.0, < 2.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-stats (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) cocoapods-try (>= 1.1.0, < 2.0) colored2 (~> 3.1) escape (~> 0.0.4) fourflusher (>= 2.3.0, < 3.0) gh_inspector (~> 1.0) - molinillo (~> 0.6.6) + molinillo (~> 0.8.0) nap (~> 1.0) - ruby-macho (~> 1.4) - xcodeproj (>= 1.11.1, < 2.0) - cocoapods-core (1.8.4) - activesupport (>= 4.0.2, < 6) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-core (1.12.1) + activesupport (>= 5.0, < 8) + addressable (~> 2.8) algoliasearch (~> 1.0) concurrent-ruby (~> 1.1) fuzzy_match (~> 2.0.4) nap (~> 1.0) - cocoapods-deintegrate (1.0.4) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) cocoapods-downloader (1.6.3) cocoapods-plugins (1.0.0) nap - cocoapods-search (1.0.0) - cocoapods-stats (1.1.0) - cocoapods-trunk (1.4.1) + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) nap (>= 0.8, < 2.0) netrc (~> 0.11) - cocoapods-try (1.1.0) + cocoapods-try (1.2.0) colored (1.2) colored2 (3.1.2) - commander-fastlane (4.4.6) - highline (~> 1.7.2) - concurrent-ruby (1.1.5) - declarative (0.0.10) - declarative-option (0.1.0) - digest-crc (0.4.1) + commander (4.6.0) + highline (~> 2.0.0) + concurrent-ruby (1.2.2) + declarative (0.0.20) + digest-crc (0.6.5) + rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.5) - emoji_regex (1.0.1) + dotenv (2.8.1) + emoji_regex (3.2.3) escape (0.0.4) - excon (0.71.1) - faraday (0.17.3) - multipart-post (>= 1.2, < 3) - faraday-cookie_jar (0.0.6) - faraday (>= 0.7.4) + ethon (0.16.0) + ffi (>= 1.15.0) + excon (0.100.0) + faraday (1.10.3) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) + faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) + faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.0) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) + ruby2_keywords (>= 0.0.4) + faraday-cookie_jar (0.0.7) + faraday (>= 0.8.0) http-cookie (~> 1.0.0) - faraday_middleware (0.13.1) - faraday (>= 0.7.4, < 1.0) - fastimage (2.1.7) - fastlane (2.139.0) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) + faraday-excon (1.1.0) + faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) + faraday-net_http (1.0.1) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) + faraday (~> 1.0) + fastimage (2.2.7) + fastlane (2.214.0) CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) - babosa (>= 1.0.2, < 2.0.0) + addressable (>= 2.8, < 3.0.0) + artifactory (~> 3.0) + aws-sdk-s3 (~> 1.0) + babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) colored - commander-fastlane (>= 4.4.6, < 5.0.0) + commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) - emoji_regex (>= 0.1, < 2.0) + emoji_regex (>= 0.1, < 4.0) excon (>= 0.71.0, < 1.0.0) - faraday (~> 0.17) + faraday (~> 1.0) faraday-cookie_jar (~> 0.0.6) - faraday_middleware (~> 0.13.1) + faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) - google-api-client (>= 0.29.2, < 0.37.0) - google-cloud-storage (>= 1.15.0, < 2.0.0) - highline (>= 1.7.2, < 2.0.0) + google-apis-androidpublisher_v3 (~> 0.3) + google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-storage (~> 1.31) + highline (~> 2.0) json (< 3.0.0) - jwt (~> 2.1.0) + jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) - multi_xml (~> 0.5) - multipart-post (~> 2.0.0) + multipart-post (>= 2.0.0, < 3.0.0) + naturally (~> 2.2) + optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) - public_suffix (~> 2.0.0) - rubyzip (>= 1.3.0, < 2.0.0) + rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) simctl (~> 1.6.3) - slack-notifier (>= 2.0.0, < 3.0.0) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (>= 1.4.5, < 2.0.0) tty-screen (>= 0.6.3, < 1.0.0) @@ -109,109 +154,129 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) + ffi (1.15.5) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-api-client (0.36.3) + google-apis-androidpublisher_v3 (0.48.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 0.9) - httpclient (>= 2.8.1, < 3.0) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) representable (~> 3.0) - retriable (>= 2.0, < 4.0) - signet (~> 0.12) - google-cloud-core (1.4.1) + retriable (>= 2.0, < 4.a) + rexml + webrick + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.19.0) + google-apis-core (>= 0.9.0, < 2.a) + google-cloud-core (1.6.0) google-cloud-env (~> 1.0) - google-cloud-env (1.3.0) - faraday (~> 0.11) - google-cloud-storage (1.25.0) - addressable (~> 2.5) + google-cloud-errors (~> 1.0) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.3.1) + google-cloud-storage (1.44.0) + addressable (~> 2.8) digest-crc (~> 0.4) - google-api-client (~> 0.33) - google-cloud-core (~> 1.2) - googleauth (~> 0.9) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.19.0) + google-cloud-core (~> 1.6) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.10.0) - faraday (~> 0.12) + googleauth (1.7.0) + faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.12) - highline (1.7.10) - http-cookie (1.0.3) + signet (>= 0.16, < 2.a) + highline (2.0.3) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (0.9.5) + i18n (1.14.1) concurrent-ruby (~> 1.0) - json (2.3.0) - jwt (2.1.0) + jmespath (1.6.2) + json (2.6.3) + jwt (2.7.1) memoist (0.16.2) - mini_magick (4.9.5) - mini_mime (1.0.2) - minitest (5.13.0) - molinillo (0.6.6) - multi_json (1.14.1) - multi_xml (0.6.0) - multipart-post (2.0.0) - nanaimo (0.2.6) + mini_magick (4.12.0) + mini_mime (1.1.5) + minitest (5.19.0) + molinillo (0.8.0) + multi_json (1.15.0) + multipart-post (2.3.0) + nanaimo (0.3.0) nap (1.1.0) - naturally (2.2.0) + naturally (2.2.1) netrc (0.11.0) - os (1.0.1) - plist (3.5.0) - public_suffix (2.0.5) - representable (3.0.4) + optparse (0.1.1) + os (1.1.4) + plist (3.7.0) + public_suffix (4.0.7) + rake (13.0.6) + representable (3.2.0) declarative (< 0.1.0) - declarative-option (< 0.2.0) + trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) + rexml (3.2.6) rouge (2.0.7) - ruby-macho (1.4.0) - rubyzip (1.3.0) + ruby-macho (2.5.1) + ruby2_keywords (0.0.5) + rubyzip (2.3.2) security (0.1.3) - signet (0.12.0) - addressable (~> 2.3) - faraday (~> 0.9) + signet (0.17.0) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) - simctl (1.6.7) + simctl (1.6.10) CFPropertyList naturally - slack-notifier (2.3.2) terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) - tty-cursor (0.7.0) - tty-screen (0.7.0) - tty-spinner (0.9.2) + trailblazer-option (0.1.2) + tty-cursor (0.7.1) + tty-screen (0.8.1) + tty-spinner (0.9.3) tty-cursor (~> 0.7) - tzinfo (1.2.10) - thread_safe (~> 0.1) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.6) - unicode-display_width (1.6.0) + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) + webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.14.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.2.6) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) xcpretty (0.3.0) rouge (~> 2.0.7) - xcpretty-travis-formatter (1.0.0) + xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) PLATFORMS - ruby + arm64-darwin-22 DEPENDENCIES cocoapods fastlane BUNDLED WITH - 2.1.3 + 2.4.10 diff --git a/LICENSE b/LICENSE index d6ab2f1f..663de542 100644 --- a/LICENSE +++ b/LICENSE @@ -2,7 +2,7 @@ Version 2.0, January 2004 http://www.apache.org/licenses/ - Copyright (c) 2014-2016 Dalton Cherry. + Copyright (c) 2014-2023 Dalton Cherry. TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index e49c8be4..00000000 --- a/Package.resolved +++ /dev/null @@ -1,16 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "swift-nio-zlib-support", - "repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git", - "state": { - "branch": null, - "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", - "version": "1.0.0" - } - } - ] - }, - "version": 1 -} diff --git a/Sources/Engine/Engine.swift b/Sources/Engine/Engine.swift index 71a4d06a..79fe6bfe 100644 --- a/Sources/Engine/Engine.swift +++ b/Sources/Engine/Engine.swift @@ -1,10 +1,24 @@ +////////////////////////////////////////////////////////////////////////////////////////////////// // // Engine.swift // Starscream // -// Created by Dalton Cherry on 6/15/19. +// Created by Dalton Cherry on 6/15/19 // Copyright © 2019 Vluxe. All rights reserved. // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +////////////////////////////////////////////////////////////////////////////////////////////////// import Foundation diff --git a/Sources/Engine/NativeEngine.swift b/Sources/Engine/NativeEngine.swift index 63455091..a1cb4a45 100644 --- a/Sources/Engine/NativeEngine.swift +++ b/Sources/Engine/NativeEngine.swift @@ -1,10 +1,24 @@ +////////////////////////////////////////////////////////////////////////////////////////////////// // // NativeEngine.swift // Starscream // -// Created by Dalton Cherry on 6/15/19. +// Created by Dalton Cherry on 6/15/19 // Copyright © 2019 Vluxe. All rights reserved. // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +////////////////////////////////////////////////////////////////////////////////////////////////// import Foundation diff --git a/Sources/Engine/WSEngine.swift b/Sources/Engine/WSEngine.swift index 4ae5e44f..4dcaea32 100644 --- a/Sources/Engine/WSEngine.swift +++ b/Sources/Engine/WSEngine.swift @@ -1,10 +1,24 @@ +////////////////////////////////////////////////////////////////////////////////////////////////// // // WSEngine.swift // Starscream // -// Created by Dalton Cherry on 6/15/19. +// Created by Dalton Cherry on 6/15/19 // Copyright © 2019 Vluxe. All rights reserved. // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +////////////////////////////////////////////////////////////////////////////////////////////////// import Foundation diff --git a/Sources/Starscream.h b/Sources/Starscream.h index 38ff9dfb..c2a6f605 100644 --- a/Sources/Starscream.h +++ b/Sources/Starscream.h @@ -1,10 +1,24 @@ +////////////////////////////////////////////////////////////////////////////////////////////////// // // Starscream.h // Starscream // // Created by Austin Cherry on 9/25/14. -// Copyright (c) 2014 Vluxe. All rights reserved. +// Copyright © 2014 Vluxe. All rights reserved. // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +////////////////////////////////////////////////////////////////////////////////////////////////// #import @@ -15,5 +29,3 @@ FOUNDATION_EXPORT double StarscreamVersionNumber; FOUNDATION_EXPORT const unsigned char StarscreamVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Sources/Transport/Transport.swift b/Sources/Transport/Transport.swift index f954b484..8a101a4a 100644 --- a/Sources/Transport/Transport.swift +++ b/Sources/Transport/Transport.swift @@ -1,7 +1,5 @@ ////////////////////////////////////////////////////////////////////////////////////////////////// // -////////////////////////////////////////////////////////////////////////////////////////////////// -// // Transport.swift // Starscream // diff --git a/Starscream.podspec b/Starscream.podspec index e470d01f..4b31cb45 100644 --- a/Starscream.podspec +++ b/Starscream.podspec @@ -7,9 +7,9 @@ Pod::Spec.new do |s| s.author = {'Dalton Cherry' => 'http://daltoniam.com', 'Austin Cherry' => 'http://austincherry.me'} s.source = { :git => 'https://github.com/daltoniam/Starscream.git', :tag => "#{s.version}"} s.social_media_url = 'http://twitter.com/daltoniam' - s.ios.deployment_target = '8.0' - s.osx.deployment_target = '10.10' - s.tvos.deployment_target = '9.0' + s.ios.deployment_target = '11.0' + s.osx.deployment_target = '10.13' + s.tvos.deployment_target = '12.0' s.watchos.deployment_target = '2.0' s.source_files = 'Sources/**/*.swift' s.swift_version = '5.0' diff --git a/Starscream.xcodeproj/project.pbxproj b/Starscream.xcodeproj/project.pbxproj index b35ead4a..99b3f6ed 100644 --- a/Starscream.xcodeproj/project.pbxproj +++ b/Starscream.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ @@ -291,9 +291,10 @@ 6B3E79DD19D48B7F006071F7 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = Vluxe; TargetAttributes = { 335FA1F41F5DF71D00F6D2EC = { @@ -398,13 +399,24 @@ APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = "$(SRCROOT)/Tests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx"; @@ -422,15 +434,27 @@ APPLICATION_EXTENSION_API_ONLY = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "-"; + DEAD_CODE_STRIPPING = YES; INFOPLIST_FILE = "$(SRCROOT)/Tests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + "@executable_path/../Frameworks", + "@loader_path/../Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvos appletvsimulator macosx"; SUPPORTS_MACCATALYST = YES; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 5.0; }; @@ -441,16 +465,24 @@ buildSettings = { BITCODE_GENERATION_MODE = marker; CLANG_ENABLE_MODULES = YES; + DEAD_CODE_STRIPPING = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MARKETING_VERSION = 4.0.4; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -459,7 +491,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 9.0; + TVOS_DEPLOYMENT_TARGET = 12.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Debug; @@ -469,25 +501,34 @@ buildSettings = { BITCODE_GENERATION_MODE = bitcode; CLANG_ENABLE_MODULES = YES; + DEAD_CODE_STRIPPING = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; MARKETING_VERSION = 4.0.4; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11"; OTHER_LDFLAGS = "-all_load"; PRODUCT_BUNDLE_IDENTIFIER = "com.vluxe.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 9.0; + TVOS_DEPLOYMENT_TARGET = 12.0; WATCHOS_DEPLOYMENT_TARGET = 2.0; }; name = Release; @@ -516,6 +557,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -523,6 +565,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -540,7 +583,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos xros xrsimulator"; @@ -576,6 +619,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -583,6 +627,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -593,7 +638,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx appletvos appletvsimulator watchsimulator watchos xros xrsimulator"; SWIFT_VERSION = 5.0; diff --git a/Starscream.xcodeproj/xcshareddata/xcschemes/Starscream.xcscheme b/Starscream.xcodeproj/xcshareddata/xcschemes/Starscream.xcscheme index f50707a5..ec7854e1 100644 --- a/Starscream.xcodeproj/xcshareddata/xcschemes/Starscream.xcscheme +++ b/Starscream.xcodeproj/xcshareddata/xcschemes/Starscream.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + @@ -44,17 +53,6 @@ - - - - - - - - CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.vluxe.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/examples/SimpleTest/SimpleTest/ViewController.swift b/examples/SimpleTest/SimpleTest/ViewController.swift index 6a6a4a36..26aaf99d 100644 --- a/examples/SimpleTest/SimpleTest/ViewController.swift +++ b/examples/SimpleTest/SimpleTest/ViewController.swift @@ -30,19 +30,6 @@ class ViewController: UIViewController, WebSocketDelegate { override func viewDidLoad() { super.viewDidLoad() -// let err = server.start(address: "localhost", port: 8080) -// if err != nil { -// print("server didn't start!") -// } -// server.onEvent = { event in -// switch event { -// case .text(let conn, let string): -// let payload = string.data(using: .utf8)! -// conn.write(data: payload, opcode: .textFrame) -// default: -// break -// } -// } //https://echo.websocket.org var request = URLRequest(url: URL(string: "http://localhost:8080")!) //https://localhost:8080 request.timeoutInterval = 5 @@ -52,7 +39,7 @@ class ViewController: UIViewController, WebSocketDelegate { } // MARK: - WebSocketDelegate - func didReceive(event: WebSocketEvent, client: WebSocket) { + func didReceive(event: Starscream.WebSocketEvent, client: Starscream.WebSocketClient) { switch event { case .connected(let headers): isConnected = true @@ -77,6 +64,8 @@ class ViewController: UIViewController, WebSocketDelegate { case .error(let error): isConnected = false handleError(error) + case .peerClosed: + break } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 069321f9..764ef4ff 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -2,27 +2,28 @@ default_platform(:ios) update_fastlane + +desc "Run tests" +lane :test do + run_tests( + devices: ["iPhone 14 Pro", "iPad Pro (11-inch) (4th generation)"], + ) +end + platform :ios do desc "Deploy new version" lane :release do - ensure_git_branch - version = version_get_podspec(path: "Starscream.podspec") - changelog = prompt(text: "Changelog: ", multi_line_end_keyword: "END") - - github_token = ENV['GITHUB_TOKEN'] - if !github_token || github_token.empty? - github_token = prompt(text: "Please enter your GitHub token: ") - end + version = version_bump_podspec(path: "Starscream.podspec", version_number: ENV['TAG']) + changelog = changelog_from_git_commits(merge_commit_filtering: "exclude_merges") github_release = set_github_release( repository_name: "daltoniam/Starscream", - api_token: github_token, + api_token: ENV['GITHUB_TOKEN'], name: version, tag_name: version, description: changelog, commitish: "master" ) - sh("git fetch --tags") - pod_push(allow_warnings: true, verbose: true) + pod_push(allow_warnings: false, verbose: true) end end diff --git a/fastlane/README.md b/fastlane/README.md index 58c0dc75..1ccfc536 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -1,29 +1,43 @@ fastlane documentation -================ +---- + # Installation Make sure you have the latest version of the Xcode command line tools installed: -``` +```sh xcode-select --install ``` -Install _fastlane_ using -``` -[sudo] gem install fastlane -NV -``` -or alternatively using `brew cask install fastlane` +For _fastlane_ installation instructions, see [Installing _fastlane_](https://docs.fastlane.tools/#installing-fastlane) # Available Actions + +### test + +```sh +[bundle exec] fastlane test +``` + +Run tests + +---- + + ## iOS + ### ios release + +```sh +[bundle exec] fastlane ios release ``` -fastlane ios release -``` + Deploy new version ---- -This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. -More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). -The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). +This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. + +More information about _fastlane_ can be found on [fastlane.tools](https://fastlane.tools). + +The documentation of _fastlane_ can be found on [docs.fastlane.tools](https://docs.fastlane.tools). diff --git a/release.sh b/release.sh deleted file mode 100755 index 7e244db9..00000000 --- a/release.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -bundle install -bundle exec fastlane release From 76fa39ec307637cff0b319330b85236ce5892483 Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 13:09:12 -0500 Subject: [PATCH 25/36] chore: add ruby version --- .ruby-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..acf9bf09 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.2.2 \ No newline at end of file From dcfffe11144e6d61f6200545d075ba50e9effc3d Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 13:13:57 -0500 Subject: [PATCH 26/36] chore: change ruby version --- .ruby-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index acf9bf09..a4f52a5d 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.2 \ No newline at end of file +3.2.0 \ No newline at end of file From f8ac424b8e6d05e3ac5e88c4ee3277cdfdc93f8a Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 13:16:38 -0500 Subject: [PATCH 27/36] chore: update bundler --- .ruby-version | 2 +- Gemfile.lock | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.ruby-version b/.ruby-version index a4f52a5d..acf9bf09 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.0 \ No newline at end of file +3.2.2 \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index efcccf01..4e5ecd60 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -273,6 +273,7 @@ GEM PLATFORMS arm64-darwin-22 + x86_64-darwin-20 DEPENDENCIES cocoapods From 4c7b8817a1ceca4ec52c06f45d3972d6b3a08cfa Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 15:24:17 -0500 Subject: [PATCH 28/36] fix: release workflow --- .github/workflows/release.yml | 3 ++- fastlane/Fastfile | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5c5f0dae..d3f80552 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,5 +19,6 @@ jobs: - run: bundle exec fastlane test - run: bundle exec fastlane release env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.PAT_GITHUB_TOKEN }} + COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} TAG: ${{ steps.vars.outputs.tag }} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 764ef4ff..df1cdf77 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -13,12 +13,12 @@ end platform :ios do desc "Deploy new version" lane :release do - version = version_bump_podspec(path: "Starscream.podspec", version_number: ENV['TAG']) + version = version_bump_podspec(path: "Starscream.podspec", version_number: ENV["TAG"]) changelog = changelog_from_git_commits(merge_commit_filtering: "exclude_merges") github_release = set_github_release( - repository_name: "daltoniam/Starscream", - api_token: ENV['GITHUB_TOKEN'], + repository_name: "daltoniam/starscream", + api_token: ENV["GITHUB_TOKEN"], name: version, tag_name: version, description: changelog, From 7b1e5bb60d9f1ce9fa0c732df54c5f7f74f35645 Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 15:30:29 -0500 Subject: [PATCH 29/36] fix: update secret --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d3f80552..12850429 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,6 +19,6 @@ jobs: - run: bundle exec fastlane test - run: bundle exec fastlane release env: - GITHUB_TOKEN: ${{ secrets.PAT_GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} TAG: ${{ steps.vars.outputs.tag }} From d2a9549ea45018ef6802e3fe3c61490386a0ee8c Mon Sep 17 00:00:00 2001 From: paul-verkada <85518497+paul-verkada@users.noreply.github.com> Date: Sat, 19 Aug 2023 14:09:19 -0700 Subject: [PATCH 30/36] Fix a leak with the TCPTransport (#923) Co-authored-by: Andreas Binnewies --- Sources/Transport/TCPTransport.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sources/Transport/TCPTransport.swift b/Sources/Transport/TCPTransport.swift index 3f0a1757..27e951c0 100644 --- a/Sources/Transport/TCPTransport.swift +++ b/Sources/Transport/TCPTransport.swift @@ -35,7 +35,11 @@ public class TCPTransport: Transport { private weak var delegate: TransportEventClient? private var isRunning = false private var isTLS = false - + + deinit { + disconnect() + } + public var usingTLS: Bool { return self.isTLS } @@ -85,6 +89,7 @@ public class TCPTransport: Transport { public func disconnect() { isRunning = false connection?.cancel() + connection = nil } public func register(delegate: TransportEventClient) { From d67812c56103f32710b02be25b3aa3029c5f4920 Mon Sep 17 00:00:00 2001 From: Zac West <74188+zacwest@users.noreply.github.com> Date: Sat, 19 Aug 2023 14:09:52 -0700 Subject: [PATCH 31/36] Fix compression when headers don't include window bits (#937) --- Sources/Compression/WSCompression.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sources/Compression/WSCompression.swift b/Sources/Compression/WSCompression.swift index 21295841..82f96740 100644 --- a/Sources/Compression/WSCompression.swift +++ b/Sources/Compression/WSCompression.swift @@ -44,6 +44,10 @@ public class WSCompression: CompressionHandler { guard let extensionHeader = headers[headerWSExtensionName] else { return } decompressorTakeOver = false compressorTakeOver = false + + // assume defaults unless the headers say otherwise + compressor = Compressor(windowBits: 15) + decompressor = Decompressor(windowBits: 15) let parts = extensionHeader.components(separatedBy: ";") for p in parts { @@ -204,6 +208,11 @@ class Compressor { } func compress(_ data: Data) throws -> Data { + guard !data.isEmpty else { + // For example, PONG has no content + return data + } + var compressed = Data() var res: CInt = 0 data.withUnsafeBytes { (ptr:UnsafePointer) -> Void in From 86998dd144c1215fd326210a541d86621a68dade Mon Sep 17 00:00:00 2001 From: yohei yoshimuta Date: Sun, 20 Aug 2023 06:11:05 +0900 Subject: [PATCH 32/36] Fix connection race when using WSEngine (#930) --- Sources/Engine/WSEngine.swift | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sources/Engine/WSEngine.swift b/Sources/Engine/WSEngine.swift index 4dcaea32..4add12a7 100644 --- a/Sources/Engine/WSEngine.swift +++ b/Sources/Engine/WSEngine.swift @@ -38,6 +38,7 @@ FrameCollectorDelegate, HTTPHandlerDelegate { private let writeQueue = DispatchQueue(label: "com.vluxe.starscream.writequeue") private let mutex = DispatchSemaphore(value: 1) private var canSend = false + private var isConnecting = false weak var delegate: EngineDelegate? public var respondToPingWithPong: Bool = true @@ -64,9 +65,10 @@ FrameCollectorDelegate, HTTPHandlerDelegate { public func start(request: URLRequest) { mutex.wait() + let isConnecting = self.isConnecting let isConnected = canSend mutex.signal() - if isConnected { + if isConnecting || isConnected { return } @@ -78,6 +80,9 @@ FrameCollectorDelegate, HTTPHandlerDelegate { guard let url = request.url else { return } + mutex.wait() + self.isConnecting = true + mutex.signal() transport.connect(url: url, timeout: request.timeoutInterval, certificatePinning: certPinner) } @@ -93,6 +98,10 @@ FrameCollectorDelegate, HTTPHandlerDelegate { } public func forceStop() { + mutex.wait() + isConnecting = false + mutex.signal() + transport.disconnect() } @@ -153,6 +162,10 @@ FrameCollectorDelegate, HTTPHandlerDelegate { } } case .cancelled: + mutex.wait() + isConnecting = false + mutex.signal() + broadcast(event: .cancelled) case .peerClosed: broadcast(event: .peerClosed) @@ -169,6 +182,7 @@ FrameCollectorDelegate, HTTPHandlerDelegate { return } mutex.wait() + isConnecting = false didUpgrade = true canSend = true mutex.signal() @@ -241,6 +255,7 @@ FrameCollectorDelegate, HTTPHandlerDelegate { private func reset() { mutex.wait() + isConnecting = false canSend = false didUpgrade = false mutex.signal() From ca9b1225b7afcc578265e59f972f135ae3d94166 Mon Sep 17 00:00:00 2001 From: Mikhail Akopov Date: Sun, 20 Aug 2023 00:12:23 +0300 Subject: [PATCH 33/36] Update SwiftPM section in Readme (#824) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fac1963e..3c38633f 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ Once you have your Swift package set up, adding Starscream as a dependency is as ```swift dependencies: [ - .Package(url: "https://github.com/daltoniam/Starscream.git", majorVersion: 4) + .package(url: "https://github.com/daltoniam/Starscream.git", from: "4.0.0") ] ``` From ac6c0fc9da221873e01bd1a0d4818498a71eef33 Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Sat, 19 Aug 2023 16:19:25 -0500 Subject: [PATCH 34/36] fix: update README --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3c38633f..77eb91b0 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,8 @@ func didReceive(event: WebSocketEvent, client: WebSocket) { case .error(let error): isConnected = false handleError(error) + case .peerClosed: + break } } ``` @@ -202,10 +204,10 @@ Check out [Get Started](http://cocoapods.org/) tab on [cocoapods.org](http://coc To use Starscream in your project add the following 'Podfile' to your project source 'https://github.com/CocoaPods/Specs.git' - platform :ios, '9.0' + platform :ios, '11.0' use_frameworks! - pod 'Starscream', '~> 4.0.4' + pod 'Starscream', '~> 4.0.6' Then run: @@ -227,7 +229,7 @@ $ brew install carthage To integrate Starscream into your Xcode project using Carthage, specify it in your `Cartfile`: ``` -github "daltoniam/Starscream" >= 4.0.4 +github "daltoniam/Starscream" >= 4.0.6 ``` ### Accio @@ -237,7 +239,7 @@ Check out the [Accio](https://github.com/JamitLabs/Accio) docs on how to add a i Add the following to your Package.swift: ```swift -.package(url: "https://github.com/daltoniam/Starscream.git", .upToNextMajor(from: "4.0.4")), +.package(url: "https://github.com/daltoniam/Starscream.git", .upToNextMajor(from: "4.0.6")), ``` Next, add `Starscream` to your App targets dependencies like so: @@ -290,6 +292,9 @@ If you are running this in an OSX app or on a physical iOS device you will need ## TODOs - [ ] Proxy support +- [ ] Thread safe implementation +- [ ] Better testing/CI +- [ ] SSL Pinning/client auth examples ## License From 7723d1ec4ff32812759ead958fa61ad6ef406de8 Mon Sep 17 00:00:00 2001 From: Austin Cherry Date: Tue, 22 Aug 2023 16:32:08 -0500 Subject: [PATCH 35/36] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 77eb91b0..bf71f14f 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ func didReceive(event: WebSocketEvent, client: WebSocket) { case .error(let error): isConnected = false handleError(error) - case .peerClosed: - break + case .peerClosed: + break } } ``` From d3a0b107328e3bc1601dccbfbcd556bd53aed767 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:08:38 -0500 Subject: [PATCH 36/36] Bump activesupport from 7.0.7 to 7.0.7.2 (#976) Bumps [activesupport](https://github.com/rails/rails) from 7.0.7 to 7.0.7.2. - [Release notes](https://github.com/rails/rails/releases) - [Changelog](https://github.com/rails/rails/blob/v7.0.7.2/activesupport/CHANGELOG.md) - [Commits](https://github.com/rails/rails/compare/v7.0.7...v7.0.7.2) --- updated-dependencies: - dependency-name: activesupport dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4e5ecd60..6f447ec4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.7) + activesupport (7.0.7.2) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -274,6 +274,7 @@ GEM PLATFORMS arm64-darwin-22 x86_64-darwin-20 + x86_64-linux DEPENDENCIES cocoapods