From dcea5fbcbb965a3f05e08a18eaea80f8a4ac0f9f Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 16 Jan 2025 16:58:10 +0000 Subject: [PATCH 1/5] Update ClientInterceptor and ClientContext docs --- Sources/GRPCCore/Call/Client/ClientContext.swift | 5 +++++ Sources/GRPCCore/Call/Client/ClientInterceptor.swift | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Sources/GRPCCore/Call/Client/ClientContext.swift b/Sources/GRPCCore/Call/Client/ClientContext.swift index 613cf0c36..679496ed4 100644 --- a/Sources/GRPCCore/Call/Client/ClientContext.swift +++ b/Sources/GRPCCore/Call/Client/ClientContext.swift @@ -46,6 +46,11 @@ public struct ClientContext: Sendable { public var localPeer: String /// Create a new client interceptor context. + /// + /// - Parameters: + /// - descriptor: A description of the method being called. + /// - remotePeer: A description of the remote peer. + /// - localPeer: A description of the local peer. public init( descriptor: MethodDescriptor, remotePeer: String, diff --git a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift index 68a1fcf45..890a49f0c 100644 --- a/Sources/GRPCCore/Call/Client/ClientInterceptor.swift +++ b/Sources/GRPCCore/Call/Client/ClientInterceptor.swift @@ -14,6 +14,8 @@ * limitations under the License. */ +// - FIXME: Update example and documentation to show how to register an interceptor. + /// A type that intercepts requests and response for clients. /// /// Interceptors allow you to inspect and modify requests and responses. Requests are intercepted @@ -21,14 +23,12 @@ /// received from the transport. They are typically used for cross-cutting concerns like injecting /// metadata, validating messages, logging additional data, and tracing. /// -/// Interceptors are registered with the server via ``ClientInterceptorPipelineOperation``s. +/// Interceptors are registered with the client via ``ClientInterceptorPipelineOperation``s. /// You may register them for all services registered with a server, for RPCs directed to specific services, or /// for RPCs directed to specific methods. If you need to modify the behavior of an interceptor on a /// per-RPC basis in more detail, then you can use the ``ClientContext/descriptor`` to determine /// which RPC is being called and conditionalise behavior accordingly. /// -/// - TODO: Update example and documentation to show how to register an interceptor. -/// /// Some examples of simple interceptors follow. /// /// ## Metadata injection From bca5dd92c0d80c9cf83cd894b902e2a74ae2c9fe Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 16 Jan 2025 17:07:29 +0000 Subject: [PATCH 2/5] Add remote and local peers to ServerContext --- .../GRPCCore/Call/Server/ServerContext.swift | 40 +++++++++++++++++-- .../InProcessTransport+Server.swift | 3 +- .../ServerRPCExecutorTestHarness.swift | 3 +- .../InProcessTransportTests.swift | 2 +- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Sources/GRPCCore/Call/Server/ServerContext.swift b/Sources/GRPCCore/Call/Server/ServerContext.swift index 504e9563a..91709e566 100644 --- a/Sources/GRPCCore/Call/Server/ServerContext.swift +++ b/Sources/GRPCCore/Call/Server/ServerContext.swift @@ -30,7 +30,36 @@ public struct ServerContext: Sendable { /// - "ipv4:127.0.0.1:31415", /// - "ipv6:[::1]:443", /// - "in-process:27182". - public var peer: String + @available(*, deprecated, renamed: "remotePeer") + public var peer: String { + remotePeer + } + + /// A description of the remote peer. + /// + /// The format of the description should follow the pattern ":
" where + /// "" indicates the underlying network transport (such as "ipv4", "unix", or + /// "in-process"). This is a guideline for how descriptions should be formatted; different + /// implementations may not follow this format so you shouldn't make assumptions based on it. + /// + /// Some examples include: + /// - "ipv4:127.0.0.1:31415", + /// - "ipv6:[::1]:443", + /// - "in-process:27182". + public var remotePeer: String + + /// A description of the local peer. + /// + /// The format of the description should follow the pattern ":
" where + /// "" indicates the underlying network transport (such as "ipv4", "unix", or + /// "in-process"). This is a guideline for how descriptions should be formatted; different + /// implementations may not follow this format so you shouldn't make assumptions based on it. + /// + /// Some examples include: + /// - "ipv4:127.0.0.1:31415", + /// - "ipv6:[::1]:443", + /// - "in-process:27182". + public var localPeer: String /// A handle for checking the cancellation status of an RPC. public var cancellation: RPCCancellationHandle @@ -39,16 +68,19 @@ public struct ServerContext: Sendable { /// /// - Parameters: /// - descriptor: A description of the method being called. - /// - peer: A description of the remote peer. + /// - remotePeer: A description of the remote peer. + /// - localPeer: A description of the local peer. /// - cancellation: A cancellation handle. You can create a cancellation handle /// using ``withServerContextRPCCancellationHandle(_:)``. public init( descriptor: MethodDescriptor, - peer: String, + remotePeer: String, + localPeer: String, cancellation: RPCCancellationHandle ) { self.descriptor = descriptor - self.peer = peer + self.remotePeer = remotePeer + self.localPeer = localPeer self.cancellation = cancellation } } diff --git a/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift b/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift index 659c53465..d8b385ce3 100644 --- a/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift +++ b/Sources/GRPCInProcessTransport/InProcessTransport+Server.swift @@ -122,7 +122,8 @@ extension InProcessTransport { let context = ServerContext( descriptor: stream.descriptor, - peer: self.peer, + remotePeer: self.peer, + localPeer: self.peer, cancellation: handle ) await streamHandler(stream, context) diff --git a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift index 6634d9e9f..d9beb0d6a 100644 --- a/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift +++ b/Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTestSupport/ServerRPCExecutorTestHarness.swift @@ -102,7 +102,8 @@ struct ServerRPCExecutorTestHarness { await withServerContextRPCCancellationHandle { cancellation in let context = ServerContext( descriptor: MethodDescriptor(fullyQualifiedService: "foo", method: "bar"), - peer: "tests", + remotePeer: "remote", + localPeer: "local", cancellation: cancellation ) diff --git a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift index 786f6fe99..cf6466324 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift @@ -123,7 +123,7 @@ private struct TestService: RegistrableRPCService { request: ServerRequest, context: ServerContext ) async throws -> ServerResponse { - return ServerResponse(message: context.peer) + return ServerResponse(message: context.remotePeer) } func registerMethods(with router: inout RPCRouter) { From da4a7ff88acbc3742866f24673f368aff5ff5ab6 Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 16 Jan 2025 17:18:33 +0000 Subject: [PATCH 3/5] Improve test --- .../InProcessTransportTests.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift index cf6466324..feeb9c13d 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift @@ -83,8 +83,9 @@ struct InProcessTransportTests { try $0.message } - let match = peerInfo.wholeMatch(of: /in-process:\d+/) - #expect(match != nil) + let maybeMatch = peerInfo.wholeMatch(of: /local: in-process:(\d+), remote: in-process:(\d+)/) + let match = try #require(maybeMatch) + #expect(match.1 == match.2) } } } @@ -123,7 +124,8 @@ private struct TestService: RegistrableRPCService { request: ServerRequest, context: ServerContext ) async throws -> ServerResponse { - return ServerResponse(message: context.remotePeer) + let peerInfo = "local: \(context.localPeer), remote: \(context.remotePeer)" + return ServerResponse(message: peerInfo) } func registerMethods(with router: inout RPCRouter) { From 9fd57dc3b6807726134b6243b921ca7472c28981 Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 16 Jan 2025 21:28:55 +0000 Subject: [PATCH 4/5] Add PeerInfo (de)serialiser for tests --- .../InProcessTransportTests.swift | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift index feeb9c13d..04b8265a0 100644 --- a/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift +++ b/Tests/GRPCInProcessTransportTests/InProcessTransportTests.swift @@ -1,5 +1,5 @@ /* - * Copyright 2024, gRPC Authors All rights reserved. + * Copyright 2024-2025, gRPC Authors All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,15 +77,13 @@ struct InProcessTransportTests { request: ClientRequest(message: ()), descriptor: .peerInfo, serializer: VoidSerializer(), - deserializer: UTF8Deserializer(), + deserializer: PeerInfoDeserializer(), options: .defaults ) { try $0.message } - let maybeMatch = peerInfo.wholeMatch(of: /local: in-process:(\d+), remote: in-process:(\d+)/) - let match = try #require(maybeMatch) - #expect(match.1 == match.2) + #expect(peerInfo.local == peerInfo.remote) } } } @@ -123,8 +121,8 @@ private struct TestService: RegistrableRPCService { func peerInfo( request: ServerRequest, context: ServerContext - ) async throws -> ServerResponse { - let peerInfo = "local: \(context.localPeer), remote: \(context.remotePeer)" + ) async throws -> ServerResponse { + let peerInfo = PeerInfo(local: context.localPeer, remote: context.remotePeer) return ServerResponse(message: peerInfo) } @@ -141,7 +139,7 @@ private struct TestService: RegistrableRPCService { router.registerHandler( forMethod: .peerInfo, deserializer: VoidDeserializer(), - serializer: UTF8Serializer(), + serializer: PeerInfoSerializer(), handler: { let response = try await self.peerInfo( request: ServerRequest(stream: $0), @@ -165,6 +163,25 @@ extension MethodDescriptor { ) } +private struct PeerInfo: Codable { + var local: String + var remote: String +} + +private struct PeerInfoSerializer: MessageSerializer { + func serialize(_ message: PeerInfo) throws -> [UInt8] { + Array("\(message.local) \(message.remote)".utf8) + } +} + +private struct PeerInfoDeserializer: MessageDeserializer { + func deserialize(_ serializedMessageBytes: [UInt8]) throws -> PeerInfo { + let stringPeerInfo = String(decoding: serializedMessageBytes, as: UTF8.self) + let peerInfoComponents = stringPeerInfo.split(separator: " ") + return PeerInfo(local: String(peerInfoComponents[0]), remote: String(peerInfoComponents[1])) + } +} + private struct UTF8Serializer: MessageSerializer { func serialize(_ message: String) throws -> [UInt8] { Array(message.utf8) From bf92ba7dc78748a31af7b5b008ee1d1942ae16a6 Mon Sep 17 00:00:00 2001 From: Gus Cairo Date: Thu, 16 Jan 2025 21:29:06 +0000 Subject: [PATCH 5/5] Add setter to deprecated peer property in ServerContext --- Sources/GRPCCore/Call/Server/ServerContext.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/GRPCCore/Call/Server/ServerContext.swift b/Sources/GRPCCore/Call/Server/ServerContext.swift index 91709e566..812a22886 100644 --- a/Sources/GRPCCore/Call/Server/ServerContext.swift +++ b/Sources/GRPCCore/Call/Server/ServerContext.swift @@ -32,7 +32,8 @@ public struct ServerContext: Sendable { /// - "in-process:27182". @available(*, deprecated, renamed: "remotePeer") public var peer: String { - remotePeer + get { remotePeer } + set { remotePeer = newValue } } /// A description of the remote peer.