Skip to content

Commit

Permalink
Init with request (#18)
Browse files Browse the repository at this point in the history
* Allow initializing WebSocket with a URLRequest
* Use WebSocketKit utilities and add license info
* Update dependencies
* Update README
  • Loading branch information
atdrendel authored Aug 15, 2024
1 parent 32de0d7 commit a176fc4
Show file tree
Hide file tree
Showing 12 changed files with 538 additions and 165 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ on: push

jobs:
test:
runs-on: macos-13
runs-on: macos-14

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Select Xcode 15
run: sudo xcode-select -s /Applications/Xcode_15.0.app
run: sudo xcode-select -s /Applications/Xcode_15.4.app
- name: Test
run: swift test
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2024 Shareup Software Corporation

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
41 changes: 25 additions & 16 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,62 +32,71 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "a902f1823a7ff3c9ab2fba0f992396b948eda307",
"version" : "1.0.5"
"revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d",
"version" : "1.1.2"
}
},
{
"identity" : "swift-http-types",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-http-types",
"state" : {
"revision" : "1827dc94bdab2eb5f2fc804e9b0cb43574282566",
"version" : "1.0.2"
"revision" : "ae67c8178eb46944fd85e4dc6dd970e1f3ed6ccd",
"version" : "1.3.0"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "702cd7c56d5d44eeba73fdf83918339b26dc855c",
"version" : "2.62.0"
"revision" : "4c4453b489cf76e6b3b0f300aba663eb78182fad",
"version" : "2.70.0"
}
},
{
"identity" : "swift-nio-extras",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-extras.git",
"state" : {
"revision" : "798c962495593a23fdea0c0c63fd55571d8dff51",
"version" : "1.20.0"
"revision" : "d1ead62745cc3269e482f1c51f27608057174379",
"version" : "1.24.0"
}
},
{
"identity" : "swift-nio-http2",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-http2.git",
"state" : {
"revision" : "3bd9004b9d685ed6b629760fc84903e48efec806",
"version" : "1.29.0"
"revision" : "b5f7062b60e4add1e8c343ba4eb8da2e324b3a94",
"version" : "1.34.0"
}
},
{
"identity" : "swift-nio-ssl",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-ssl.git",
"state" : {
"revision" : "320bd978cceb8e88c125dcbb774943a92f6286e9",
"version" : "2.25.0"
"revision" : "a9fa5efd86e7ce2e5c1b6de113262e58035ca251",
"version" : "2.27.1"
}
},
{
"identity" : "swift-nio-transport-services",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-transport-services.git",
"state" : {
"revision" : "ebf8b9c365a6ce043bf6e6326a04b15589bd285e",
"version" : "1.20.0"
"revision" : "38ac8221dd20674682148d6451367f89c2652980",
"version" : "1.21.0"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "d2ba781702a1d8285419c15ee62fd734a9437ff5",
"version" : "1.3.2"
}
},
{
Expand All @@ -104,8 +113,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/vapor/websocket-kit.git",
"state" : {
"revision" : "53fe0639a98903858d0196b699720decb42aee7b",
"version" : "2.14.0"
"revision" : "4232d34efa49f633ba61afde365d3896fc7f8740",
"version" : "2.15.0"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let package = Package(
),
.package(
url: "https://github.com/vapor/websocket-kit.git",
from: "2.14.0"
from: "2.15.0"
),
.package(
url: "https://github.com/apple/swift-nio.git",
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

## _(macOS, iOS, iPadOS, tvOS, and watchOS)_

A concrete implementation of a WebSocket client implemented by wrapping Apple's [`NWConnection`](https://developer.apple.com/documentation/network/nwconnection).
A concrete implementation of a WebSocket client implemented by wrapping Apple's [`URLSessionWebSocketTask`](https://developer.apple.com/documentation/foundation/urlsessionwebsockettask).

The public interface of `WebSocket` is a simple struct whose public methods are exposed as closures. The reason for this design is to make it easy to inject fake WebSockets into your code for testing purposes.

The actual implementation is `SystemWebSocket`, but this type is not publicly accessible. Instead, you can access it via `WebSocket.system(url:)`. `SystemWebSocket` tries its best to mirror the documented behavior of web browsers' [`WebSocket`](http://developer.mozilla.org/en-US/docs/Web/API/WebSocket). Please report any deviations as bugs.
The actual implementation is `SystemWebSocket`, but this type is not publicly accessible. Instead, you can access it via `WebSocket.system(url:)` or `WebSocket.system(request:)`. `SystemWebSocket` tries its best to mirror the documented behavior of web browsers' [`WebSocket`](http://developer.mozilla.org/en-US/docs/Web/API/WebSocket). Please report any deviations as bugs.

`WebSocket` exposes a simple API and makes heavy use of [Swift Concurrency](https://developer.apple.com/documentation/swift/swift_standard_library/concurrency).

Expand Down Expand Up @@ -49,3 +49,7 @@ try await socket.close()

1. In your Terminal, navigate to the `websocket-apple` directory
2. Run the tests using `swift test`

## Notices

This library includes code from [WebSocketKit](https://github.com/vapor/websocket-kit) and [SwiftNIO](https://github.com/apple/swift-nio), the use of which depends on their licenses.
4 changes: 2 additions & 2 deletions Sources/WebSocket/SystemURLSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import Foundation
import Synchronized

func webSocketTask(
for url: URL,
for request: URLRequest,
options: WebSocketOptions,
onOpen: @escaping @Sendable () async -> Void,
onClose: @escaping @Sendable (WebSocketCloseCode, Data?) async -> Void
) -> URLSessionWebSocketTask {
let session = session(for: options)

let task = session.webSocketTask(with: url)
let task = session.webSocketTask(with: request)
task.maximumMessageSize = options.maximumMessageSize

let delegate = session.delegate as! Delegate
Expand Down
9 changes: 5 additions & 4 deletions Sources/WebSocket/SystemWebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ final actor SystemWebSocket: Publisher {
return true
} }

nonisolated let url: URL
nonisolated var url: URL { request.url! }
nonisolated let request: URLRequest
nonisolated let options: WebSocketOptions
nonisolated let onOpen: WebSocketOnOpen
nonisolated let onClose: WebSocketOnClose
Expand All @@ -49,12 +50,12 @@ final actor SystemWebSocket: Publisher {
)

init(
url: URL,
request: URLRequest,
options: WebSocketOptions = .init(),
onOpen: @escaping WebSocketOnOpen = {},
onClose: @escaping WebSocketOnClose = { _ in }
) async throws {
self.url = url
self.request = request
self.options = options
self.onOpen = onOpen
self.onClose = onClose
Expand Down Expand Up @@ -180,7 +181,7 @@ private extension SystemWebSocket {
func connect() throws {
precondition(isUnopened)
let task = webSocketTask(
for: url,
for: request,
options: options,
onOpen: { [weak self] in await self?.doOpen() },
onClose: { [weak self] closeCode, reason async in
Expand Down
17 changes: 16 additions & 1 deletion Sources/WebSocket/WebSocket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,24 @@ public extension WebSocket {
options: WebSocketOptions = .init(),
onOpen: @escaping WebSocketOnOpen = {},
onClose: @escaping WebSocketOnClose = { _ in }
) async throws -> Self {
try await system(
request: URLRequest(url: url),
options: options,
onOpen: onOpen,
onClose: onClose
)
}

/// System WebSocket implementation powered by `URLSessionWebSocketTask`.
static func system(
request: URLRequest,
options: WebSocketOptions = .init(),
onOpen: @escaping WebSocketOnOpen = {},
onClose: @escaping WebSocketOnClose = { _ in }
) async throws -> Self {
let ws = try await SystemWebSocket(
url: url,
request: request,
options: options,
onOpen: onOpen,
onClose: onClose
Expand Down
Loading

0 comments on commit a176fc4

Please sign in to comment.