diff --git a/Package.swift b/Package.swift index e377c5b1..93d9c899 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let swiftSettings: [SwiftSetting] = [ let package = Package( name: "hummingbird", - platforms: [.macOS(.v14), .iOS(.v17), .macCatalyst(.v17), .tvOS(.v17), .visionOS(.v1)], + platforms: [.macOS(.v11), .iOS(.v15), .macCatalyst(.v15), .tvOS(.v15), .visionOS(.v1)], products: [ .library(name: "Hummingbird", targets: ["Hummingbird"]), .library(name: "HummingbirdCore", targets: ["HummingbirdCore"]), diff --git a/Package@swift-6.0.swift b/Package@swift-6.0.swift index 32ea7df3..3d6b3bdd 100644 --- a/Package@swift-6.0.swift +++ b/Package@swift-6.0.swift @@ -17,7 +17,7 @@ let swiftSettings: [SwiftSetting] = [ let package = Package( name: "hummingbird", - platforms: [.macOS(.v14), .iOS(.v17), .macCatalyst(.v17), .tvOS(.v17), .visionOS(.v1)], + platforms: [.macOS(.v11), .iOS(.v15), .macCatalyst(.v15), .tvOS(.v15), .visionOS(.v1)], products: [ .library(name: "Hummingbird", targets: ["Hummingbird"]), .library(name: "HummingbirdCore", targets: ["HummingbirdCore"]), diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift index 58645c6f..083df979 100644 --- a/Package@swift-6.1.swift +++ b/Package@swift-6.1.swift @@ -17,7 +17,7 @@ let swiftSettings: [SwiftSetting] = [ let package = Package( name: "hummingbird", - platforms: [.macOS(.v14), .iOS(.v17), .macCatalyst(.v17), .tvOS(.v17), .visionOS(.v1)], + platforms: [.macOS(.v11), .iOS(.v15), .macCatalyst(.v15), .tvOS(.v15), .visionOS(.v1)], products: [ .library(name: "Hummingbird", targets: ["Hummingbird"]), .library(name: "HummingbirdCore", targets: ["HummingbirdCore"]), diff --git a/Sources/Hummingbird/Application.swift b/Sources/Hummingbird/Application.swift index da43e737..be8382e6 100644 --- a/Sources/Hummingbird/Application.swift +++ b/Sources/Hummingbird/Application.swift @@ -41,6 +41,7 @@ public enum EventLoopGroupProvider { } /// Protocol for an Application. Brings all the components of Hummingbird together +@available(macOS 14, iOS 17, tvOS 17, *) public protocol ApplicationProtocol: Service where Context: InitializableFromSource { /// Responder that generates a response from a requests and context associatedtype Responder: HTTPResponder @@ -67,11 +68,13 @@ public protocol ApplicationProtocol: Service where Context: InitializableFromSou var processesRunBeforeServerStart: [@Sendable () async throws -> Void] { get } } +@available(macOS 14, iOS 17, tvOS 17, *) extension ApplicationProtocol { /// Server channel setup public var server: HTTPServerBuilder { .http1() } } +@available(macOS 14, iOS 17, tvOS 17, *) extension ApplicationProtocol { /// Default event loop group used by application public var eventLoopGroup: any EventLoopGroup { MultiThreadedEventLoopGroup.singleton } @@ -88,6 +91,7 @@ extension ApplicationProtocol { } /// Conform to `Service` from `ServiceLifecycle`. +@available(macOS 14, iOS 17, tvOS 17, *) extension ApplicationProtocol { /// Construct application and run it public func run() async throws { @@ -175,6 +179,7 @@ extension ApplicationProtocol { /// try await app.runService() /// ``` /// Editing the application setup after calling `runService` will produce undefined behaviour. +@available(macOS 14, iOS 17, tvOS 17, *) public struct Application: ApplicationProtocol where Responder.Context: InitializableFromSource { // MARK: Member variables @@ -303,6 +308,7 @@ where Responder.Context: InitializableFromSource Bool { (try? self.unboxNil(self.storage.topContainer)) ?? false @@ -487,6 +490,7 @@ extension _URLEncodedFormDecoder: SingleValueDecodingContainer { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension _URLEncodedFormDecoder { func unboxNil(_ node: URLEncodedFormNode) throws -> Bool { switch node { @@ -686,6 +690,7 @@ extension _URLEncodedFormDecoder { } } +@available(macOS 14, iOS 17, tvOS 17, *) private struct URLEncodedFormDecodingStorage { /// the container stack private var containers: [URLEncodedFormNode] = [] diff --git a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormEncoder.swift b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormEncoder.swift index 2c042a55..cceeff3b 100644 --- a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormEncoder.swift +++ b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormEncoder.swift @@ -9,6 +9,7 @@ public import Foundation /// The wrapper struct for encoding Codable classes to URL encoded form data +@available(macOS 14, iOS 17, tvOS 17, *) public struct URLEncodedFormEncoder: Sendable { /// The strategy to use for encoding `Date` values. public enum DateEncodingStrategy: Sendable { @@ -80,6 +81,7 @@ public struct URLEncodedFormEncoder: Sendable { } /// Internal QueryEncoder class. Does all the heavy lifting +@available(macOS 14, iOS 17, tvOS 17, *) private class _URLEncodedFormEncoder: Encoder { var codingPath: [any CodingKey] @@ -273,6 +275,7 @@ private class _URLEncodedFormEncoder: Encoder { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension _URLEncodedFormEncoder: SingleValueEncodingContainer { func encodeResult(_ value: URLEncodedFormNode) { self.storage.push(container: value) @@ -310,6 +313,7 @@ extension _URLEncodedFormEncoder: SingleValueEncodingContainer { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension _URLEncodedFormEncoder { func box(_ date: Date) throws -> URLEncodedFormNode { switch self.options.dateEncodingStrategy { @@ -355,6 +359,7 @@ extension _URLEncodedFormEncoder { } /// storage for Query Encoder. Stores a stack of QueryEncoder containers, plus leaf objects +@available(macOS 14, iOS 17, tvOS 17, *) private struct URLEncodedFormEncoderStorage { /// the container stack private var containers: [URLEncodedFormNode] = [] diff --git a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift index e15a7f33..56319bac 100644 --- a/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift +++ b/Sources/Hummingbird/Codable/URLEncodedForm/URLEncodedFormNode.swift @@ -71,6 +71,7 @@ extension URLEncodedFormError { } } /// Internal representation of URL encoded form data used by both encode and decode +@available(macOS 14, iOS 17, tvOS 17, *) enum URLEncodedFormNode: CustomStringConvertible, Equatable { /// holds a value case leaf(NodeValue?) diff --git a/Sources/Hummingbird/HTTP/Cookie.swift b/Sources/Hummingbird/HTTP/Cookie.swift index e762f1ca..d0093503 100644 --- a/Sources/Hummingbird/HTTP/Cookie.swift +++ b/Sources/Hummingbird/HTTP/Cookie.swift @@ -13,6 +13,7 @@ public import Foundation #endif /// Structure holding a single cookie +@available(macOS 14, iOS 17, tvOS 17, *) public struct Cookie: Sendable, CustomStringConvertible { public struct ValidationError: Error { enum Reason { diff --git a/Sources/Hummingbird/HTTP/Cookies.swift b/Sources/Hummingbird/HTTP/Cookies.swift index 3e06399e..f7d73ad7 100644 --- a/Sources/Hummingbird/HTTP/Cookies.swift +++ b/Sources/Hummingbird/HTTP/Cookies.swift @@ -9,6 +9,7 @@ /// Structure holding an array of cookies /// /// Cookies can be accessed from request via `Request.cookies`. +@available(macOS 14, iOS 17, tvOS 17, *) public struct Cookies: Sendable { /// Construct cookies accessor from `Request` /// - Parameter request: request to get cookies from diff --git a/Sources/Hummingbird/HTTP/Request+Cookies.swift b/Sources/Hummingbird/HTTP/Request+Cookies.swift index 5b08dd4c..5eb82449 100644 --- a/Sources/Hummingbird/HTTP/Request+Cookies.swift +++ b/Sources/Hummingbird/HTTP/Request+Cookies.swift @@ -8,6 +8,7 @@ public import HummingbirdCore +@available(macOS 14, iOS 17, tvOS 17, *) extension Request { /// access cookies from request. When accessing this for the first time the Cookies struct will be created public var cookies: Cookies { diff --git a/Sources/Hummingbird/HTTP/Response+Cookies.swift b/Sources/Hummingbird/HTTP/Response+Cookies.swift index 6c5d1ceb..f087576c 100644 --- a/Sources/Hummingbird/HTTP/Response+Cookies.swift +++ b/Sources/Hummingbird/HTTP/Response+Cookies.swift @@ -8,6 +8,7 @@ public import HummingbirdCore +@available(macOS 14, iOS 17, tvOS 17, *) extension Response { /// Set cookie on response public mutating func setCookie(_ cookie: Cookie) { @@ -15,6 +16,7 @@ extension Response { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension EditedResponse { /// Set cookie on reponse patch /// diff --git a/Sources/Hummingbird/Middleware/FileMiddleware.swift b/Sources/Hummingbird/Middleware/FileMiddleware.swift index 593a25fa..815fefdd 100644 --- a/Sources/Hummingbird/Middleware/FileMiddleware.swift +++ b/Sources/Hummingbird/Middleware/FileMiddleware.swift @@ -40,6 +40,7 @@ public protocol FileMiddlewareFileAttributes { /// "if-modified-since", "if-none-match", "if-range" and 'range" headers. It will output "content-length", /// "modified-date", "eTag", "content-type", "cache-control" and "content-range" headers where /// they are relevant. +@available(macOS 14, iOS 17, tvOS 17, *) public struct FileMiddleware: RouterMiddleware where Provider.FileAttributes: FileMiddlewareFileAttributes { let cacheControl: CacheControl @@ -221,6 +222,7 @@ where Provider.FileAttributes: FileMiddlewareFileAttributes { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension FileMiddleware { /// Whether to return data from the file or a not modified response private enum FileResult { diff --git a/Sources/Hummingbird/Middleware/MiddlewareGroup.swift b/Sources/Hummingbird/Middleware/MiddlewareGroup.swift index b74517d5..fbd6d8a2 100644 --- a/Sources/Hummingbird/Middleware/MiddlewareGroup.swift +++ b/Sources/Hummingbird/Middleware/MiddlewareGroup.swift @@ -7,6 +7,7 @@ // /// Group of middleware that can be used to create a responder chain. Each middleware calls the next one +@available(macOS 14, iOS 17, tvOS 17, *) public final class MiddlewareGroup { var middlewares: [any MiddlewareProtocol] diff --git a/Sources/Hummingbird/Middleware/TracingMiddleware.swift b/Sources/Hummingbird/Middleware/TracingMiddleware.swift index e02b5ef0..ea85e76f 100644 --- a/Sources/Hummingbird/Middleware/TracingMiddleware.swift +++ b/Sources/Hummingbird/Middleware/TracingMiddleware.swift @@ -28,6 +28,7 @@ import Foundation /// Swift-Distributed-Tracing has a flexible backend, which will need to be initialized before any traces are recorded. /// /// A list of implementations is available in the swift-distributed-tracing repository's README. +@available(macOS 14, iOS 17, tvOS 17, *) public struct TracingMiddleware: RouterMiddleware { private let headerNamesToRecord: Set private let queryParametersToRedact: Set @@ -196,6 +197,7 @@ public protocol RemoteAddressRequestContext: RequestContext { var remoteAddress: SocketAddress? { get } } +@available(macOS 14, iOS 17, tvOS 17, *) struct RecordingHeader: Hashable { let name: HTTPField.Name let attributeName: String diff --git a/Sources/Hummingbird/Router/EndpointResponder.swift b/Sources/Hummingbird/Router/EndpointResponder.swift index 1fbc74e8..8cdacdc3 100644 --- a/Sources/Hummingbird/Router/EndpointResponder.swift +++ b/Sources/Hummingbird/Router/EndpointResponder.swift @@ -9,6 +9,7 @@ public import HTTPTypes /// Stores endpoint responders for each HTTP method +@available(macOS 14, iOS 17, tvOS 17, *) @usableFromInline struct EndpointResponders: Sendable { init(path: RouterPath) { diff --git a/Sources/Hummingbird/Router/RouteCollection.swift b/Sources/Hummingbird/Router/RouteCollection.swift index beb34d5a..46fb98e7 100644 --- a/Sources/Hummingbird/Router/RouteCollection.swift +++ b/Sources/Hummingbird/Router/RouteCollection.swift @@ -9,6 +9,7 @@ public import HTTPTypes /// Collection of routes +@available(macOS 14, iOS 17, tvOS 17, *) public final class RouteCollection: RouterMethods { /// Initialize RouteCollection public init(context: Context.Type = BasicRequestContext.self) { @@ -52,6 +53,7 @@ public final class RouteCollection: RouterMethods { let middlewares: MiddlewareGroup } +@available(macOS 14, iOS 17, tvOS 17, *) extension RouterMethods { /// Add route collection to router /// - Parameters diff --git a/Sources/Hummingbird/Router/Router+validation.swift b/Sources/Hummingbird/Router/Router+validation.swift index b4d30b3d..5ed85202 100644 --- a/Sources/Hummingbird/Router/Router+validation.swift +++ b/Sources/Hummingbird/Router/Router+validation.swift @@ -14,6 +14,7 @@ import FoundationEssentials import Foundation #endif +@available(macOS 14, iOS 17, tvOS 17, *) extension Router { /// Route description public struct RouteDescription: CustomStringConvertible { diff --git a/Sources/Hummingbird/Router/Router.swift b/Sources/Hummingbird/Router/Router.swift index a384fb63..0c13b412 100644 --- a/Sources/Hummingbird/Router/Router.swift +++ b/Sources/Hummingbird/Router/Router.swift @@ -36,6 +36,7 @@ public import HummingbirdCore /// Both of these match routes which start with "/user" and the next path segment being anything. /// The second version extracts the path segment out and adds it to `Request.parameters` with the /// key "id". +@available(macOS 14, iOS 17, tvOS 17, *) public final class Router: RouterMethods, HTTPResponderBuilder { var trie: RouterPathTrieBuilder> public let middlewares: MiddlewareGroup diff --git a/Sources/Hummingbird/Router/RouterGroup.swift b/Sources/Hummingbird/Router/RouterGroup.swift index 2ae7e9f8..a7c045ad 100644 --- a/Sources/Hummingbird/Router/RouterGroup.swift +++ b/Sources/Hummingbird/Router/RouterGroup.swift @@ -23,6 +23,7 @@ public import HummingbirdCore /// .put(":id", use: todoController.update) /// .delete(":id", use: todoController.delete) /// ``` +@available(macOS 14, iOS 17, tvOS 17, *) public struct RouterGroup: RouterMethods { let path: RouterPath let parent: any RouterMethods diff --git a/Sources/Hummingbird/Router/RouterMethods.swift b/Sources/Hummingbird/Router/RouterMethods.swift index 2737f08e..147adb0e 100644 --- a/Sources/Hummingbird/Router/RouterMethods.swift +++ b/Sources/Hummingbird/Router/RouterMethods.swift @@ -34,6 +34,7 @@ public protocol RouterMethods: _HB_SendableMetatype { func add(middleware: any MiddlewareProtocol) -> Self } +@available(macOS 14, iOS 17, tvOS 17, *) extension RouterMethods { /// Add path for async closure @discardableResult public func on( diff --git a/Sources/Hummingbird/Router/RouterResponder.swift b/Sources/Hummingbird/Router/RouterResponder.swift index c635fff7..eb3a26c9 100644 --- a/Sources/Hummingbird/Router/RouterResponder.swift +++ b/Sources/Hummingbird/Router/RouterResponder.swift @@ -8,6 +8,7 @@ import NIOCore +@available(macOS 14, iOS 17, tvOS 17, *) public struct RouterResponder: HTTPResponder { @usableFromInline let trie: RouterTrie> diff --git a/Sources/Hummingbird/Server/Request.swift b/Sources/Hummingbird/Server/Request.swift index 405eef3d..c0efceb8 100644 --- a/Sources/Hummingbird/Server/Request.swift +++ b/Sources/Hummingbird/Server/Request.swift @@ -58,6 +58,7 @@ extension Request { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension Request { /// Conditional request which will only be processed if the eTag supplied is not in the /// `If-None-Match` request header. diff --git a/Sources/Hummingbird/Server/URI+decodeQuery.swift b/Sources/Hummingbird/Server/URI+decodeQuery.swift index 8e530a61..da934177 100644 --- a/Sources/Hummingbird/Server/URI+decodeQuery.swift +++ b/Sources/Hummingbird/Server/URI+decodeQuery.swift @@ -9,6 +9,7 @@ public import HummingbirdCore import Logging +@available(macOS 14, iOS 17, tvOS 17, *) extension URI { /// Decode request query using ``Hummingbird/URLEncodedFormDecoder``. /// - Parameters diff --git a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift index 9401c8e1..759d889c 100644 --- a/Sources/Hummingbird/Storage/MemoryPersistDriver.swift +++ b/Sources/Hummingbird/Storage/MemoryPersistDriver.swift @@ -12,6 +12,7 @@ import NIOCore import ServiceLifecycle /// In memory driver for persist system for storing persistent cross request key/value pairs +@available(macOS 14, iOS 17, tvOS 17, *) public actor MemoryPersistDriver: PersistDriver where C.Duration == Duration { public struct Configuration: Sendable { /// amount of time between each call to tidy diff --git a/Sources/Hummingbird/Storage/PersistDriver.swift b/Sources/Hummingbird/Storage/PersistDriver.swift index 58a3c12f..641c0188 100644 --- a/Sources/Hummingbird/Storage/PersistDriver.swift +++ b/Sources/Hummingbird/Storage/PersistDriver.swift @@ -9,6 +9,7 @@ public import ServiceLifecycle /// Protocol for driver supporting persistent Key/Value pairs across requests +@available(macOS 14, iOS 17, tvOS 17, *) public protocol PersistDriver: Service { /// shutdown driver func shutdown() async throws @@ -40,6 +41,7 @@ public protocol PersistDriver: Service { func remove(key: String) async throws } +@available(macOS 14, iOS 17, tvOS 17, *) extension PersistDriver { /// default implemenation of shutdown() public func shutdown() async throws {} diff --git a/Sources/Hummingbird/Utils/DateCache.swift b/Sources/Hummingbird/Utils/DateCache.swift index d1404f9f..d6a161ea 100644 --- a/Sources/Hummingbird/Utils/DateCache.swift +++ b/Sources/Hummingbird/Utils/DateCache.swift @@ -22,6 +22,7 @@ import Foundation /// /// Getting the current date formatted is an expensive operation. This creates a task that will /// update a cached version of the date in the format as detailed in RFC9110 once every second. +@available(macOS 14, iOS 17, tvOS 17, *) final class DateCache: Service { final class DateContainer: AtomicReference, Sendable { let date: String diff --git a/Sources/Hummingbird/Utils/HTTPHeaderDateFormatStyle.swift b/Sources/Hummingbird/Utils/HTTPHeaderDateFormatStyle.swift index 30fd566b..2a759c77 100644 --- a/Sources/Hummingbird/Utils/HTTPHeaderDateFormatStyle.swift +++ b/Sources/Hummingbird/Utils/HTTPHeaderDateFormatStyle.swift @@ -18,6 +18,7 @@ import FoundationEssentials import Foundation #endif +@available(macOS 14, iOS 17, tvOS 17, *) extension Date { init?(httpHeader: String) { try? self.init(httpHeader, strategy: .rfc9110) @@ -30,6 +31,7 @@ extension Date { struct HTTPHeaderDateParsingError: Error {} +@available(macOS 14, iOS 17, tvOS 17, *) struct HTTPHeaderDateFormatStyle { let calendar: Calendar @@ -40,6 +42,7 @@ struct HTTPHeaderDateFormatStyle { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTPHeaderDateFormatStyle: ParseStrategy { func parse(_ input: String) throws -> Date { guard let components = self.components(from: input) else { @@ -275,6 +278,7 @@ let timezoneOffsetMap: [[UInt8]: Int] = [ Array("PDT".utf8): -7 * 60, ] +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTPHeaderDateFormatStyle: FormatStyle { //let calendar: Calendar @@ -319,10 +323,12 @@ extension HTTPHeaderDateFormatStyle: FormatStyle { ] } +@available(macOS 14, iOS 17, tvOS 17, *) extension FormatStyle where Self == HTTPHeaderDateFormatStyle { static var rfc9110: Self { .init() } } +@available(macOS 14, iOS 17, tvOS 17, *) extension ParseStrategy where Self == HTTPHeaderDateFormatStyle { static var rfc9110: Self { .init() } } diff --git a/Sources/HummingbirdCore/Server/HTTP/HTTPServerBuilder.swift b/Sources/HummingbirdCore/Server/HTTP/HTTPServerBuilder.swift index c98884d9..4339e323 100644 --- a/Sources/HummingbirdCore/Server/HTTP/HTTPServerBuilder.swift +++ b/Sources/HummingbirdCore/Server/HTTP/HTTPServerBuilder.swift @@ -32,6 +32,7 @@ public struct HTTPServerBuilder: Sendable { /// - responder: HTTP responder /// - onServerRunning: Closure to run once server is up and running /// - Returns: Server Service + @available(macOS 14, iOS 17, tvOS 17, *) public func buildServer( configuration: ServerConfiguration, eventLoopGroup: any EventLoopGroup, diff --git a/Sources/HummingbirdCore/Server/Server.swift b/Sources/HummingbirdCore/Server/Server.swift index ced1fad5..5f4b350c 100644 --- a/Sources/HummingbirdCore/Server/Server.swift +++ b/Sources/HummingbirdCore/Server/Server.swift @@ -18,6 +18,7 @@ import NIOTransportServices #endif /// HTTP server class +@available(macOS 14, iOS 17, tvOS 17, *) public actor Server: Service { public typealias AsyncChildChannel = ChildChannel.Value public typealias AsyncServerChannel = NIOAsyncChannel @@ -88,6 +89,7 @@ public actor Server: Service { self.logger = logger } + @available(macOS 14, iOS 17, tvOS 17, *) public func run() async throws { switch self.state { case .initial(let childChannelSetup, let configuration, let onServerRunning): @@ -361,6 +363,7 @@ extension NIOTSListenerBootstrap: ServerBootstrapProtocol { } #endif +@available(macOS 14, iOS 17, tvOS 17, *) extension Server: CustomStringConvertible { public nonisolated var description: String { "Hummingbird" diff --git a/Sources/HummingbirdCore/Server/ServerChildChannel.swift b/Sources/HummingbirdCore/Server/ServerChildChannel.swift index e556eded..9b9ffaab 100644 --- a/Sources/HummingbirdCore/Server/ServerChildChannel.swift +++ b/Sources/HummingbirdCore/Server/ServerChildChannel.swift @@ -34,6 +34,7 @@ public protocol ServerChildChannel: Sendable { func handle(value: Value, logger: Logger) async } +@available(macOS 14, iOS 17, tvOS 17, *) extension ServerChildChannel { /// Build existential ``Server`` from existential `ServerChildChannel` /// diff --git a/Sources/HummingbirdHTTP2/HTTP2Channel.swift b/Sources/HummingbirdHTTP2/HTTP2Channel.swift index 711c5ca7..27234559 100644 --- a/Sources/HummingbirdHTTP2/HTTP2Channel.swift +++ b/Sources/HummingbirdHTTP2/HTTP2Channel.swift @@ -15,6 +15,7 @@ import NIOHTTPTypesHTTP2 import NIOSSL /// HTTP2 configuration +@available(macOS 14, iOS 17, tvOS 17, *) public struct HTTP2ChannelConfiguration: Sendable { /// Idle timeout, how long connection is kept idle before closing public var idleTimeout: Duration? @@ -44,6 +45,7 @@ public struct HTTP2ChannelConfiguration: Sendable { } /// Child channel for processing HTTP2 +@available(macOS 14, iOS 17, tvOS 17, *) public struct HTTP2Channel: ServerChildChannel { public typealias Configuration = HTTP2ChannelConfiguration typealias HTTP2Connection = NIOHTTP2Handler.AsyncStreamMultiplexer diff --git a/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager+StateMachine.swift b/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager+StateMachine.swift index def8b863..be6350df 100644 --- a/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager+StateMachine.swift +++ b/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager+StateMachine.swift @@ -9,6 +9,7 @@ import NIOCore import NIOHTTP2 +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager { struct StateMachine: ~Copyable { var state: State @@ -196,6 +197,7 @@ extension HTTP2ServerConnectionManager { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager.StateMachine { enum State: ~Copyable { struct ActiveState { @@ -232,6 +234,7 @@ extension HTTP2ServerConnectionManager.StateMachine { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager.StateMachine { struct Keepalive { /// Allow the client to send keep alive pings when there are no active calls. @@ -303,6 +306,7 @@ extension HTTP2ServerConnectionManager.StateMachine { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager.StateMachine { // case active(ActiveState) // case closing(ClosingState) diff --git a/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager.swift b/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager.swift index d867d2f8..807e790a 100644 --- a/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager.swift +++ b/Sources/HummingbirdHTTP2/HTTP2ServerConnectionManager.swift @@ -12,6 +12,7 @@ import NIOHTTP2 /// HTTP2 server connection manager /// /// This is heavily based off the ServerConnectionManagementHandler from https://github.com/grpc/grpc-swift-nio-transport +@available(macOS 14, iOS 17, tvOS 17, *) final class HTTP2ServerConnectionManager: ChannelDuplexHandler { package typealias InboundIn = HTTP2Frame package typealias InboundOut = HTTP2Frame @@ -225,6 +226,7 @@ final class HTTP2ServerConnectionManager: ChannelDuplexHandler { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager { struct LoopBoundHandler: @unchecked Sendable { let handler: HTTP2ServerConnectionManager @@ -240,6 +242,7 @@ extension HTTP2ServerConnectionManager { } } +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTP2ServerConnectionManager { /// Stream delegate struct HTTP2StreamDelegate: NIOHTTP2StreamDelegate, @unchecked Sendable { diff --git a/Sources/HummingbirdHTTP2/HTTP2UpgradeChannel.swift b/Sources/HummingbirdHTTP2/HTTP2UpgradeChannel.swift index 49d05681..c2151e28 100644 --- a/Sources/HummingbirdHTTP2/HTTP2UpgradeChannel.swift +++ b/Sources/HummingbirdHTTP2/HTTP2UpgradeChannel.swift @@ -17,6 +17,7 @@ import NIOSSL import NIOTLS /// Child channel for processing HTTP1 with the option of upgrading to HTTP2 via ALPN +@available(macOS 14, iOS 17, tvOS 17, *) public struct HTTP2UpgradeChannel: HTTPChannelHandler { public typealias Configuration = HTTP2ChannelConfiguration typealias HTTP1Connection = HTTP1Channel.Value diff --git a/Sources/HummingbirdHTTP2/HTTPServerBuilder+http2.swift b/Sources/HummingbirdHTTP2/HTTPServerBuilder+http2.swift index 2bc1d0f2..c42c3030 100644 --- a/Sources/HummingbirdHTTP2/HTTPServerBuilder+http2.swift +++ b/Sources/HummingbirdHTTP2/HTTPServerBuilder+http2.swift @@ -10,6 +10,7 @@ import HummingbirdCore import NIOCore import NIOSSL +@available(macOS 14, iOS 17, tvOS 17, *) extension HTTPServerBuilder { /// Build HTTP channel with HTTP2 upgrade /// diff --git a/Sources/HummingbirdTesting/Application+Test.swift b/Sources/HummingbirdTesting/Application+Test.swift index e9fb7462..b6f9f9c8 100644 --- a/Sources/HummingbirdTesting/Application+Test.swift +++ b/Sources/HummingbirdTesting/Application+Test.swift @@ -36,6 +36,7 @@ public struct TestingSetup { } /// Extends `ApplicationProtocol` to support testing of applications +@available(macOS 14, iOS 17, tvOS 17, *) extension ApplicationProtocol { // MARK: Initialization diff --git a/Sources/HummingbirdTesting/AsyncHTTPClientTestFramework.swift b/Sources/HummingbirdTesting/AsyncHTTPClientTestFramework.swift index 3388a653..02667f27 100644 --- a/Sources/HummingbirdTesting/AsyncHTTPClientTestFramework.swift +++ b/Sources/HummingbirdTesting/AsyncHTTPClientTestFramework.swift @@ -19,6 +19,7 @@ import ServiceLifecycle import UnixSignals /// Test using a live server and AsyncHTTPClient as a client +@available(macOS 14, iOS 17, tvOS 17, *) final class AsyncHTTPClientTestFramework: ApplicationTestFramework { struct Client: TestClientProtocol { let client: HTTPClient diff --git a/Sources/HummingbirdTesting/LiveTestFramework.swift b/Sources/HummingbirdTesting/LiveTestFramework.swift index dacf3d64..d9c657d4 100644 --- a/Sources/HummingbirdTesting/LiveTestFramework.swift +++ b/Sources/HummingbirdTesting/LiveTestFramework.swift @@ -16,6 +16,7 @@ import ServiceLifecycle import UnixSignals /// Test using a live server +@available(macOS 14, iOS 17, tvOS 17, *) final class LiveTestFramework: ApplicationTestFramework { struct Client: TestClientProtocol { let client: TestClient diff --git a/Sources/HummingbirdTesting/RouterTestFramework.swift b/Sources/HummingbirdTesting/RouterTestFramework.swift index a028fea5..feb709b6 100644 --- a/Sources/HummingbirdTesting/RouterTestFramework.swift +++ b/Sources/HummingbirdTesting/RouterTestFramework.swift @@ -20,6 +20,7 @@ import ServiceLifecycle import UnixSignals /// Test sending requests directly to router. This does not setup a live server +@available(macOS 14, iOS 17, tvOS 17, *) struct RouterTestFramework: ApplicationTestFramework where Responder.Context: InitializableFromSource { let responder: Responder let makeContext: @Sendable (Logger) -> Responder.Context diff --git a/Sources/HummingbirdTesting/TestApplication.swift b/Sources/HummingbirdTesting/TestApplication.swift index 0d812210..b2f47bbe 100644 --- a/Sources/HummingbirdTesting/TestApplication.swift +++ b/Sources/HummingbirdTesting/TestApplication.swift @@ -16,6 +16,7 @@ import ServiceLifecycle /// TestApplication used to wrap Application being tested. /// /// This is needed to override the `onServerRunning` function +@available(macOS 14, iOS 17, tvOS 17, *) internal struct TestApplication: ApplicationProtocol, Service { typealias Responder = BaseApp.Responder diff --git a/Sources/HummingbirdTesting/TestClient+types.swift b/Sources/HummingbirdTesting/TestClient+types.swift index 1d015cfa..904c9308 100644 --- a/Sources/HummingbirdTesting/TestClient+types.swift +++ b/Sources/HummingbirdTesting/TestClient+types.swift @@ -10,6 +10,7 @@ public import HTTPTypes public import NIOCore /// HTTP client types +@available(macOS 14, iOS 17, tvOS 17, *) extension TestClient { public enum Error: Swift.Error { case invalidURL diff --git a/Sources/HummingbirdTesting/TestClient.swift b/Sources/HummingbirdTesting/TestClient.swift index 9e896b64..cb079555 100644 --- a/Sources/HummingbirdTesting/TestClient.swift +++ b/Sources/HummingbirdTesting/TestClient.swift @@ -18,6 +18,7 @@ public import NIOSSL /// /// This HTTP client is used for internal testing of Hummingbird and is also /// the client used by `.live` testing framework. +@available(macOS 14, iOS 17, tvOS 17, *) public struct TestClient: Sendable { public let channelPromise: EventLoopPromise let eventLoopGroup: any EventLoopGroup diff --git a/Sources/PerformanceTest/main.swift b/Sources/PerformanceTest/main.swift index 35cb80a2..6dac7c57 100644 --- a/Sources/PerformanceTest/main.swift +++ b/Sources/PerformanceTest/main.swift @@ -11,58 +11,62 @@ import Logging import NIOCore import NIOPosix -// get environment -let env = Environment() -let hostname = env.get("SERVER_HOSTNAME") ?? "127.0.0.1" -let port = env.get("SERVER_PORT", as: Int.self) ?? 8080 +if #available(macOS 14, iOS 17, tvOS 17, *) { + // get environment + let env = Environment() + let hostname = env.get("SERVER_HOSTNAME") ?? "127.0.0.1" + let port = env.get("SERVER_PORT", as: Int.self) ?? 8080 -// create app -let elg = MultiThreadedEventLoopGroup(numberOfThreads: 4) -var router = Router() -router.addMiddleware { - FileMiddleware() -} + // create app + let elg = MultiThreadedEventLoopGroup(numberOfThreads: 4) + var router = Router() + router.addMiddleware { + FileMiddleware() + } -// number of raw requests -// ./wrk -c 128 -d 15s -t 8 http://localhost:8080 -router.get { _, _ in - "Hello, world" -} + // number of raw requests + // ./wrk -c 128 -d 15s -t 8 http://localhost:8080 + router.get { _, _ in + "Hello, world" + } -// request with a body -// ./wrk -c 128 -d 15s -t 8 -s scripts/post.lua http://localhost:8080 -router.post { request, _ in - Response(status: .ok, body: .init(asyncSequence: request.body)) -} + // request with a body + // ./wrk -c 128 -d 15s -t 8 -s scripts/post.lua http://localhost:8080 + router.post { request, _ in + Response(status: .ok, body: .init(asyncSequence: request.body)) + } -struct Object: ResponseEncodable { - let message: String -} + struct Object: ResponseEncodable { + let message: String + } -// return JSON -// ./wrk -c 128 -d 15s -t 8 http://localhost:8080/json -router.get("json") { _, _ in - Object(message: "Hello, world") -} + // return JSON + // ./wrk -c 128 -d 15s -t 8 http://localhost:8080/json + router.get("json") { _, _ in + Object(message: "Hello, world") + } -// return JSON -// ./wrk -c 128 -d 15s -t 8 http://localhost:8080/json -router.get("wait") { _, _ in - try await Task.sleep(for: .seconds(8)) - return "I waited" -} + // return JSON + // ./wrk -c 128 -d 15s -t 8 http://localhost:8080/json + router.get("wait") { _, _ in + try await Task.sleep(for: .seconds(8)) + return "I waited" + } -var app = Application( - responder: router.buildResponder(), - configuration: .init( - address: .hostname(hostname, port: port), - serverName: "Hummingbird" - ), - eventLoopGroupProvider: .shared(elg) -) -app.logger.logLevel = .debug + var app = Application( + responder: router.buildResponder(), + configuration: .init( + address: .hostname(hostname, port: port), + serverName: "Hummingbird" + ), + eventLoopGroupProvider: .shared(elg) + ) + app.logger.logLevel = .debug -// configure app + // configure app -// run app -try await app.runService() + // run app + try await app.runService() +} else { + fatalError("Hummingbird requires macOS 14, iOS 17 or tvOS 17") +}