Skip to content

Commit 6b77031

Browse files
committed
Update builder API to use grpc-swift-2.
- Closes apple#1308. - Applies dependency and code changes similar to apple/containerization#578. - Upgrades hawkeye to latest version. - Update StderrLogHandler not to create a (non-Sendable) Swift time formatter object for every log message.
1 parent 8dafe3e commit 6b77031

5 files changed

Lines changed: 111 additions & 30 deletions

File tree

Package.resolved

Lines changed: 33 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ let package = Package(
5252
.package(url: "https://github.com/apple/swift-collections.git", from: "1.2.0"),
5353
.package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),
5454
.package(url: "https://github.com/apple/swift-nio.git", from: "2.80.0"),
55-
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.34.1"),
56-
.package(url: "https://github.com/apple/swift-system.git", from: "1.4.0"),
55+
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.36.0"),
56+
.package(url: "https://github.com/apple/swift-system.git", from: "1.6.4"),
5757
.package(url: "https://github.com/Bouke/DNS.git", from: "1.2.0"),
58-
.package(url: "https://github.com/grpc/grpc-swift-2.git", from: "2.2.1"),
59-
.package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "2.1.2"),
60-
.package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "2.2.0"),
58+
.package(url: "https://github.com/grpc/grpc-swift-2.git", from: "2.3.0"),
59+
.package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "2.4.4"),
60+
.package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "2.2.0"),
6161
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.20.1"),
6262
.package(url: "https://github.com/swiftlang/swift-docc-plugin.git", from: "1.1.0"),
6363
],

Sources/ContainerBuild/Builder.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import GRPCCore
2323
import GRPCNIOTransportHTTP2
2424
import Logging
2525
import NIO
26+
import NIOCore
2627
import NIOHPACK
2728
import NIOHTTP2
2829
import NIOPosix
@@ -42,6 +43,11 @@ public struct Builder: Sendable {
4243
try socket.setRecvBufSize(2 << 20)
4344

4445
let channel = try ClientBootstrap(group: group)
46+
.channelInitializer { channel in
47+
channel.eventLoop.makeCompletedFuture(withResultOf: {
48+
try channel.pipeline.syncOperations.addHandler(HTTP2ConnectBufferingHandler())
49+
})
50+
}
4551
.withConnectedSocket(socket.fileDescriptor)
4652
.wait()
4753

@@ -407,3 +413,49 @@ extension FileHandle {
407413
}
408414
}
409415
}
416+
417+
/// Buffers incoming bytes until the full gRPC HTTP/2 pipeline is configured, then replays them.
418+
///
419+
/// See the equivalent in Containerization/Vminitd.swift for a full explanation.
420+
private final class HTTP2ConnectBufferingHandler: ChannelDuplexHandler, RemovableChannelHandler {
421+
typealias InboundIn = ByteBuffer
422+
typealias InboundOut = ByteBuffer
423+
typealias OutboundIn = ByteBuffer
424+
typealias OutboundOut = ByteBuffer
425+
426+
private var removalScheduled = false
427+
private var bufferedReads: [NIOAny] = []
428+
429+
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
430+
bufferedReads.append(data)
431+
}
432+
433+
func channelReadComplete(context: ChannelHandlerContext) {}
434+
435+
func flush(context: ChannelHandlerContext) {
436+
if !removalScheduled {
437+
removalScheduled = true
438+
context.eventLoop.assumeIsolatedUnsafeUnchecked().execute {
439+
context.pipeline.syncOperations.removeHandler(self, promise: nil)
440+
}
441+
}
442+
context.flush()
443+
}
444+
445+
func removeHandler(context: ChannelHandlerContext, removalToken: ChannelHandlerContext.RemovalToken) {
446+
var didRead = false
447+
while !bufferedReads.isEmpty {
448+
context.fireChannelRead(bufferedReads.removeFirst())
449+
didRead = true
450+
}
451+
if didRead {
452+
context.fireChannelReadComplete()
453+
}
454+
context.leavePipeline(removalToken: removalToken)
455+
}
456+
457+
func channelInactive(context: ChannelHandlerContext) {
458+
bufferedReads.removeAll()
459+
context.fireChannelInactive()
460+
}
461+
}

Sources/ContainerLog/StderrLogHandler.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,31 +46,42 @@ public struct StderrLogHandler: LogHandler {
4646
let data: Data
4747
switch logLevel {
4848
case .debug, .trace:
49-
let timestamp = ISO8601DateFormatter().string(from: Date())
49+
let timestamp = isoTimestamp()
5050
if let metadata, !metadata.isEmpty {
5151
data =
52-
"\(timestamp) \(message.description): \(metadata.description)"
52+
"\(timestamp) \(message.description): \(metadata.description)\n"
5353
.data(using: .utf8) ?? Data()
5454
} else {
5555
data =
56-
"\(timestamp) \(message.description)"
56+
"\(timestamp) \(message.description)\n"
5757
.data(using: .utf8) ?? Data()
5858
}
5959
default:
6060
if let metadata, !metadata.isEmpty {
6161
data =
62-
"\(message.description): \(metadata.description)"
62+
"\(message.description): \(metadata.description)\n"
6363
.data(using: .utf8) ?? Data()
6464
} else {
6565
data =
66-
message.description
66+
"\(message.description)\n"
6767
.data(using: .utf8) ?? Data()
6868
}
6969
}
7070

71-
// Use a single write call for atomicity
72-
var output = data
73-
output.append("\n".data(using: .utf8)!)
74-
FileHandle.standardError.write(output)
71+
FileHandle.standardError.write(data)
72+
}
73+
74+
private func isoTimestamp() -> String {
75+
let date = Date()
76+
var time = time_t(date.timeIntervalSince1970)
77+
var ms = Int(date.timeIntervalSince1970 * 1000) % 1000
78+
if ms < 0 { ms += 1000 }
79+
var tm = tm()
80+
gmtime_r(&time, &tm)
81+
let buf = withUnsafeTemporaryAllocation(of: CChar.self, capacity: 32) { ptr -> String in
82+
strftime(ptr.baseAddress!, 32, "%Y-%m-%dT%H:%M:%S", &tm)
83+
return String(cString: ptr.baseAddress!)
84+
}
85+
return String(format: "%@.%03dZ", buf, ms)
7586
}
7687
}

scripts/install-hawkeye.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ if command -v .local/bin/hawkeye >/dev/null 2>&1; then
1717
echo "hawkeye already installed"
1818
else
1919
echo "Installing hawkeye"
20-
export VERSION=v6.1.0
20+
export VERSION=v6.5.1
2121
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/korandoru/hawkeye/releases/download/${VERSION}/hawkeye-installer.sh | CARGO_HOME=.local sh -s -- --no-modify-path
2222
fi

0 commit comments

Comments
 (0)