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

Add deprecation warnings for package-internal APIs #315

Merged
merged 2 commits into from
Oct 17, 2024
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 @@ -158,7 +158,7 @@ extension ConnectInterceptor: StreamInterceptor {

@Sendable
func handleStreamRawInput(_ input: Data, proceed: @escaping (Data) -> Void) {
proceed(Envelope.packMessage(input, using: self.config.requestCompression))
proceed(Envelope._packMessage(input, using: self.config.requestCompression))
}

@Sendable
Expand Down Expand Up @@ -190,7 +190,7 @@ extension ConnectInterceptor: StreamInterceptor {
let responseCompressionPool = self.streamResponseHeaders.value?[
HeaderConstants.connectStreamingContentEncoding
]?.first.flatMap { self.config.responseCompressionPool(forName: $0) }
if responseCompressionPool == nil && Envelope.isCompressed(data) {
if responseCompressionPool == nil && Envelope._isCompressed(data) {
proceed(.complete(
code: .internalError, error: ConnectError(
code: .internalError, message: "received unexpected compressed message"
Expand All @@ -199,7 +199,7 @@ extension ConnectInterceptor: StreamInterceptor {
return
}

let (headerByte, message) = try Envelope.unpackMessage(
let (headerByte, message) = try Envelope._unpackMessage(
data, compressionPool: responseCompressionPool
)
let isEndStream = 0b00000010 & headerByte != 0
Expand Down
30 changes: 15 additions & 15 deletions Libraries/Connect/Internal/Interceptors/GRPCWebInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ extension GRPCWebInterceptor: UnaryInterceptor {
proceed: @escaping (Result<HTTPRequest<Data?>, ConnectError>) -> Void
) {
// gRPC-Web unary payloads are enveloped.
let envelopedRequestBody = Envelope.packMessage(
let envelopedRequestBody = Envelope._packMessage(
request.message ?? Data(), using: self.config.requestCompression
)
proceed(.success(HTTPRequest(
url: request.url,
headers: request.headers.addingGRPCHeaders(using: self.config, grpcWeb: true),
headers: request.headers._addingGRPCHeaders(using: self.config, grpcWeb: true),
message: envelopedRequestBody,
method: request.method,
trailers: nil,
Expand All @@ -57,7 +57,7 @@ extension GRPCWebInterceptor: UnaryInterceptor {
}

guard let responseData = response.message, !responseData.isEmpty else {
let (grpcCode, connectError) = ConnectError.parseGRPCHeaders(
let (grpcCode, connectError) = ConnectError._parseGRPCHeaders(
response.headers,
trailers: response.trailers
)
Expand Down Expand Up @@ -102,7 +102,7 @@ extension GRPCWebInterceptor: UnaryInterceptor {
let compressionPool = response.headers[HeaderConstants.grpcContentEncoding]?
.first
.flatMap { self.config.responseCompressionPool(forName: $0) }
if compressionPool == nil && Envelope.isCompressed(responseData) {
if compressionPool == nil && Envelope._isCompressed(responseData) {
proceed(HTTPResponse(
code: .internalError, headers: response.headers, message: nil,
trailers: response.trailers,
Expand All @@ -120,9 +120,9 @@ extension GRPCWebInterceptor: UnaryInterceptor {
// message data.
// 2. The (headers and length prefixed) trailers data.
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
let firstChunkLength = Envelope.messageLength(forPackedData: responseData)
let prefixedFirstChunkLength = Envelope.prefixLength + firstChunkLength
let firstChunk = try Envelope.unpackMessage(
let firstChunkLength = Envelope._messageLength(forPackedData: responseData)
let prefixedFirstChunkLength = Envelope._prefixLength + firstChunkLength
let firstChunk = try Envelope._unpackMessage(
Data(responseData.prefix(upTo: prefixedFirstChunkLength)),
compressionPool: compressionPool
)
Expand All @@ -135,7 +135,7 @@ extension GRPCWebInterceptor: UnaryInterceptor {
} else {
let trailersData = Data(responseData.suffix(from: prefixedFirstChunkLength))
let unpackedTrailers = try Trailers.fromGRPCHeadersBlock(
try Envelope.unpackMessage(
try Envelope._unpackMessage(
trailersData, compressionPool: compressionPool
).unpacked
)
Expand Down Expand Up @@ -165,7 +165,7 @@ extension GRPCWebInterceptor: StreamInterceptor {
) {
proceed(.success(HTTPRequest(
url: request.url,
headers: request.headers.addingGRPCHeaders(using: self.config, grpcWeb: true),
headers: request.headers._addingGRPCHeaders(using: self.config, grpcWeb: true),
message: request.message,
method: request.method,
trailers: nil,
Expand All @@ -175,7 +175,7 @@ extension GRPCWebInterceptor: StreamInterceptor {

@Sendable
func handleStreamRawInput(_ input: Data, proceed: @escaping (Data) -> Void) {
proceed(Envelope.packMessage(input, using: self.config.requestCompression))
proceed(Envelope._packMessage(input, using: self.config.requestCompression))
}

@Sendable
Expand All @@ -198,11 +198,11 @@ extension GRPCWebInterceptor: StreamInterceptor {
return
}

if let grpcCode = headers.grpcStatus() {
if let grpcCode = headers._grpcStatus() {
// Headers-only response.
proceed(.complete(
code: grpcCode,
error: ConnectError.parseGRPCHeaders(nil, trailers: headers).error,
error: ConnectError._parseGRPCHeaders(nil, trailers: headers).error,
trailers: headers
))
} else {
Expand All @@ -215,13 +215,13 @@ extension GRPCWebInterceptor: StreamInterceptor {
let responseCompressionPool = self.streamResponseHeaders.value?[
HeaderConstants.grpcContentEncoding
]?.first.flatMap { self.config.responseCompressionPool(forName: $0) }
let (headerByte, unpackedData) = try Envelope.unpackMessage(
let (headerByte, unpackedData) = try Envelope._unpackMessage(
data, compressionPool: responseCompressionPool
)
let isTrailers = 0b10000000 & headerByte != 0
if isTrailers {
let trailers = try Trailers.fromGRPCHeadersBlock(unpackedData)
let (grpcCode, error) = ConnectError.parseGRPCHeaders(
let (grpcCode, error) = ConnectError._parseGRPCHeaders(
self.streamResponseHeaders.value, trailers: trailers
)
if grpcCode == .ok {
Expand Down Expand Up @@ -290,7 +290,7 @@ private extension Trailers {

private extension HTTPResponse {
func withHandledGRPCWebTrailers(_ trailers: Trailers, message: Data?) -> Self {
let (grpcCode, error) = ConnectError.parseGRPCHeaders(self.headers, trailers: trailers)
let (grpcCode, error) = ConnectError._parseGRPCHeaders(self.headers, trailers: trailers)
if grpcCode != .ok || error != nil {
return HTTPResponse(
// Rewrite the gRPC code if it is "ok" but `connectError` is non-nil.
Expand Down
9 changes: 7 additions & 2 deletions Libraries/Connect/PackageInternal/ConnectError+GRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ extension ConnectError {
/// passed in the headers block for gRPC-Web.
///
/// - returns: A tuple containing the gRPC status code and an optional error.
public static func parseGRPCHeaders(
@available(
swift,
deprecated: 100.0,
Copy link
Member

Choose a reason for hiding this comment

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

This could be misleading. Is it dangerous to use 1.1 instead? If we end up needing a minor release before we're actually ready to use Swift 6 package visibility, could we just bump this out to 1.2? Would that cause havoc?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This refers to the version of Swift that this will be deprecated in - it's just an arbitrarily high number which doesn't show up in the warning message. Unfortunately, we cannot specify which version of the package something will be deprecated in as part of this macro

Copy link
Member

Choose a reason for hiding this comment

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

Oh. So why not set it to 6?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I tested this out, but it triggers warnings if a consuming project upgrades their Package.swift to use Swift 6, which we don't want:

Screenshot 2024-10-19 at 8 42 01 AM

message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static func _parseGRPCHeaders(
_ headers: Headers?, trailers: Trailers?
) -> (grpcCode: Code, error: ConnectError?) {
// "Trailers-only" responses can be sent in the headers or trailers block.
guard let grpcCode = trailers?.grpcStatus() ?? headers?.grpcStatus() else {
guard let grpcCode = trailers?._grpcStatus() ?? headers?._grpcStatus() else {
return (.unknown, ConnectError(code: .unknown, message: "RPC response missing status"))
}

Expand Down
44 changes: 37 additions & 7 deletions Libraries/Connect/PackageInternal/Envelope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,19 @@ import SwiftProtobuf
/// to change. When the compiler supports it, this should be package-internal.**
///
/// Provides functionality for packing and unpacking (headers and length prefixed) messages.
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public enum Envelope {
/// The total number of bytes that will prefix a message.
public static var prefixLength: Int {
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static var _prefixLength: Int {
return 5 // Header flags (1 byte) + message length (4 bytes)
}

Expand All @@ -35,7 +45,12 @@ public enum Envelope {
/// - parameter compression: Configuration to use for compressing the message.
///
/// - returns: Serialized/enveloped data for transmission.
public static func packMessage(
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static func _packMessage(
_ source: Data, using compression: ProtocolClientConfig.RequestCompression?
) -> Data {
var buffer = Data()
Expand Down Expand Up @@ -70,7 +85,12 @@ public enum Envelope {
///
/// - returns: A tuple that includes the header byte and the un-prefixed and decompressed
/// message.
public static func unpackMessage(
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static func _unpackMessage(
_ source: Data, compressionPool: CompressionPool?
) throws -> (headerByte: UInt8, unpacked: Data) {
if source.isEmpty {
Expand All @@ -79,7 +99,7 @@ public enum Envelope {

let headerByte = source[0]
let isCompressed = 0b00000001 & headerByte != 0
let messageData = Data(source.dropFirst(self.prefixLength))
let messageData = Data(source.dropFirst(self._prefixLength))
if isCompressed {
guard let compressionPool = compressionPool else {
throw Error.missingExpectedCompressionPool
Expand All @@ -96,7 +116,12 @@ public enum Envelope {
/// - parameter packedData: The packed data to analyze.
///
/// - returns: True if the data is compressed.
public static func isCompressed(_ packedData: Data) -> Bool {
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static func _isCompressed(_ packedData: Data) -> Bool {
return !packedData.isEmpty && (0b00000001 & packedData[0] != 0)
}

Expand All @@ -111,8 +136,13 @@ public enum Envelope {
/// - returns: The length of the next expected message in the packed data. If multiple chunks
/// are specified, this will return the length of the first. Returns -1 if there is
/// not enough prefix data to determine the message length.
public static func messageLength(forPackedData data: Data) -> Int {
guard data.count >= self.prefixLength else {
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public static func _messageLength(forPackedData data: Data) -> Int {
guard data.count >= self._prefixLength else {
return -1
}

Expand Down
7 changes: 6 additions & 1 deletion Libraries/Connect/PackageInternal/Headers+GRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ extension Headers {
/// - parameter grpcWeb: Should be true if using gRPC-Web, false if gRPC.
///
/// - returns: A set of updated headers.
public func addingGRPCHeaders(using config: ProtocolClientConfig, grpcWeb: Bool) -> Self {
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public func _addingGRPCHeaders(using config: ProtocolClientConfig, grpcWeb: Bool) -> Self {
var headers = self
headers[HeaderConstants.grpcAcceptEncoding] = config
.acceptCompressionPoolNames()
Expand Down
7 changes: 6 additions & 1 deletion Libraries/Connect/PackageInternal/Trailers+gRPC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ extension Trailers {
/// Identifies the status code from gRPC and gRPC-Web trailers.
///
/// - returns: The gRPC status code, if specified.
public func grpcStatus() -> Code? {
@available(
swift,
deprecated: 100.0,
message: "This is an internal-only API which will be made package-private in Swift 6."
)
public func _grpcStatus() -> Code? {
return self[HeaderConstants.grpcStatus]?
.first
.flatMap(Int.init)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,12 @@ extension ProtocolClient: ProtocolClientInterface {
// Handle cases where multiple messages are received in a single chunk.
responseBuffer += data
while true {
let messageLength = Envelope.messageLength(forPackedData: responseBuffer)
let messageLength = Envelope._messageLength(forPackedData: responseBuffer)
if messageLength < 0 {
return
}

let prefixedMessageLength = Envelope.prefixLength + messageLength
let prefixedMessageLength = Envelope._prefixLength + messageLength
guard responseBuffer.count >= prefixedMessageLength else {
return
}
Expand Down
26 changes: 13 additions & 13 deletions Libraries/ConnectNIO/Internal/GRPCInterceptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ extension GRPCInterceptor: UnaryInterceptor {
proceed: @escaping (Result<HTTPRequest<Data?>, ConnectError>) -> Void
) {
// gRPC unary payloads are enveloped.
let envelopedRequestBody = Envelope.packMessage(
let envelopedRequestBody = Envelope._packMessage(
request.message ?? Data(), using: self.config.requestCompression
)

proceed(.success(HTTPRequest(
url: request.url,
headers: request.headers.addingGRPCHeaders(using: self.config, grpcWeb: false),
headers: request.headers._addingGRPCHeaders(using: self.config, grpcWeb: false),
message: envelopedRequestBody,
method: request.method,
trailers: nil,
Expand Down Expand Up @@ -72,12 +72,12 @@ extension GRPCInterceptor: UnaryInterceptor {
return
}

let (grpcCode, connectError) = ConnectError.parseGRPCHeaders(
let (grpcCode, connectError) = ConnectError._parseGRPCHeaders(
response.headers,
trailers: response.trailers
)
guard grpcCode == .ok, let rawData = response.message, !rawData.isEmpty else {
if response.trailers.grpcStatus() == nil && response.message?.isEmpty == false {
if response.trailers._grpcStatus() == nil && response.message?.isEmpty == false {
proceed(HTTPResponse(
code: .internalError,
headers: response.headers,
Expand Down Expand Up @@ -117,7 +117,7 @@ extension GRPCInterceptor: UnaryInterceptor {
.headers[HeaderConstants.grpcContentEncoding]?
.first
.flatMap { self.config.responseCompressionPool(forName: $0) }
if compressionPool == nil && Envelope.isCompressed(rawData) {
if compressionPool == nil && Envelope._isCompressed(rawData) {
proceed(HTTPResponse(
code: .internalError, headers: response.headers, message: nil,
trailers: response.trailers, error: ConnectError(
Expand All @@ -140,7 +140,7 @@ extension GRPCInterceptor: UnaryInterceptor {
}

do {
let messageData = try Envelope.unpackMessage(
let messageData = try Envelope._unpackMessage(
rawData, compressionPool: compressionPool
).unpacked
proceed(HTTPResponse(
Expand Down Expand Up @@ -172,7 +172,7 @@ extension GRPCInterceptor: StreamInterceptor {
) {
proceed(.success(HTTPRequest(
url: request.url,
headers: request.headers.addingGRPCHeaders(using: self.config, grpcWeb: false),
headers: request.headers._addingGRPCHeaders(using: self.config, grpcWeb: false),
message: request.message,
method: request.method,
trailers: nil,
Expand All @@ -182,7 +182,7 @@ extension GRPCInterceptor: StreamInterceptor {

@Sendable
func handleStreamRawInput(_ input: Data, proceed: @escaping (Data) -> Void) {
proceed(Envelope.packMessage(input, using: self.config.requestCompression))
proceed(Envelope._packMessage(input, using: self.config.requestCompression))
}

@Sendable
Expand Down Expand Up @@ -214,7 +214,7 @@ extension GRPCInterceptor: StreamInterceptor {
let responseCompressionPool = self.streamResponseHeaders.value?[
HeaderConstants.grpcContentEncoding
]?.first.flatMap { self.config.responseCompressionPool(forName: $0) }
if responseCompressionPool == nil && Envelope.isCompressed(rawData) {
if responseCompressionPool == nil && Envelope._isCompressed(rawData) {
proceed(.complete(
code: .internalError, error: ConnectError(
code: .internalError, message: "received unexpected compressed message"
Expand All @@ -223,7 +223,7 @@ extension GRPCInterceptor: StreamInterceptor {
return
}

let unpackedMessage = try Envelope.unpackMessage(
let unpackedMessage = try Envelope._unpackMessage(
rawData, compressionPool: responseCompressionPool
).unpacked
proceed(.message(unpackedMessage))
Expand All @@ -239,7 +239,7 @@ extension GRPCInterceptor: StreamInterceptor {
return
}

let (grpcCode, connectError) = ConnectError.parseGRPCHeaders(
let (grpcCode, connectError) = ConnectError._parseGRPCHeaders(
self.streamResponseHeaders.value,
trailers: trailers
)
Expand Down Expand Up @@ -275,8 +275,8 @@ extension GRPCInterceptor: StreamInterceptor {

private extension Envelope {
static func containsMultipleGRPCMessages(_ packedData: Data) -> Bool {
let messageLength = self.messageLength(forPackedData: packedData)
return packedData.count > messageLength + self.prefixLength
let messageLength = self._messageLength(forPackedData: packedData)
return packedData.count > messageLength + self._prefixLength
}
}

Expand Down
Loading
Loading