Skip to content

Commit

Permalink
Remove Application Context
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-fowler committed Dec 13, 2023
1 parent 44c945e commit 620fd44
Show file tree
Hide file tree
Showing 11 changed files with 37 additions and 83 deletions.
15 changes: 0 additions & 15 deletions Sources/Hummingbird/Application.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,6 @@ public enum EventLoopGroupProvider {
}
}

public final class HBApplicationContext: Sendable {
/// Configuration
public let configuration: HBApplicationConfiguration

public init(
configuration: HBApplicationConfiguration
) {
self.configuration = configuration
}
}

public protocol HBApplicationProtocol: Service where Context: HBRequestContext {
/// Responder that generates a response from a requests and context
associatedtype Responder: HBResponder
Expand Down Expand Up @@ -107,11 +96,7 @@ extension HBApplicationProtocol {

// Function responding to HTTP request
@Sendable func respond(to request: HBRequest, channel: Channel) async throws -> HBResponse {
let applicationContext = HBApplicationContext(
configuration: self.configuration
)
let context = Self.Responder.Context(
applicationContext: applicationContext,
channel: channel,
logger: loggerWithRequestId(self.logger)
)
Expand Down
11 changes: 0 additions & 11 deletions Sources/Hummingbird/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ public struct HBApplicationConfiguration: Sendable {
public let address: HBBindAddress
/// Server name to return in "server" header
public let serverName: String?
/// Maximum upload size allowed for routes that don't stream the request payload. This
/// limits how much memory would be used for one request
public let maxUploadSize: Int
/// Defines the maximum length for the queue of pending connections
public let backlog: Int
/// Allows socket to be bound to an address that is already in use.
Expand All @@ -53,7 +50,6 @@ public struct HBApplicationConfiguration: Sendable {
/// - Parameters:
/// - address: Bind address for server
/// - serverName: Server name to return in "server" header
/// - maxUploadSize: Maximum upload size allowed for routes that don't stream the request payload
/// - backlog: the maximum length for the queue of pending connections. If a connection request arrives with the queue full,
/// the client may receive an error with an indication of ECONNREFUSE
/// - reuseAddress: Allows socket to be bound to an address that is already in use.
Expand All @@ -62,7 +58,6 @@ public struct HBApplicationConfiguration: Sendable {
public init(
address: HBBindAddress = .hostname(),
serverName: String? = nil,
maxUploadSize: Int = 1 * 1024 * 1024,
backlog: Int = 256,
reuseAddress: Bool = true,
threadPoolSize: Int = 2,
Expand All @@ -73,7 +68,6 @@ public struct HBApplicationConfiguration: Sendable {

self.address = address
self.serverName = serverName
self.maxUploadSize = maxUploadSize
self.backlog = backlog
self.reuseAddress = reuseAddress
#if canImport(Network)
Expand All @@ -97,15 +91,13 @@ public struct HBApplicationConfiguration: Sendable {
/// - Parameters:
/// - address: Bind address for server
/// - serverName: Server name to return in "server" header
/// - maxUploadSize: Maximum upload size allowed for routes that don't stream the request payload
/// - reuseAddress: Allows socket to be bound to an address that is already in use.
/// - logLevel: Logging level
/// - noHTTPServer: Don't start up the HTTP server.
/// - tlsOptions: TLS options for when you are using NIOTransportServices
public init(
address: HBBindAddress = .hostname(),
serverName: String? = nil,
maxUploadSize: Int = 1 * 1024 * 1024,
reuseAddress: Bool = true,
logLevel: Logger.Level? = nil,
noHTTPServer: Bool = false,
Expand All @@ -115,7 +107,6 @@ public struct HBApplicationConfiguration: Sendable {

self.address = address
self.serverName = serverName
self.maxUploadSize = maxUploadSize
self.backlog = 256 // not used by Network framework
self.reuseAddress = reuseAddress
self.tlsOptions = tlsOptions
Expand All @@ -137,15 +128,13 @@ public struct HBApplicationConfiguration: Sendable {
public func with(
address: HBBindAddress? = nil,
serverName: String? = nil,
maxUploadSize: Int? = nil,
backlog: Int? = nil,
reuseAddress: Bool? = nil,
logLevel: Logger.Level? = nil
) -> Self {
return .init(
address: address ?? self.address,
serverName: serverName ?? self.serverName,
maxUploadSize: maxUploadSize ?? self.maxUploadSize,
backlog: backlog ?? self.backlog,
reuseAddress: reuseAddress ?? self.reuseAddress,
logLevel: logLevel ?? self.logLevel
Expand Down
19 changes: 9 additions & 10 deletions Sources/Hummingbird/Middleware/TracingMiddleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ import Tracing
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddleware {
private let headerNamesToRecord: Set<RecordingHeader>
private let attributes: SpanAttributes?

/// Intialize a new HBTracingMiddleware.
///
/// - Parameter recordingHeaders: A list of HTTP header names to be recorded as span attributes. By default, no headers
/// - Parameters
/// - recordingHeaders: A list of HTTP header names to be recorded as span attributes. By default, no headers
/// - parameters: A list of static parameters added to every span. These could be
/// are being recorded.
public init(recordingHeaders headerNamesToRecord: some Collection<HTTPField.Name>) {
public init(recordingHeaders headerNamesToRecord: some Collection<HTTPField.Name> = [], attributes: SpanAttributes? = nil) {
self.headerNamesToRecord = Set(headerNamesToRecord.map(RecordingHeader.init))
}

/// Intialize a new HBTracingMiddleware.
public init() {
self.init(recordingHeaders: [])
self.attributes = attributes
}

public func apply(to request: HBRequest, context: Context, next: any HBResponder<Context>) async throws -> HBResponse {
Expand All @@ -52,6 +51,9 @@ public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddleware {

return try await InstrumentationSystem.tracer.withSpan(operationName, context: serviceContext, ofKind: .server) { span in
span.updateAttributes { attributes in
if let staticAttributes = self.attributes {
attributes.merge(staticAttributes)
}
attributes["http.method"] = request.method.rawValue
attributes["http.target"] = request.uri.path
// TODO: Get HTTP version and scheme
Expand All @@ -60,9 +62,6 @@ public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddleware {
attributes["http.user_agent"] = request.headers[.userAgent]
attributes["http.request_content_length"] = request.headers[.contentLength].map { Int($0) } ?? nil

attributes["net.host.name"] = context.applicationContext.configuration.address.host
attributes["net.host.port"] = context.applicationContext.configuration.address.port

if let remoteAddress = (context as? HBRemoteAddressRequestContext)?.remoteAddress {
attributes["net.sock.peer.port"] = remoteAddress.port

Expand Down
19 changes: 8 additions & 11 deletions Sources/Hummingbird/Server/RequestContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,6 @@ public struct EndpointPath: Sendable {

/// Request context values required by Hummingbird itself.
public struct HBCoreRequestContext: Sendable {
/// Application context
@usableFromInline
let applicationContext: HBApplicationContext
/// Request decoder
@usableFromInline
var requestDecoder: HBRequestDecoder
Expand All @@ -63,14 +60,12 @@ public struct HBCoreRequestContext: Sendable {

@inlinable
public init(
applicationContext: HBApplicationContext,
requestDecoder: HBRequestDecoder = NullDecoder(),
responseEncoder: HBResponseEncoder = NullEncoder(),
eventLoop: EventLoop,
allocator: ByteBufferAllocator,
logger: Logger
) {
self.applicationContext = applicationContext
self.requestDecoder = requestDecoder
self.responseEncoder = responseEncoder
self.eventLoop = eventLoop
Expand All @@ -88,12 +83,12 @@ public protocol HBBaseRequestContext: Sendable {
var coreContext: HBCoreRequestContext { get set }
/// Thread Pool
var threadPool: NIOThreadPool { get }
/// Maximum upload size allowed for routes that don't stream the request payload. This
/// limits how much memory would be used for one request
var maxUploadSize: Int { get }
}

extension HBBaseRequestContext {
/// Application context
@inlinable
public var applicationContext: HBApplicationContext { coreContext.applicationContext }
/// Request decoder
@inlinable
public var requestDecoder: HBRequestDecoder { coreContext.requestDecoder }
Expand All @@ -118,6 +113,9 @@ extension HBBaseRequestContext {
set { coreContext.logger = newValue }
}

/// maxUploadSize
@inlinable
public var maxUploadSize: Int { 2 * 1024 * 1024 }
/// Endpoint path
@inlinable
public var endpointPath: String? { coreContext.endpointPath.value }
Expand All @@ -136,7 +134,7 @@ public protocol HBRequestContext: HBBaseRequestContext {
/// - applicationContext: Context coming from Application
/// - channel: Channel that created request and context
/// - logger: Logger to use with request
init(applicationContext: HBApplicationContext, channel: Channel, logger: Logger)
init(channel: Channel, logger: Logger)
}

/// Implementation of a basic request context that supports everything the Hummingbird library needs
Expand All @@ -150,10 +148,9 @@ public struct HBBasicRequestContext: HBRequestContext {
/// - source: Source of request context
/// - logger: Logger
public init(
applicationContext: HBApplicationContext,
channel: Channel,
logger: Logger
) {
self.coreContext = .init(applicationContext: applicationContext, eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger)
self.coreContext = .init(eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension JSONDecoder: HBRequestDecoder {
/// - type: Type to decode
/// - request: Request to decode from
public func decode<T: Decodable>(_ type: T.Type, from request: HBRequest, context: some HBBaseRequestContext) async throws -> T {
let buffer = try await request.body.collect(upTo: context.applicationContext.configuration.maxUploadSize)
let buffer = try await request.body.collect(upTo: context.maxUploadSize)
return try self.decode(T.self, from: buffer)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension URLEncodedFormDecoder: HBRequestDecoder {
/// - type: Type to decode
/// - request: Request to decode from
public func decode<T: Decodable>(_ type: T.Type, from request: HBRequest, context: some HBBaseRequestContext) async throws -> T {
let buffer = try await request.body.collect(upTo: context.applicationContext.configuration.maxUploadSize)
let buffer = try await request.body.collect(upTo: context.maxUploadSize)
let string = String(buffer: buffer)
return try self.decode(T.self, from: string)
}
Expand Down
13 changes: 1 addition & 12 deletions Sources/HummingbirdXCT/HBXCTRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import Tracing

public protocol HBTestRequestContextProtocol: HBRequestContext {
init(
applicationContext: HBApplicationContext,
eventLoop: EventLoop,
allocator: ByteBufferAllocator,
logger: Logger
Expand All @@ -33,12 +32,10 @@ public protocol HBTestRequestContextProtocol: HBRequestContext {

extension HBTestRequestContextProtocol {
public init(
applicationContext: HBApplicationContext,
channel: Channel,
logger: Logger
) {
self.init(
applicationContext: applicationContext,
eventLoop: channel.eventLoop,
allocator: channel.allocator,
logger: logger
Expand All @@ -48,13 +45,11 @@ extension HBTestRequestContextProtocol {

public struct HBTestRouterContext: HBTestRequestContextProtocol {
public init(
applicationContext: HBApplicationContext,
eventLoop: EventLoop,
allocator: ByteBufferAllocator,
logger: Logger
) {
self.coreContext = .init(
applicationContext: applicationContext,
eventLoop: eventLoop,
allocator: allocator,
logger: logger
Expand All @@ -68,22 +63,18 @@ public struct HBTestRouterContext: HBTestRequestContextProtocol {
/// Test sending values to requests to router. This does not setup a live server
struct HBXCTRouter<Responder: HBResponder>: HBXCTApplication where Responder.Context: HBTestRequestContextProtocol {
let eventLoopGroup: EventLoopGroup
let context: HBApplicationContext
let responder: Responder
let logger: Logger

init<App: HBApplicationProtocol>(app: App) async throws where App.Responder == Responder {
self.eventLoopGroup = app.eventLoopGroup
self.context = HBApplicationContext(
configuration: app.configuration
)
self.responder = try await app.buildResponder()
self.logger = app.logger
}

/// Run test
func run<Value>(_ test: @escaping @Sendable (HBXCTClientProtocol) async throws -> Value) async throws -> Value {
let client = Client(eventLoopGroup: self.eventLoopGroup, responder: self.responder, applicationContext: self.context, logger: self.logger)
let client = Client(eventLoopGroup: self.eventLoopGroup, responder: self.responder, logger: self.logger)
let value = try await test(client)
return value
}
Expand All @@ -93,7 +84,6 @@ struct HBXCTRouter<Responder: HBResponder>: HBXCTApplication where Responder.Con
struct Client: HBXCTClientProtocol {
let eventLoopGroup: EventLoopGroup
let responder: Responder
let applicationContext: HBApplicationContext
let logger: Logger

func execute(uri: String, method: HTTPRequest.Method, headers: HTTPFields, body: ByteBuffer?) async throws -> HBXCTResponse {
Expand All @@ -106,7 +96,6 @@ struct HBXCTRouter<Responder: HBResponder>: HBXCTApplication where Responder.Con
body: .stream(streamer)
)
let context = Responder.Context(
applicationContext: self.applicationContext,
eventLoop: eventLoop,
allocator: ByteBufferAllocator(),
logger: loggerWithRequestId(self.logger)
Expand Down
3 changes: 1 addition & 2 deletions Sources/PerformanceTest/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ import NIOPosix
struct PerformanceTestRequestContext: HBRequestContext {
var coreContext: HBCoreRequestContext

init(applicationContext: HBApplicationContext, channel: Channel, logger: Logger) {
init(channel: Channel, logger: Logger) {
self.coreContext = .init(
applicationContext: applicationContext,
requestDecoder: JSONDecoder(),
responseEncoder: JSONEncoder(),
eventLoop: channel.eventLoop,
Expand Down
21 changes: 14 additions & 7 deletions Tests/HummingbirdTests/ApplicationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ final class ApplicationTests: XCTestCase {
let buffer = try await request.body.collect(upTo: .max)
return .init(status: .ok, headers: [:], body: .init(byteBuffer: buffer))
}
let app = HBApplication(responder: router.buildResponder(), configuration: .init(maxUploadSize: 2 * 1024 * 1024))
let app = HBApplication(responder: router.buildResponder())
try await app.test(.router) { client in

let buffer = self.randomBuffer(size: 1_140_000)
Expand Down Expand Up @@ -271,7 +271,7 @@ final class ApplicationTests: XCTestCase {
struct CollateMiddleware<Context: HBBaseRequestContext>: HBMiddleware {
func apply(to request: HBRequest, context: Context, next: any HBResponder<Context>) async throws -> HBResponse {
var request = request
request.body = try await request.body.collate(maxSize: context.applicationContext.configuration.maxUploadSize)
request.body = try await request.body.collate(maxSize: context.maxUploadSize)
return try await next.respond(to: request, context: context)
}
}
Expand Down Expand Up @@ -386,15 +386,23 @@ final class ApplicationTests: XCTestCase {
}

func testMaxUploadSize() async throws {
let router = HBRouter()
struct MaxUploadRequestContext: HBRequestContext {
init(channel: Channel, logger: Logger) {
self.coreContext = .init(eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger)
}

var coreContext: HBCoreRequestContext
var maxUploadSize: Int { 64 * 1024 }
}
let router = HBRouter(context: MaxUploadRequestContext.self)
router.post("upload") { request, context in
_ = try await request.body.collate(maxSize: context.applicationContext.configuration.maxUploadSize)
_ = try await request.body.collate(maxSize: context.maxUploadSize)
return "ok"
}
router.post("stream") { _, _ in
"ok"
}
let app = HBApplication(responder: router.buildResponder(), configuration: .init(maxUploadSize: 64 * 1024))
let app = HBApplication(responder: router.buildResponder())
try await app.test(.live) { client in
let buffer = self.randomBuffer(size: 128 * 1024)
// check non streamed route throws an error
Expand All @@ -417,11 +425,10 @@ final class ApplicationTests: XCTestCase {
let remoteAddress: SocketAddress?

public init(
applicationContext: HBApplicationContext,
channel: Channel,
logger: Logger
) {
self.coreContext = .init(applicationContext: applicationContext, eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger)
self.coreContext = .init(eventLoop: channel.eventLoop, allocator: channel.allocator, logger: logger)
self.remoteAddress = channel.remoteAddress
}
}
Expand Down
3 changes: 1 addition & 2 deletions Tests/HummingbirdTests/RouterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,11 @@ final class RouterTests: XCTestCase {

public struct HBTestRouterContext2: HBTestRequestContextProtocol {
public init(
applicationContext: HBApplicationContext,
eventLoop: EventLoop,
allocator: ByteBufferAllocator,
logger: Logger
) {
self.coreContext = .init(applicationContext: applicationContext, eventLoop: eventLoop, allocator: allocator, logger: logger)
self.coreContext = .init(eventLoop: eventLoop, allocator: allocator, logger: logger)
self.string = ""
}

Expand Down
Loading

0 comments on commit 620fd44

Please sign in to comment.