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

http provider cleanup #2120

Merged
merged 5 commits into from Dec 11, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
39 changes: 35 additions & 4 deletions Sources/Vapor/Application.swift
@@ -1,8 +1,9 @@
public protocol LockKey { }

public final class Application {
public var environment: Environment
public let eventLoopGroup: EventLoopGroup
public var storage: Storage
public let sync: Lock
public var userInfo: [AnyHashable: Any]
public private(set) var didShutdown: Bool
public var logger: Logger
Expand All @@ -20,21 +21,50 @@ public final class Application {
}
public var lifecycle: Lifecycle

public final class Locks {
public let main: Lock
var storage: [ObjectIdentifier: Lock]

init() {
self.main = .init()
self.storage = [:]
}

public func lock<Key>(for key: Key.Type) -> Lock
where Key: LockKey
{
self.main.lock()
defer { self.main.unlock() }
if let existing = self.storage[ObjectIdentifier(Key.self)] {
return existing
} else {
let new = Lock()
self.storage[ObjectIdentifier(Key.self)] = new
return new
}
}
}
public var locks: Locks
public var sync: Lock {
self.locks.main
}

public init(_ environment: Environment = .development) {
self.environment = environment
self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
self.storage = .init()
self.sync = .init()
self.locks = .init()
self.userInfo = [:]
self.didShutdown = false
self.logger = .init(label: "codes.vapor.application")
self.storage = .init(logger: self.logger)
self.lifecycle = .init()
self.isBooted = false
self.core.initialize()
self.views.initialize()
self.http.initialize()
self.sessions.initialize()
self.sessions.use(.memory)
self.commands.use(self.server.command, as: "serve", isDefault: true)
self.commands.use(RoutesCommand(), as: "routes")
}

public func run() throws {
Expand Down Expand Up @@ -86,6 +116,7 @@ public final class Application {
self.lifecycle.handlers = []

self.logger.trace("Clearing Application storage")
self.storage.shutdown()
self.storage.clear()
self.userInfo = [:]

Expand Down
64 changes: 64 additions & 0 deletions Sources/Vapor/Client/Application+Client.swift
@@ -0,0 +1,64 @@
extension Application {
public var client: Client {
.init(application: self)
}

public struct Client {
public var eventLoopGroup: EventLoopGroup {
self.application.eventLoopGroup
}

struct ConfigurationKey: StorageKey {
typealias Value = HTTPClient.Configuration
}

public var configuration: HTTPClient.Configuration {
get {
self.application.storage[ConfigurationKey.self] ?? .init()
}
nonmutating set {
if self.application.storage.contains(ClientKey.self) {
self.application.logger.warning("Cannot modify client configuration after client has been used")
}
self.application.storage[ConfigurationKey.self] = newValue
}
}

struct ClientKey: StorageKey, LockKey {
typealias Value = HTTPClient
}

public var http: HTTPClient {
if let existing = self.application.storage[ClientKey.self] {
return existing
} else {
let lock = self.application.locks.lock(for: ClientKey.self)
lock.lock()
defer { lock.unlock() }
if let existing = self.application.storage[ClientKey.self] {
return existing
}
let new = HTTPClient(
eventLoopGroupProvider: .shared(self.application.eventLoopGroup),
configuration: self.configuration
)
self.application.storage.set(ClientKey.self, to: new) {
try $0.syncShutdown()
}
return new
}
}

let application: Application
}
}

extension Application.Client: Client {
public func `for`(_ request: Request) -> Client {
RequestClient(http: self.http, req: request)
}

public func send(_ request: ClientRequest) -> EventLoopFuture<ClientResponse> {
self.http.send(request, eventLoop: .indifferent)
}
}
43 changes: 2 additions & 41 deletions Sources/Vapor/Client/HTTPClient+Client.swift
@@ -1,44 +1,5 @@
struct ApplicationClient: Client {
let http: HTTPClient

var eventLoopGroup: EventLoopGroup {
return self.http.eventLoopGroup
}

func `for`(_ request: Request) -> Client {
RequestClient(http: self.http, req: request)
}

func send(_ request: ClientRequest) -> EventLoopFuture<ClientResponse> {
return self.http.send(request, eventLoop: .indifferent)
}
}

extension Request {
public var client: Client {
return self.application.client.for(self)
}
}

struct RequestClient: Client {
let http: HTTPClient
let req: Request

var eventLoopGroup: EventLoopGroup {
return self.http.eventLoopGroup
}

func `for`(_ request: Request) -> Client {
RequestClient(http: self.http, req: request)
}

func send(_ request: ClientRequest) -> EventLoopFuture<ClientResponse> {
return self.http.send(request, eventLoop: .delegate(on: self.req.eventLoop))
}
}

private extension HTTPClient {
func send(
extension HTTPClient {
internal func send(
_ client: ClientRequest,
eventLoop: HTTPClient.EventLoopPreference
) -> EventLoopFuture<ClientResponse> {
Expand Down
22 changes: 22 additions & 0 deletions Sources/Vapor/Client/Request+Client.swift
@@ -0,0 +1,22 @@
extension Request {
public var client: Client {
return self.application.client.for(self)
}
}

struct RequestClient: Client {
let http: HTTPClient
let req: Request

var eventLoopGroup: EventLoopGroup {
return self.http.eventLoopGroup
}

func `for`(_ request: Request) -> Client {
RequestClient(http: self.http, req: request)
}

func send(_ request: ClientRequest) -> EventLoopFuture<ClientResponse> {
return self.http.send(request, eventLoop: .delegate(on: self.req.eventLoop))
}
}
11 changes: 10 additions & 1 deletion Sources/Vapor/HTTP/ApplicationResponder.swift
@@ -1,5 +1,14 @@
extension Application {
public var responder: Responder {
ApplicationResponder(
routes: self.routes,
middleware: self.middleware.resolve()
)
}
}

/// Vapor's main `Responder` type. Combines configured middleware + router to create a responder.
public struct ApplicationResponder: Responder {
internal struct ApplicationResponder: Responder {
private let responder: Responder

/// Creates a new `ApplicationResponder`.
Expand Down
118 changes: 0 additions & 118 deletions Sources/Vapor/HTTP/HTTP.swift

This file was deleted.

21 changes: 21 additions & 0 deletions Sources/Vapor/Middleware/Application+Middleware.swift
@@ -0,0 +1,21 @@
extension Application {
public var middleware: Middlewares {
get {
if let existing = self.storage[MiddlewaresKey.self] {
return existing
} else {
var new = Middlewares()
new.use(ErrorMiddleware.default(environment: self.environment))
self.storage[MiddlewaresKey.self] = new
return new
}
}
set {
self.storage[MiddlewaresKey.self] = newValue
}
}

private struct MiddlewaresKey: StorageKey {
typealias Value = Middlewares
}
}
15 changes: 15 additions & 0 deletions Sources/Vapor/Routing/Application+Routes.swift
@@ -0,0 +1,15 @@
extension Application {
public var routes: Routes {
if let existing = self.storage[RoutesKey.self] {
return existing
} else {
let new = Routes()
self.storage[RoutesKey.self] = new
return new
}
}

private struct RoutesKey: StorageKey {
typealias Value = Routes
}
}