forked from vapor/postgres-nio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPostgresMessageDecoder.swift
66 lines (53 loc) · 2.51 KB
/
PostgresMessageDecoder.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import NIOCore
import Logging
@available(*, deprecated, message: "Will be removed from public API")
public final class PostgresMessageDecoder: ByteToMessageDecoder {
/// See `ByteToMessageDecoder`.
public typealias InboundOut = PostgresMessage
/// See `ByteToMessageDecoder`.
public var cumulationBuffer: ByteBuffer?
/// If `true`, the server has asked for authentication.
public var hasSeenFirstMessage: Bool
/// Logger to send debug messages to.
let logger: Logger?
/// Creates a new `PostgresMessageDecoder`.
public init(logger: Logger? = nil) {
self.hasSeenFirstMessage = false
self.logger = logger
}
/// See `ByteToMessageDecoder`.
public func decode(context: ChannelHandlerContext, buffer: inout ByteBuffer) throws -> DecodingState {
var peekBuffer = buffer
// peek at the message identifier
// the message identifier is always the first byte of a message
guard let identifier = peekBuffer.readInteger(as: UInt8.self).map(PostgresMessage.Identifier.init) else {
return .needMoreData
}
let message: PostgresMessage
// special ssl case, no body
if !self.hasSeenFirstMessage && (identifier == .sslSupported || identifier == .sslUnsupported) {
message = PostgresMessage(identifier: identifier, data: context.channel.allocator.buffer(capacity: 0))
} else {
// peek at the message size
// the message size is always a 4 byte integer appearing immediately after the message identifier
guard let messageSize = peekBuffer.readInteger(as: Int32.self).flatMap(Int.init) else {
return .needMoreData
}
// ensure message is large enough (skipping message type) or reject
guard let data = peekBuffer.readSlice(length: messageSize - 4) else {
return .needMoreData
}
message = PostgresMessage(identifier: identifier, data: data)
}
self.hasSeenFirstMessage = true
// there is sufficient data, use this buffer
buffer = peekBuffer
self.logger?.trace("Decoded: PostgresMessage (\(message.identifier))")
context.fireChannelRead(wrapInboundOut(message))
return .continue
}
public func decodeLast(context: ChannelHandlerContext, buffer: inout ByteBuffer, seenEOF: Bool) throws -> DecodingState {
// ignore
return .needMoreData
}
}