diff --git a/Sources/HummingbirdCore/Server/EventLoopExecutor.swift b/Sources/HummingbirdCore/Server/EventLoopExecutor.swift index 5c42cdf78..8db501365 100644 --- a/Sources/HummingbirdCore/Server/EventLoopExecutor.swift +++ b/Sources/HummingbirdCore/Server/EventLoopExecutor.swift @@ -15,49 +15,49 @@ import NIOCore #if compiler(>=6.0) - final class EventLoopExecutor: TaskExecutor, SerialExecutor { - @usableFromInline let eventLoop: EventLoop +final class EventLoopExecutor: TaskExecutor, SerialExecutor { + @usableFromInline let eventLoop: EventLoop - init(eventLoop: EventLoop) { - self.eventLoop = eventLoop - } - - func asUnownedTaskExecutor() -> UnownedTaskExecutor { - UnownedTaskExecutor(ordinary: self) - } + init(eventLoop: EventLoop) { + self.eventLoop = eventLoop + } - @inlinable - func enqueue(_ job: consuming ExecutorJob) { - let job = UnownedJob(job) - self.eventLoop.execute { - job.runSynchronously(on: self.asUnownedTaskExecutor()) - } - } + func asUnownedTaskExecutor() -> UnownedTaskExecutor { + UnownedTaskExecutor(ordinary: self) + } - @inlinable - func asUnownedSerialExecutor() -> UnownedSerialExecutor { - UnownedSerialExecutor(complexEquality: self) + @inlinable + func enqueue(_ job: consuming ExecutorJob) { + let job = UnownedJob(job) + self.eventLoop.execute { + job.runSynchronously(on: self.asUnownedTaskExecutor()) } + } - @inlinable - func isSameExclusiveExecutionContext(other: EventLoopExecutor) -> Bool { - self.eventLoop === other.eventLoop - } + @inlinable + func asUnownedSerialExecutor() -> UnownedSerialExecutor { + UnownedSerialExecutor(complexEquality: self) } - struct EventLoopExecutorMap { - init(eventLoopGroup: EventLoopGroup) { - var executors: [ObjectIdentifier: EventLoopExecutor] = [:] - for eventLoop in eventLoopGroup.makeIterator() { - executors[ObjectIdentifier(eventLoop)] = EventLoopExecutor(eventLoop: eventLoop) - } - self.executors = executors - } + @inlinable + func isSameExclusiveExecutionContext(other: EventLoopExecutor) -> Bool { + self.eventLoop === other.eventLoop + } +} - subscript(eventLoop: EventLoop) -> EventLoopExecutor? { - return self.executors[ObjectIdentifier(eventLoop)] +struct EventLoopExecutorMap { + init(eventLoopGroup: EventLoopGroup) { + var executors: [ObjectIdentifier: EventLoopExecutor] = [:] + for eventLoop in eventLoopGroup.makeIterator() { + executors[ObjectIdentifier(eventLoop)] = EventLoopExecutor(eventLoop: eventLoop) } + self.executors = executors + } - let executors: [ObjectIdentifier: EventLoopExecutor] + subscript(eventLoop: EventLoop) -> EventLoopExecutor? { + return self.executors[ObjectIdentifier(eventLoop)] } -#endif // swift(>=6.0) + + let executors: [ObjectIdentifier: EventLoopExecutor] +} +#endif // swift(>=6.0) diff --git a/Sources/HummingbirdCore/Server/HTTP/HTTP1Channel.swift b/Sources/HummingbirdCore/Server/HTTP/HTTP1Channel.swift index a292d32bb..9a8efe112 100644 --- a/Sources/HummingbirdCore/Server/HTTP/HTTP1Channel.swift +++ b/Sources/HummingbirdCore/Server/HTTP/HTTP1Channel.swift @@ -46,13 +46,13 @@ public struct HTTP1Channel: ServerChildChannel, HTTPChannelHandler { public func setup(channel: Channel, logger: Logger) -> EventLoopFuture { let childChannelHandlers: [any ChannelHandler] = [HTTP1ToHTTPServerCodec(secure: false)] + self.additionalChannelHandlers() + [ - HTTPUserEventHandler(logger: logger) + HTTPUserEventHandler(logger: logger), ] return channel.eventLoop.makeCompletedFuture { try channel.pipeline.syncOperations.configureHTTPServerPipeline( - withPipeliningAssistance: false, // HTTP is pipelined by NIOAsyncChannel + withPipeliningAssistance: false, // HTTP is pipelined by NIOAsyncChannel withErrorHandling: true, - withOutboundHeaderValidation: false // Swift HTTP Types are already doing this validation + withOutboundHeaderValidation: false // Swift HTTP Types are already doing this validation ) try channel.pipeline.syncOperations.addHandlers(childChannelHandlers) return try NIOAsyncChannel( diff --git a/Sources/HummingbirdCore/Server/Server.swift b/Sources/HummingbirdCore/Server/Server.swift index 294784cb3..443bad83b 100644 --- a/Sources/HummingbirdCore/Server/Server.swift +++ b/Sources/HummingbirdCore/Server/Server.swift @@ -19,8 +19,8 @@ import NIOPosix import ServiceLifecycle #if canImport(Network) - import Network - import NIOTransportServices +import Network +import NIOTransportServices #endif /// HTTP server class @@ -115,8 +115,8 @@ public actor Server: Service { let logger = self.logger #if compiler(>=6.0) - let eventLoopExecutorMap = EventLoopExecutorMap( - eventLoopGroup: self.eventLoopGroup) + let eventLoopExecutorMap = EventLoopExecutorMap( + eventLoopGroup: self.eventLoopGroup) #endif // We can now start to handle our work. await withDiscardingTaskGroup { group in @@ -124,18 +124,21 @@ public actor Server: Service { try await asyncChannel.executeThenClose { inbound in for try await childChannel in inbound { #if compiler(>=6.0) - group.addTask( - executorPreference: eventLoopExecutorMap[ - childChannel.eventLoop] - ) { - await childChannelSetup.handle( - value: childChannel, logger: logger) - } + group.addTask( + executorPreference: eventLoopExecutorMap[ + childChannel.eventLoop + ] + ) { + await childChannelSetup.handle( + value: childChannel, logger: logger + ) + } #else - group.addTask { - await childChannelSetup.handle( - value: childChannel, logger: logger) - } + group.addTask { + await childChannelSetup.handle( + value: childChannel, logger: logger + ) + } #endif } } @@ -200,25 +203,25 @@ public actor Server: Service { { let bootstrap: ServerBootstrapProtocol #if canImport(Network) - if let tsBootstrap = self.createTSBootstrap(configuration: configuration) { - bootstrap = tsBootstrap - } else { - #if os(iOS) || os(tvOS) - self.logger.warning( - "Running BSD sockets on iOS or tvOS is not recommended. Please use NIOTSEventLoopGroup, to run with the Network framework" - ) - #endif - if configuration.tlsOptions.options != nil { - self.logger.warning( - "tlsOptions set in Configuration will not be applied to a BSD sockets server. Please use NIOTSEventLoopGroup, to run with the Network framework" - ) - } - bootstrap = self.createSocketsBootstrap(configuration: configuration) + if let tsBootstrap = self.createTSBootstrap(configuration: configuration) { + bootstrap = tsBootstrap + } else { + #if os(iOS) || os(tvOS) + self.logger.warning( + "Running BSD sockets on iOS or tvOS is not recommended. Please use NIOTSEventLoopGroup, to run with the Network framework" + ) + #endif + if configuration.tlsOptions.options != nil { + self.logger.warning( + "tlsOptions set in Configuration will not be applied to a BSD sockets server. Please use NIOTSEventLoopGroup, to run with the Network framework" + ) } + bootstrap = self.createSocketsBootstrap(configuration: configuration) + } #else - bootstrap = self.createSocketsBootstrap( - configuration: configuration - ) + bootstrap = self.createSocketsBootstrap( + configuration: configuration + ) #endif do { @@ -279,32 +282,32 @@ public actor Server: Service { } #if canImport(Network) - /// create a NIOTransportServices bootstrap using Network.framework - @available(macOS 10.14, iOS 12, tvOS 12, *) - private nonisolated func createTSBootstrap( - configuration: ServerConfiguration - ) -> NIOTSListenerBootstrap? { - guard - let bootstrap = NIOTSListenerBootstrap(validatingGroup: self.eventLoopGroup)? - .serverChannelOption( - ChannelOptions.socketOption(.so_reuseaddr), - value: configuration.reuseAddress ? 1 : 0 - ) - // Set the handlers that are applied to the accepted Channels - .childChannelOption( - ChannelOptions.socketOption(.so_reuseaddr), - value: configuration.reuseAddress ? 1 : 0 - ) - .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) - else { - return nil - } + /// create a NIOTransportServices bootstrap using Network.framework + @available(macOS 10.14, iOS 12, tvOS 12, *) + private nonisolated func createTSBootstrap( + configuration: ServerConfiguration + ) -> NIOTSListenerBootstrap? { + guard + let bootstrap = NIOTSListenerBootstrap(validatingGroup: self.eventLoopGroup)? + .serverChannelOption( + ChannelOptions.socketOption(.so_reuseaddr), + value: configuration.reuseAddress ? 1 : 0 + ) + // Set the handlers that are applied to the accepted Channels + .childChannelOption( + ChannelOptions.socketOption(.so_reuseaddr), + value: configuration.reuseAddress ? 1 : 0 + ) + .childChannelOption(ChannelOptions.allowRemoteHalfClosure, value: true) + else { + return nil + } - if let tlsOptions = configuration.tlsOptions.options { - return bootstrap.tlsOptions(tlsOptions) - } - return bootstrap + if let tlsOptions = configuration.tlsOptions.options { + return bootstrap.tlsOptions(tlsOptions) } + return bootstrap + } #endif } @@ -331,20 +334,20 @@ protocol ServerBootstrapProtocol { extension ServerBootstrap: ServerBootstrapProtocol {} #if canImport(Network) - @available(macOS 10.14, iOS 12, tvOS 12, *) - extension NIOTSListenerBootstrap: ServerBootstrapProtocol { - // need to be able to extend `NIOTSListenerBootstrap` to conform to `ServerBootstrapProtocol` - // before we can use TransportServices - func bind( - unixDomainSocketPath: String, - cleanupExistingSocketFile: Bool, - serverBackPressureStrategy: NIOAsyncSequenceProducerBackPressureStrategies - .HighLowWatermark?, - childChannelInitializer: @escaping @Sendable (Channel) -> EventLoopFuture - ) async throws -> NIOAsyncChannel { - preconditionFailure("Binding to a unixDomainSocketPath is currently not available") - } +@available(macOS 10.14, iOS 12, tvOS 12, *) +extension NIOTSListenerBootstrap: ServerBootstrapProtocol { + // need to be able to extend `NIOTSListenerBootstrap` to conform to `ServerBootstrapProtocol` + // before we can use TransportServices + func bind( + unixDomainSocketPath: String, + cleanupExistingSocketFile: Bool, + serverBackPressureStrategy: NIOAsyncSequenceProducerBackPressureStrategies + .HighLowWatermark?, + childChannelInitializer: @escaping @Sendable (Channel) -> EventLoopFuture + ) async throws -> NIOAsyncChannel { + preconditionFailure("Binding to a unixDomainSocketPath is currently not available") } +} #endif extension Server: CustomStringConvertible { diff --git a/Sources/HummingbirdHTTP2/HTTP2Channel.swift b/Sources/HummingbirdHTTP2/HTTP2Channel.swift index a54095254..c5429c470 100644 --- a/Sources/HummingbirdHTTP2/HTTP2Channel.swift +++ b/Sources/HummingbirdHTTP2/HTTP2Channel.swift @@ -61,7 +61,8 @@ public struct HTTP2UpgradeChannel: HTTPChannelHandler { self.sslContext = try NIOSSLContext(configuration: tlsConfiguration) self.additionalChannelHandlers = additionalChannelHandlers self.http1 = HTTP1Channel( - responder: responder, additionalChannelHandlers: additionalChannelHandlers) + responder: responder, additionalChannelHandlers: additionalChannelHandlers + ) } /// Setup child channel for HTTP1 with HTTP2 upgrade @@ -82,7 +83,7 @@ public struct HTTP2UpgradeChannel: HTTPChannelHandler { http1Channel -> EventLoopFuture in let childChannelHandlers: [ChannelHandler] = [HTTP1ToHTTPServerCodec(secure: false)] + self.additionalChannelHandlers() + [ - HTTPUserEventHandler(logger: logger) + HTTPUserEventHandler(logger: logger), ] return http1Channel @@ -100,7 +101,7 @@ public struct HTTP2UpgradeChannel: HTTPChannelHandler { } http2StreamInitializer: { http2ChildChannel -> EventLoopFuture in let childChannelHandlers: [ChannelHandler] = self.additionalChannelHandlers() + [ - HTTPUserEventHandler(logger: logger) + HTTPUserEventHandler(logger: logger), ] return http2ChildChannel