Skip to content

Commit

Permalink
Merge pull request #78 from swhitty/swift-5.10
Browse files Browse the repository at this point in the history
Swift 5.10
  • Loading branch information
swhitty committed Mar 9, 2024
2 parents 6677f51 + 142ba00 commit 5c60e1c
Show file tree
Hide file tree
Showing 44 changed files with 370 additions and 183 deletions.
45 changes: 29 additions & 16 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ on:
workflow_dispatch:

jobs:
xcode_14_3_1:
runs-on: macos-13
xcode_15_2:
runs-on: macos-14
env:
DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
Expand All @@ -22,17 +22,17 @@ jobs:
- name: Gather code coverage
run: xcrun llvm-cov export -format="lcov" .build/debug/FlyingFoxPackageTests.xctest/Contents/MacOS/FlyingFoxPackageTests -instr-profile .build/debug/codecov/default.profdata > coverage_report.lcov
- name: Upload Coverage
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
files: ./coverage_report.lcov

xcode_15_1:
xcode_14_3_1:
runs-on: macos-13
env:
DEVELOPER_DIR: /Applications/Xcode_15.1.app/Contents/Developer
DEVELOPER_DIR: /Applications/Xcode_14.3.1.app/Contents/Developer
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
Expand All @@ -46,20 +46,33 @@ jobs:
DEVELOPER_DIR: /Applications/Xcode_14.2.app/Contents/Developer
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
run: swift build --build-tests
- name: Test
run: swift test --skip-build

linux_swift_5_7:
linux_swift_5_10:
runs-on: ubuntu-latest
container: swift:5.7
container: swift:5.10
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
run: swift build --build-tests
- name: Test
run: swift test --skip-build

linux_swift_5_9:
runs-on: ubuntu-latest
container: swift:5.9
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
Expand All @@ -72,20 +85,20 @@ jobs:
container: swift:5.8
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
run: swift build --build-tests
- name: Test
run: swift test --skip-build

linux_swift_5_9:
linux_swift_5_7:
runs-on: ubuntu-latest
container: swift:5.9
container: swift:5.7
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Version
run: swift --version
- name: Build
Expand Down
10 changes: 5 additions & 5 deletions FlyingFox/Sources/HTTPConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ struct HTTPConnection: Sendable {

let hostname: String
private let socket: AsyncSocket
private let logger: Logging?
private let logger: any Logging
let requests: HTTPRequestSequence<AsyncSocketReadSequence>

init(socket: AsyncSocket, logger: Logging?) {
init(socket: AsyncSocket, logger: some Logging) {
self.socket = socket
self.logger = logger
self.hostname = HTTPConnection.makeIdentifer(from: socket.socket)
Expand All @@ -65,11 +65,11 @@ struct HTTPConnection: Sendable {
}
}

func switchToWebSocket(with handler: WSHandler, response: Data) async throws {
func switchToWebSocket(with handler: some WSHandler, response: Data) async throws {
let client = AsyncThrowingStream.decodingFrames(from: socket.bytes)
let server = try await handler.makeFrames(for: client)
try await socket.write(response)
logger?.logSwitchProtocol(self, to: "websocket")
logger.logSwitchProtocol(self, to: "websocket")
await requests.complete()
for await frame in server {
try await socket.write(WSFrameEncoder.encodeFrame(frame))
Expand Down Expand Up @@ -97,7 +97,7 @@ actor HTTPRequestSequence<S: AsyncChunkedSequence & Sendable>: AsyncSequence, As
private let bytes: S

private var isComplete: Bool
private var task: Task<Element, Error>?
private var task: Task<Element, any Error>?

init(bytes: S) {
self.bytes = bytes
Expand Down
2 changes: 1 addition & 1 deletion FlyingFox/Sources/HTTPHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public extension HTTPHandler where Self == ClosureHTTPHandler {
}

public extension HTTPHandler where Self == WebSocketHTTPHandler {
static func webSocket(_ handler: WSMessageHandler, frameSize: Int = 16384) -> WebSocketHTTPHandler {
static func webSocket(_ handler: some WSMessageHandler, frameSize: Int = 16384) -> WebSocketHTTPHandler {
WebSocketHTTPHandler(handler: MessageFrameWSHandler(handler: handler, frameSize: frameSize))
}
}
4 changes: 2 additions & 2 deletions FlyingFox/Sources/HTTPLogging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ public extension Logging where Self == PrintLogger {

extension HTTPServer {

public static func defaultLogger(category: String = "FlyingFox") -> Logging {
public static func defaultLogger(category: String = "FlyingFox") -> any Logging {
defaultLogger(category: category, forceFallback: false)
}

static func defaultLogger(category: String = "FlyingFox", forceFallback: Bool) -> Logging {
static func defaultLogger(category: String = "FlyingFox", forceFallback: Bool) -> any Logging {
guard !forceFallback, #available(macOS 11.0, iOS 14.0, tvOS 14.0, *) else {
return .print(category: category)
}
Expand Down
4 changes: 2 additions & 2 deletions FlyingFox/Sources/HTTPResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public struct HTTPResponse: Sendable {

public enum Payload: @unchecked Sendable {
case httpBody(HTTPBodySequence)
case webSocket(WSHandler)
case webSocket(any WSHandler)

@available(*, unavailable, renamed: "httpBody")
static func body(_ data: Data) -> Self {
Expand Down Expand Up @@ -94,7 +94,7 @@ public struct HTTPResponse: Sendable {
}

public init(headers: [HTTPHeader: String] = [:],
webSocket handler: WSHandler) {
webSocket handler: some WSHandler) {
self.version = .http11
self.statusCode = .switchingProtocols
self.headers = headers
Expand Down
8 changes: 4 additions & 4 deletions FlyingFox/Sources/HTTPRoute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ public struct HTTPRoute: Sendable {
public var path: [Component]
public var query: [QueryItem]
public var headers: [HTTPHeader: Component]
public var body: HTTPBodyPattern?
public var body: (any HTTPBodyPattern)?

public init(_ string: String, headers: [HTTPHeader: String] = [:], body: HTTPBodyPattern? = nil) {
public init(_ string: String, headers: [HTTPHeader: String] = [:], body: (any HTTPBodyPattern)? = nil) {
let comps = Self.components(for: string)
self.init(method: comps.method, path: comps.path, headers: headers, body: body)
}

public init(method: HTTPMethod, path: String, headers: [HTTPHeader: String] = [:], body: HTTPBodyPattern? = nil) {
public init(method: HTTPMethod, path: String, headers: [HTTPHeader: String] = [:], body: (any HTTPBodyPattern)? = nil) {
self.init(method: method.rawValue, path: path, headers: headers, body: body)
}

init(method: String, path: String, headers: [HTTPHeader: String], body: HTTPBodyPattern?) {
init(method: String, path: String, headers: [HTTPHeader: String], body: (any HTTPBodyPattern)?) {
self.method = Component(method)

let comps = HTTPRoute.readComponents(from: path)
Expand Down
54 changes: 27 additions & 27 deletions FlyingFox/Sources/HTTPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ import WinSDK.WinSock2

public final actor HTTPServer {

let pool: AsyncSocketPool
let pool: any AsyncSocketPool
private let address: sockaddr_storage
private let timeout: TimeInterval
private let logger: Logging?
private let logger: any Logging
private var handlers: RoutedHTTPHandler

public init<A: SocketAddress>(address: A,
timeout: TimeInterval = 15,
pool: AsyncSocketPool = defaultPool(),
logger: Logging? = defaultLogger(),
handler: HTTPHandler? = nil) {
pool: some AsyncSocketPool = defaultPool(),
logger: any Logging = defaultLogger(),
handler: (any HTTPHandler)? = nil) {
self.address = address.makeStorage()
self.timeout = timeout
self.pool = pool
Expand All @@ -60,7 +60,7 @@ public final actor HTTPServer {
try? state?.socket.sockname()
}

public func appendRoute(_ route: HTTPRoute, to handler: HTTPHandler) {
public func appendRoute(_ route: HTTPRoute, to handler: some HTTPHandler) {
handlers.appendRoute(route, to: handler)
}

Expand All @@ -70,7 +70,7 @@ public final actor HTTPServer {

public func start() async throws {
guard state == nil else {
logger?.logCritical("server error: already started")
logger.logCritical("server error: already started")
throw SocketError.unsupportedAddress
}
defer { state = nil }
Expand All @@ -80,7 +80,7 @@ public final actor HTTPServer {
state = (socket: socket, task: task)
try await task.getValue(cancelling: .whenParentIsCancelled)
} catch {
logger?.logCritical("server error: \(error.localizedDescription)")
logger.logCritical("server error: \(error.localizedDescription)")
if let state = self.state {
try? state.socket.close()
}
Expand All @@ -93,13 +93,13 @@ public final actor HTTPServer {
try await pool.prepare()
return try makeSocketAndListen()
} catch {
logger?.logCritical("server error: \(error.localizedDescription)")
logger.logCritical("server error: \(error.localizedDescription)")
throw error
}
}

var waiting: Set<Continuation> = []
private(set) var state: (socket: Socket, task: Task<Void, Error>)? {
private(set) var state: (socket: Socket, task: Task<Void, any Error>)? {
didSet { isListeningDidUpdate(from: oldValue != nil ) }
}

Expand All @@ -123,14 +123,14 @@ public final actor HTTPServer {
#endif
try socket.bind(to: address)
try socket.listen()
logger?.logListening(on: socket)
logger.logListening(on: socket)
return socket
}

func start(on socket: Socket, pool: AsyncSocketPool) async throws {
func start(on socket: Socket, pool: some AsyncSocketPool) async throws {
let asyncSocket = try AsyncSocket(socket: socket, pool: pool)

return try await withThrowingTaskGroup(of: Void.self) { group in
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
try await pool.run()
}
Expand Down Expand Up @@ -184,21 +184,21 @@ public final actor HTTPServer {
private(set) var connections: Set<HTTPConnection> = []

private func handleConnection(_ connection: HTTPConnection) async {
logger?.logOpenConnection(connection)
logger.logOpenConnection(connection)
connections.insert(connection)
do {
for try await request in connection.requests {
logger?.logRequest(request, on: connection)
logger.logRequest(request, on: connection)
let response = await handleRequest(request)
try await request.bodySequence.flushIfNeeded()
try await connection.sendResponse(response)
}
} catch {
logger?.logError(error, on: connection)
logger.logError(error, on: connection)
}
connections.remove(connection)
try? connection.close()
logger?.logCloseConnection(connection)
logger.logCloseConnection(connection)
}

func handleRequest(_ request: HTTPRequest) async -> HTTPResponse {
Expand All @@ -215,24 +215,24 @@ public final actor HTTPServer {
try await handlers.handleRequest(request)
}
} catch is HTTPUnhandledError {
logger?.logError("unhandled request")
logger.logError("unhandled request")
return HTTPResponse(statusCode: .notFound)
}
catch {
logger?.logError("handler error: \(error.localizedDescription)")
logger.logError("handler error: \(error.localizedDescription)")
return HTTPResponse(statusCode: .internalServerError)
}
}

private static func makeRootHandler(to handler: HTTPHandler?) -> RoutedHTTPHandler {
private static func makeRootHandler(to handler: (any HTTPHandler)?) -> RoutedHTTPHandler {
var root = RoutedHTTPHandler()
if let handler = handler {
root.appendRoute("*", to: handler)
}
return root
}

public static func defaultPool(logger: Logging? = nil) -> AsyncSocketPool {
public static func defaultPool(logger: some Logging = .disabled) -> some AsyncSocketPool {
#if canImport(Darwin)
return .kQueue(logger: logger)
#elseif canImport(CSystemLinux)
Expand All @@ -247,9 +247,9 @@ public extension HTTPServer {

init(port: UInt16,
timeout: TimeInterval = 15,
pool: AsyncSocketPool = defaultPool(),
logger: Logging? = defaultLogger(),
handler: HTTPHandler? = nil) {
pool: some AsyncSocketPool = defaultPool(),
logger: any Logging = defaultLogger(),
handler: (any HTTPHandler)? = nil) {
#if canImport(WinSDK)
let address = sockaddr_in.inet(port: port)
#else
Expand All @@ -264,8 +264,8 @@ public extension HTTPServer {

init(port: UInt16,
timeout: TimeInterval = 15,
pool: AsyncSocketPool = defaultPool(),
logger: Logging? = defaultLogger(),
pool: some AsyncSocketPool = defaultPool(),
logger: any Logging = defaultLogger(),
handler: @Sendable @escaping (HTTPRequest) async throws -> HTTPResponse) {
self.init(port: port,
timeout: timeout,
Expand Down Expand Up @@ -293,7 +293,7 @@ extension Logging {
logInfo("\(connection.identifer) request: \(request.method.rawValue) \(request.path)")
}

func logError(_ error: Error, on connection: HTTPConnection) {
func logError(_ error: any Error, on connection: HTTPConnection) {
logError("\(connection.identifer) error: \(error.localizedDescription)")
}

Expand Down
4 changes: 2 additions & 2 deletions FlyingFox/Sources/Handlers/RoutedHTTPHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@

public struct RoutedHTTPHandler: HTTPHandler, Sendable {

private var handlers: [(route: HTTPRoute, handler: HTTPHandler)] = []
private var handlers: [(route: HTTPRoute, handler: any HTTPHandler)] = []

public init() { }

public mutating func appendRoute(_ route: HTTPRoute, to handler: HTTPHandler) {
public mutating func appendRoute(_ route: HTTPRoute, to handler: some HTTPHandler) {
handlers.append((route, handler))
}

Expand Down
Loading

0 comments on commit 5c60e1c

Please sign in to comment.