Skip to content

Commit 817291a

Browse files
committed
PR changes
1 parent 9475866 commit 817291a

File tree

8 files changed

+110
-153
lines changed

8 files changed

+110
-153
lines changed

Diff for: Sources/GRPCCore/Call/Server/Internal/ServerRPCExecutor.swift

+1-4
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,7 @@ extension ServerRPCExecutor {
316316
case .some(let interceptor):
317317
let iter = iterator
318318
do {
319-
return try await interceptor.intercept(
320-
request: request,
321-
context: context
322-
) {
319+
return try await interceptor.intercept(request: request, context: context) {
323320
try await self._intercept(request: $0, context: $1, iterator: iter, finally: finally)
324321
}
325322
} catch let error as RPCError {

Diff for: Sources/GRPCCore/Call/Server/RPCRouter.swift

+10-12
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,6 @@ public struct RPCRouter: Sendable {
136136
self.handlers[descriptor] = (handler, [])
137137
}
138138

139-
@inlinable
140-
public mutating func registerInterceptors(
141-
pipeline: [ServerInterceptorOperation]
142-
) {
143-
for descriptor in self.handlers.keys {
144-
let applicableOperations = pipeline.filter { $0.applies(to: descriptor) }
145-
if !applicableOperations.isEmpty {
146-
self.handlers[descriptor]?.interceptors = applicableOperations.map { $0.interceptor }
147-
}
148-
}
149-
}
150-
151139
/// Removes any handler registered for the specified method.
152140
///
153141
/// - Parameter descriptor: A descriptor of the method to remove a handler for.
@@ -156,6 +144,16 @@ public struct RPCRouter: Sendable {
156144
public mutating func removeHandler(forMethod descriptor: MethodDescriptor) -> Bool {
157145
return self.handlers.removeValue(forKey: descriptor) != nil
158146
}
147+
148+
@inlinable
149+
mutating func registerInterceptors(pipeline: [ServerInterceptorOperation]) {
150+
for descriptor in self.handlers.keys {
151+
let applicableOperations = pipeline.filter { $0._applies(to: descriptor) }
152+
if !applicableOperations.isEmpty {
153+
self.handlers[descriptor]?.interceptors = applicableOperations.map { $0.interceptor }
154+
}
155+
}
156+
}
159157
}
160158

161159
extension RPCRouter {

Diff for: Sources/GRPCCore/Call/Server/ServerInterceptorOperation.swift

+57-68
Original file line numberDiff line numberDiff line change
@@ -15,93 +15,82 @@
1515
*/
1616

1717
/// A `ServerInterceptorOperation` describes to which RPCs a server interceptor should be applied.
18-
///
18+
///
1919
/// You can configure a server interceptor to be applied to:
2020
/// - all RPCs and services;
2121
/// - requests directed only to specific services registered with your server; or
2222
/// - requests directed only to specific methods (of a specific service).
23-
///
23+
///
2424
/// - SeeAlso: ``ServerInterceptor`` for more information on server interceptors, and
2525
/// ``ClientInterceptorOperation`` for the client-side version of this type.
2626
public struct ServerInterceptorOperation: Sendable {
27-
internal enum Wrapped: Sendable {
28-
case allServices(interceptor: any ServerInterceptor)
29-
case serviceSpecific(interceptor: any ServerInterceptor, services: [String])
30-
case methodSpecific(interceptor: any ServerInterceptor, methods: [MethodDescriptor])
31-
}
27+
/// The subject of a ``ServerInterceptorOperation``.
28+
/// The subject of an interceptor can either be all services and methods, only specific services, or only specific methods.
29+
public struct Subject: Sendable {
30+
internal enum Wrapped: Sendable {
31+
case all
32+
case services([ServiceDescriptor])
33+
case methods([MethodDescriptor])
34+
}
3235

33-
/// An operation specifying an interceptor that applies to all RPCs across all services will be registered with this server.
34-
/// - Parameter interceptor: The interceptor to register with the server.
35-
/// - Returns: A ``ServerInterceptorOperation``.
36-
public static func applyToAllServices(
37-
_ interceptor: any ServerInterceptor
38-
) -> Self {
39-
Self(wrapped: .allServices(interceptor: interceptor))
40-
}
36+
private let wrapped: Wrapped
4137

42-
/// An operation specifying an interceptor that will be applied only to RPCs directed to the specified services.
43-
/// - Parameters:
44-
/// - interceptor: The interceptor to register with the server.
45-
/// - services: The list of service names for which this interceptor should intercept RPCs.
46-
/// - Returns: A ``ServerInterceptorOperation``.
47-
public static func apply(
48-
_ interceptor: any ServerInterceptor,
49-
onlyToServices services: [String]
50-
) -> Self {
51-
Self(
52-
wrapped: .serviceSpecific(
53-
interceptor: interceptor,
54-
services: services
55-
)
56-
)
57-
}
38+
/// An operation subject specifying an interceptor that applies to all RPCs across all services will be registered with this server.
39+
public static var all: Self { .init(wrapped: .all) }
5840

59-
/// An operation specifying an interceptor that will be applied only to RPCs directed to the specified service methods.
60-
/// - Parameters:
61-
/// - interceptor: The interceptor to register with the server.
62-
/// - services: The list of method descriptors for which this interceptor should intercept RPCs.
63-
/// - Returns: A ``ServerInterceptorOperation``.
64-
public static func apply(
65-
_ interceptor: any ServerInterceptor,
66-
onlyToMethods methods: [MethodDescriptor]
67-
) -> Self {
68-
Self(
69-
wrapped: .methodSpecific(
70-
interceptor: interceptor,
71-
methods: methods
72-
)
73-
)
41+
/// An operation subject specifying an interceptor that will be applied only to RPCs directed to the specified services.
42+
/// - Parameters:
43+
/// - services: The list of service names for which this interceptor should intercept RPCs.
44+
/// - Returns: A ``ServerInterceptorOperation``.
45+
public static func services(_ services: [ServiceDescriptor]) -> Self {
46+
Self(wrapped: .services(services))
47+
}
48+
49+
/// An operation subject specifying an interceptor that will be applied only to RPCs directed to the specified service methods.
50+
/// - Parameters:
51+
/// - methods: The list of method descriptors for which this interceptor should intercept RPCs.
52+
/// - Returns: A ``ServerInterceptorOperation``.
53+
public static func methods(_ methods: [MethodDescriptor]) -> Self {
54+
Self(wrapped: .methods(methods))
55+
}
56+
57+
internal func applies(to descriptor: MethodDescriptor) -> Bool {
58+
switch self.wrapped {
59+
case .all:
60+
return true
61+
62+
case .services(let services):
63+
return services.map({ $0.fullyQualifiedService }).contains(descriptor.service)
64+
65+
case .methods(let methods):
66+
return methods.contains(descriptor)
67+
}
68+
}
7469
}
7570

76-
private let wrapped: Wrapped
71+
/// The interceptor specified for this operation.
72+
public let interceptor: any ServerInterceptor
7773

78-
private init(wrapped: Wrapped) {
79-
self.wrapped = wrapped
74+
private let subject: Subject
75+
76+
private init(interceptor: any ServerInterceptor, appliesTo: Subject) {
77+
self.interceptor = interceptor
78+
self.subject = appliesTo
8079
}
8180

82-
/// Get the ``ServerInterceptor`` associated with this ``ServerInterceptorOperation``.
83-
public var interceptor: any ServerInterceptor {
84-
switch self.wrapped {
85-
case .allServices(let interceptor):
86-
return interceptor
87-
case .serviceSpecific(let interceptor, _):
88-
return interceptor
89-
case .methodSpecific(let interceptor, _):
90-
return interceptor
91-
}
81+
/// Create an operation, specifying which ``ServerInterceptor`` to apply and to which ``Subject``.
82+
/// - Parameters:
83+
/// - interceptor: The ``ServerInterceptor`` to register with the server.
84+
/// - subject: The ``Subject`` to which the `interceptor` applies.
85+
/// - Returns: A ``ServerInterceptorOperation``.
86+
public static func apply(_ interceptor: any ServerInterceptor, to subject: Subject) -> Self {
87+
Self(interceptor: interceptor, appliesTo: subject)
9288
}
9389

9490
/// Returns whether this ``ServerInterceptorOperation`` applies to the given `descriptor`.
9591
/// - Parameter descriptor: A ``MethodDescriptor`` for which to test whether this interceptor applies.
9692
/// - Returns: `true` if this interceptor applies to the given `descriptor`, or `false` otherwise.
97-
public func applies(to descriptor: MethodDescriptor) -> Bool {
98-
switch self.wrapped {
99-
case .allServices:
100-
return true
101-
case .serviceSpecific(_, let services):
102-
return services.contains(descriptor.service)
103-
case .methodSpecific(_, let methods):
104-
return methods.contains(descriptor)
105-
}
93+
public func _applies(to descriptor: MethodDescriptor) -> Bool {
94+
self.subject.applies(to: descriptor)
10695
}
10796
}

Diff for: Sources/GRPCCore/GRPCServer.swift

+6-46
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ private import Synchronization
4848
/// let server = GRPCServer(
4949
/// transport: inProcessTransport.server,
5050
/// services: [greeter, echo],
51-
/// interceptors: [.allServices(interceptor: statsRecorder)]
51+
/// interceptors: [statsRecorder]
5252
/// )
5353
/// ```
5454
///
@@ -149,7 +149,7 @@ public final class GRPCServer: Sendable {
149149
self.init(
150150
transport: transport,
151151
services: services,
152-
interceptorPipeline: interceptors.map { .applyToAllServices($0) }
152+
interceptorPipeline: interceptors.map { .apply($0, to: .all) }
153153
)
154154
}
155155

@@ -172,54 +172,17 @@ public final class GRPCServer: Sendable {
172172
for service in services {
173173
service.registerMethods(with: &router)
174174
}
175+
router.registerInterceptors(pipeline: interceptorPipeline)
175176

176-
self.init(
177-
transport: transport,
178-
router: router,
179-
interceptorPipeline: interceptorPipeline
180-
)
181-
}
182-
183-
/// Creates a new server with no resources.
184-
///
185-
/// - Parameters:
186-
/// - transport: The transport the server should listen on.
187-
/// - router: A ``RPCRouter`` used by the server to route accepted streams to method handlers.
188-
/// - interceptors: A collection of interceptors providing cross-cutting functionality to each
189-
/// accepted RPC. The order in which interceptors are added reflects the order in which they
190-
/// are called. The first interceptor added will be the first interceptor to intercept each
191-
/// request. The last interceptor added will be the final interceptor to intercept each
192-
/// request before calling the appropriate handler.
193-
public convenience init(
194-
transport: any ServerTransport,
195-
router: RPCRouter,
196-
interceptors: [any ServerInterceptor] = []
197-
) {
198-
self.init(
199-
transport: transport,
200-
router: router,
201-
interceptorPipeline: interceptors.map { .applyToAllServices($0) }
202-
)
177+
self.init(transport: transport, router: router)
203178
}
204179

205180
/// Creates a new server with no resources.
206181
///
207182
/// - Parameters:
208183
/// - transport: The transport the server should listen on.
209184
/// - router: A ``RPCRouter`` used by the server to route accepted streams to method handlers.
210-
/// - interceptors: A collection of interceptors providing cross-cutting functionality to each
211-
/// accepted RPC. The order in which interceptors are added reflects the order in which they
212-
/// are called. The first interceptor added will be the first interceptor to intercept each
213-
/// request. The last interceptor added will be the final interceptor to intercept each
214-
/// request before calling the appropriate handler.
215-
public init(
216-
transport: any ServerTransport,
217-
router: RPCRouter,
218-
interceptorPipeline: [ServerInterceptorOperation]
219-
) {
220-
var router = router
221-
router.registerInterceptors(pipeline: interceptorPipeline)
222-
185+
public init(transport: any ServerTransport, router: RPCRouter) {
223186
self.state = Mutex(.notStarted)
224187
self.transport = transport
225188
self.router = router
@@ -248,10 +211,7 @@ public final class GRPCServer: Sendable {
248211

249212
do {
250213
try await transport.listen { stream, context in
251-
await self.router.handle(
252-
stream: stream,
253-
context: context
254-
)
214+
await self.router.handle(stream: stream, context: context)
255215
}
256216
} catch {
257217
throw RuntimeError(

Diff for: Tests/GRPCCoreTests/Call/Server/Internal/ServerRPCExecutorTests.swift

+1-3
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,7 @@ final class ServerRPCExecutorTests: XCTestCase {
258258
)
259259

260260
// The interceptor skips the handler altogether.
261-
let harness = ServerRPCExecutorTestHarness(interceptors: [
262-
.rejectAll(with: error)
263-
])
261+
let harness = ServerRPCExecutorTestHarness(interceptors: [.rejectAll(with: error)])
264262
try await harness.execute(
265263
deserializer: IdentityDeserializer(),
266264
serializer: IdentitySerializer()

Diff for: Tests/GRPCCoreTests/GRPCServerTests.swift

+12-12
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,9 @@ final class GRPCServerTests: XCTestCase {
221221
try await self.withInProcessClientConnectedToServer(
222222
services: [BinaryEcho()],
223223
interceptorPipeline: [
224-
.applyToAllServices(.requestCounter(counter1)),
225-
.applyToAllServices(.rejectAll(with: RPCError(code: .unavailable, message: ""))),
226-
.applyToAllServices(.requestCounter(counter2)),
224+
.apply(.requestCounter(counter1), to: .all),
225+
.apply(.rejectAll(with: RPCError(code: .unavailable, message: "")), to: .all),
226+
.apply(.requestCounter(counter2), to: .all),
227227
]
228228
) { client, _ in
229229
try await client.withStream(
@@ -249,7 +249,7 @@ final class GRPCServerTests: XCTestCase {
249249

250250
try await self.withInProcessClientConnectedToServer(
251251
services: [BinaryEcho()],
252-
interceptorPipeline: [.applyToAllServices(.requestCounter(counter))]
252+
interceptorPipeline: [.apply(.requestCounter(counter), to: .all)]
253253
) { client, _ in
254254
try await client.withStream(
255255
descriptor: MethodDescriptor(service: "not", method: "implemented"),
@@ -390,16 +390,16 @@ struct ServerTests {
390390
interceptorPipeline: [
391391
.apply(
392392
.requestCounter(onlyBinaryEchoCounter),
393-
onlyToServices: [BinaryEcho.serviceName]
393+
to: .services([BinaryEcho.serviceDescriptor])
394394
),
395-
.applyToAllServices(.requestCounter(allServicesCounter)),
395+
.apply(.requestCounter(allServicesCounter), to: .all),
396396
.apply(
397397
.requestCounter(onlyHelloWorldCounter),
398-
onlyToServices: [HelloWorld.serviceName]
398+
to: .services([HelloWorld.serviceDescriptor])
399399
),
400400
.apply(
401401
.requestCounter(bothServicesCounter),
402-
onlyToServices: [BinaryEcho.serviceName, HelloWorld.serviceName]
402+
to: .services([BinaryEcho.serviceDescriptor, HelloWorld.serviceDescriptor])
403403
),
404404
]
405405
) { client, _ in
@@ -477,16 +477,16 @@ struct ServerTests {
477477
interceptorPipeline: [
478478
.apply(
479479
.requestCounter(onlyBinaryEchoGetCounter),
480-
onlyToMethods: [BinaryEcho.Methods.get]
480+
to: .methods([BinaryEcho.Methods.get])
481481
),
482-
.applyToAllServices(.requestCounter(allMethodsCounter)),
482+
.apply(.requestCounter(allMethodsCounter), to: .all),
483483
.apply(
484484
.requestCounter(onlyBinaryEchoCollectCounter),
485-
onlyToMethods: [BinaryEcho.Methods.collect]
485+
to: .methods([BinaryEcho.Methods.collect])
486486
),
487487
.apply(
488488
.requestCounter(bothBinaryEchoMethodsCounter),
489-
onlyToMethods: [BinaryEcho.Methods.get, BinaryEcho.Methods.collect]
489+
to: .methods([BinaryEcho.Methods.get, BinaryEcho.Methods.collect])
490490
),
491491
]
492492
) { client, _ in

Diff for: Tests/GRPCCoreTests/Test Utilities/Services/BinaryEcho.swift

+17-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import GRPCCore
1717

1818
struct BinaryEcho: RegistrableRPCService {
19-
static let serviceName = "echo.Echo"
19+
static let serviceDescriptor = ServiceDescriptor(package: "echo", service: "Echo")
2020

2121
func get(
2222
_ request: ServerRequest<[UInt8]>
@@ -97,9 +97,21 @@ struct BinaryEcho: RegistrableRPCService {
9797
}
9898

9999
enum Methods {
100-
static let get = MethodDescriptor(service: BinaryEcho.serviceName, method: "Get")
101-
static let collect = MethodDescriptor(service: BinaryEcho.serviceName, method: "Collect")
102-
static let expand = MethodDescriptor(service: BinaryEcho.serviceName, method: "Expand")
103-
static let update = MethodDescriptor(service: BinaryEcho.serviceName, method: "Update")
100+
static let get = MethodDescriptor(
101+
service: BinaryEcho.serviceDescriptor.fullyQualifiedService,
102+
method: "Get"
103+
)
104+
static let collect = MethodDescriptor(
105+
service: BinaryEcho.serviceDescriptor.fullyQualifiedService,
106+
method: "Collect"
107+
)
108+
static let expand = MethodDescriptor(
109+
service: BinaryEcho.serviceDescriptor.fullyQualifiedService,
110+
method: "Expand"
111+
)
112+
static let update = MethodDescriptor(
113+
service: BinaryEcho.serviceDescriptor.fullyQualifiedService,
114+
method: "Update"
115+
)
104116
}
105117
}

0 commit comments

Comments
 (0)