Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Application Context #308

Merged
merged 3 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ protocol BenchmarkContext: HBBaseRequestContext {
/// - source: Source of request context
/// - logger: Logger
init(
applicationContext: HBApplicationContext,
eventLoop: EventLoop,
allocator: ByteBufferAllocator,
logger: Logger
Expand All @@ -40,12 +39,11 @@ struct BasicBenchmarkContext: BenchmarkContext {
var coreContext: HBCoreRequestContext

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)
}
}

Expand All @@ -67,12 +65,15 @@ extension Benchmark {
let router = HBRouter(context: Context.self)
self.init(name, configuration: configuration) { benchmark in
let responder = router.buildResponder()
let applicationContext = HBApplicationContext(configuration: .init())
benchmark.startMeasurement()

try await withThrowingTaskGroup(of: Void.self) { group in
for _ in benchmark.scaledIterations {
let context = Context(applicationContext: applicationContext, eventLoop: MultiThreadedEventLoopGroup.singleton.any(), allocator: ByteBufferAllocator(), logger: Logger(label: "Benchmark"))
let context = Context(
eventLoop: MultiThreadedEventLoopGroup.singleton.any(),
allocator: ByteBufferAllocator(),
logger: Logger(label: "Benchmark")
)
let requestBodyStream = HBStreamedRequestBody()
let requestBody = HBRequestBody.stream(requestBodyStream)
let hbRequest = HBRequest(head: request, body: requestBody)
Expand Down
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
22 changes: 11 additions & 11 deletions Sources/Hummingbird/Middleware/TracingMiddleware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ import Tracing
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddlewareProtocol {
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
/// are being recorded.
public init(recordingHeaders headerNamesToRecord: some Collection<HTTPField.Name>) {
/// - Parameters
/// - recordingHeaders: A list of HTTP header names to be recorded as span attributes. By default, no headers
adam-fowler marked this conversation as resolved.
Show resolved Hide resolved
/// are being recorded.
/// - parameters: A list of static parameters added to every span. These could be the "net.host.name",
/// "net.host.port" or "http.scheme"
public init(recordingHeaders headerNamesToRecord: some Collection<HTTPField.Name> = [], attributes: SpanAttributes? = nil) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is not related to the application context change

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related, in that when we remove the application context we don't have access to some of the application configuration, so cannot update some attributes eg "net.host.name" and "net.host.port". My solution was to allow the user to add some static attributes to the middleware itself.

self.headerNamesToRecord = Set(headerNamesToRecord.map(RecordingHeader.init))
}

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

public func handle(_ request: HBRequest, context: Context, next: (HBRequest, Context) async throws -> HBResponse) async throws -> HBResponse {
Expand All @@ -52,6 +52,9 @@ public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddlewarePr

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 +63,6 @@ public struct HBTracingMiddleware<Context: HBBaseRequestContext>: HBMiddlewarePr
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
Loading
Loading