Skip to content

Commit 305e2d2

Browse files
authored
proposal feedback (#26)
* add swift log / metrics * remove PostgresConnection.requestTLS * make error code's camelCase * remove tableoid from PostgresRow * update PostgresRequest protocol * remove test prints * only run perf tests in release mode * rebuild test linuxmain * add psql db to perf tests * bump
1 parent 7328388 commit 305e2d2

19 files changed

+595
-482
lines changed

Package.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ let package = Package(
1010
dependencies: [
1111
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
1212
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.0.0"),
13+
.package(url: "https://github.com/apple/swift-metrics.git", from: "1.0.0-a"),
14+
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
1315
],
1416
targets: [
1517
.target(name: "CMD5", dependencies: []),
16-
.target(name: "NIOPostgres", dependencies: ["CMD5", "NIO", "NIOSSL"]),
18+
.target(name: "NIOPostgres", dependencies: ["CMD5", "Logging", "Metrics", "NIO", "NIOSSL"]),
1719
.target(name: "NIOPostgresBenchmark", dependencies: ["NIOPostgres"]),
1820
.testTarget(name: "NIOPostgresTests", dependencies: ["NIOPostgres"]),
1921
]

Sources/NIOPostgres/Connection/PostgresDatabase+Query.swift renamed to Sources/NIOPostgres/Connection/PostgresClient+Query.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIO
2+
import Logging
23

34
extension PostgresClient {
45
public func query(_ string: String, _ binds: [PostgresData] = []) -> EventLoopFuture<[PostgresRow]> {
@@ -14,7 +15,7 @@ extension PostgresClient {
1415

1516
// MARK: Private
1617

17-
private final class PostgresParameterizedQuery: PostgresRequestHandler {
18+
private final class PostgresParameterizedQuery: PostgresRequest {
1819
let query: String
1920
let binds: [PostgresData]
2021
var onRow: (PostgresRow) throws -> ()
@@ -32,7 +33,14 @@ private final class PostgresParameterizedQuery: PostgresRequestHandler {
3233
self.resultFormatCodes = [.binary]
3334
}
3435

36+
func log(to logger: Logger) {
37+
logger.debug("\(self.query) \(self.binds)")
38+
}
39+
3540
func respond(to message: PostgresMessage) throws -> [PostgresMessage]? {
41+
if case .error = message.identifier {
42+
return nil
43+
}
3644
switch message.identifier {
3745
case .bindComplete:
3846
return []
@@ -57,6 +65,8 @@ private final class PostgresParameterizedQuery: PostgresRequestHandler {
5765
return []
5866
case .commandComplete:
5967
return []
68+
case .notice:
69+
return []
6070
case .readyForQuery:
6171
return nil
6272
default: throw PostgresError.protocol("Unexpected message during query: \(message)")

Sources/NIOPostgres/Connection/PostgresDatabase+SimpleQuery.swift renamed to Sources/NIOPostgres/Connection/PostgresClient+SimpleQuery.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import NIO
2+
import Logging
23

34
extension PostgresClient {
45
public func simpleQuery(_ string: String) -> EventLoopFuture<[PostgresRow]> {
@@ -14,7 +15,7 @@ extension PostgresClient {
1415

1516
// MARK: Private
1617

17-
private final class PostgresSimpleQuery: PostgresRequestHandler {
18+
private final class PostgresSimpleQuery: PostgresRequest {
1819
var query: String
1920
var onRow: (PostgresRow) throws -> ()
2021
var rowLookupTable: PostgresRow.LookupTable?
@@ -24,7 +25,14 @@ private final class PostgresSimpleQuery: PostgresRequestHandler {
2425
self.onRow = onRow
2526
}
2627

28+
func log(to logger: Logger) {
29+
logger.debug("\(self.query)")
30+
}
31+
2732
func respond(to message: PostgresMessage) throws -> [PostgresMessage]? {
33+
if case .error = message.identifier {
34+
return nil
35+
}
2836
switch message.identifier {
2937
case .dataRow:
3038
let data = try PostgresMessage.DataRow(message: message)
@@ -43,6 +51,8 @@ private final class PostgresSimpleQuery: PostgresRequestHandler {
4351
return []
4452
case .readyForQuery:
4553
return nil
54+
case .notice:
55+
return []
4656
default:
4757
throw PostgresError.protocol("Unexpected message during simple query: \(message)")
4858
}
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
#warning("TODO: make this protocol more general, not depend on PostgresRequestHandler")
21
public protocol PostgresClient {
32
var eventLoop: EventLoop { get }
4-
func send(_ request: PostgresRequestHandler) -> EventLoopFuture<Void>
3+
func send(_ request: PostgresRequest) -> EventLoopFuture<Void>
54
}
6-
7-
extension PostgresConnection: PostgresClient { }

Sources/NIOPostgres/Connection/PostgresConnection+Authenticate.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import CMD5
22
import NIO
3+
import Logging
34

45
extension PostgresConnection {
56
public func authenticate(username: String, database: String? = nil, password: String? = nil) -> EventLoopFuture<Void> {
@@ -14,7 +15,7 @@ extension PostgresConnection {
1415

1516
// MARK: Private
1617

17-
private final class PostgresAuthenticationRequest: PostgresRequestHandler {
18+
private final class PostgresAuthenticationRequest: PostgresRequest {
1819
enum State {
1920
case ready
2021
case done
@@ -25,18 +26,23 @@ private final class PostgresAuthenticationRequest: PostgresRequestHandler {
2526
let password: String?
2627
var state: State
2728

28-
var errorMessageIsFinal: Bool {
29-
return true
30-
}
31-
3229
init(username: String, database: String?, password: String?) {
3330
self.state = .ready
3431
self.username = username
3532
self.database = database
3633
self.password = password
3734
}
3835

36+
func log(to logger: Logger) {
37+
logger.debug("Logging into Postgres db \(self.database ?? "nil") as \(self.username)")
38+
}
39+
3940
func respond(to message: PostgresMessage) throws -> [PostgresMessage]? {
41+
if case .error = message.identifier {
42+
// terminate immediately on error
43+
return nil
44+
}
45+
4046
switch self.state {
4147
case .ready:
4248
switch message.identifier {
Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,49 @@
1+
import Logging
12
import NIO
23

34
extension PostgresConnection {
4-
public static func connect(to socketAddress: SocketAddress, on eventLoop: EventLoop) -> EventLoopFuture<PostgresConnection> {
5+
public static func connect(
6+
to socketAddress: SocketAddress,
7+
tlsConfiguration: TLSConfiguration? = nil,
8+
serverHostname: String? = nil,
9+
on eventLoop: EventLoop
10+
) -> EventLoopFuture<PostgresConnection> {
511
let bootstrap = ClientBootstrap(group: eventLoop)
612
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR), value: 1)
713

14+
let logger = Logger(label: "codes.vapor.nio-postgres")
815
return bootstrap.connect(to: socketAddress).flatMap { channel in
916
return channel.pipeline.addHandlers([
1017
ByteToMessageHandler(PostgresMessageDecoder()),
1118
MessageToByteHandler(PostgresMessageEncoder()),
12-
PostgresConnectionHandler(),
19+
PostgresRequestHandler(logger: logger),
20+
PostgresErrorHandler(logger: logger)
1321
]).map {
14-
return .init(channel: channel)
22+
return PostgresConnection(channel: channel, logger: logger)
23+
}
24+
}.flatMap { conn in
25+
if let tlsConfiguration = tlsConfiguration {
26+
return conn.requestTLS(using: tlsConfiguration, serverHostname: serverHostname)
27+
.map { conn }
28+
} else {
29+
return eventLoop.makeSucceededFuture(conn)
1530
}
1631
}
1732
}
1833
}
34+
35+
36+
private final class PostgresErrorHandler: ChannelInboundHandler {
37+
typealias InboundIn = Never
38+
39+
let logger: Logger
40+
init(logger: Logger) {
41+
self.logger = logger
42+
}
43+
44+
func errorCaught(context: ChannelHandlerContext, error: Error) {
45+
self.logger.error("Uncaught error: \(error)")
46+
context.close(promise: nil)
47+
context.fireErrorCaught(error)
48+
}
49+
}

Sources/NIOPostgres/Connection/PostgresConnection+RequestTLS.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
import NIOSSL
2+
import Logging
23

34
extension PostgresConnection {
4-
public func requestTLS(using tlsConfig: TLSConfiguration, serverHostname: String?) -> EventLoopFuture<Bool> {
5+
internal func requestTLS(using tlsConfig: TLSConfiguration, serverHostname: String?) -> EventLoopFuture<Void> {
56
let tls = RequestTLSQuery()
67
return self.send(tls).flatMapThrowing { _ in
7-
if tls.isSupported {
8-
let sslContext = try NIOSSLContext(configuration: tlsConfig)
9-
let handler = try NIOSSLClientHandler(context: sslContext, serverHostname: serverHostname)
10-
_ = self.channel.pipeline.addHandler(handler, position: .first)
8+
guard tls.isSupported else {
9+
throw PostgresError.protocol("Server does not support TLS")
1110
}
12-
return tls.isSupported
11+
let sslContext = try NIOSSLContext(configuration: tlsConfig)
12+
let handler = try NIOSSLClientHandler(context: sslContext, serverHostname: serverHostname)
13+
_ = self.channel.pipeline.addHandler(handler, position: .first)
1314
}
1415
}
1516
}
1617

1718
// MARK: Private
1819

19-
private final class RequestTLSQuery: PostgresRequestHandler {
20+
private final class RequestTLSQuery: PostgresRequest {
2021
var isSupported: Bool
2122

2223
init() {
2324
self.isSupported = false
2425
}
2526

27+
func log(to logger: Logger) {
28+
logger.debug("Requesting TLS")
29+
}
30+
2631
func respond(to message: PostgresMessage) throws -> [PostgresMessage]? {
2732
switch message.identifier {
2833
case .sslSupported:

Sources/NIOPostgres/Connection/PostgresConnection.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import Foundation
2+
import Logging
3+
24
public final class PostgresConnection {
3-
// #warning("publicize these values?")
4-
// public var status: [String: String]
5-
// var processID: Int32?
6-
// var secretKey: Int32?
75
let channel: Channel
86

97
public var eventLoop: EventLoop {
@@ -14,18 +12,20 @@ public final class PostgresConnection {
1412
return channel.closeFuture
1513
}
1614

17-
init(channel: Channel) {
15+
public var logger: Logger
16+
17+
init(channel: Channel, logger: Logger) {
1818
self.channel = channel
19+
self.logger = logger
1920
}
2021

2122
public func close() -> EventLoopFuture<Void> {
2223
guard self.channel.isActive else {
2324
return self.eventLoop.makeSucceededFuture(())
2425
}
25-
return self.channel.close(mode: .all)
26+
return self.channel.close()
2627
}
2728

28-
#warning("TODO: add error handler that closes connection")
2929
deinit {
3030
if self.channel.isActive {
3131
assertionFailure("PostgresConnection deinitialized before being closed.")

0 commit comments

Comments
 (0)