|
19 | 19 | /// You can configure interceptors to be applied to:
|
20 | 20 | /// - all RPCs and services;
|
21 | 21 | /// - requests directed only to specific services; or
|
22 |
| -/// - requests directed only to specific methods (of a specific service). |
| 22 | +/// - requests directed only to specific methods (of a specific service); or |
| 23 | +/// - requests directed only to specific services or methods (of a specific service); or |
| 24 | +/// - all requests excluding requests directed to specific services or methods (of a specific service); or |
| 25 | +/// - requests whose ``MethodDescriptor`` satisfies a predicate. |
23 | 26 | ///
|
24 | 27 | /// - SeeAlso: ``ClientInterceptor`` and ``ServerInterceptor`` for more information on client and
|
25 | 28 | /// server interceptors, respectively.
|
26 | 29 | @available(gRPCSwift 2.0, *)
|
27 | 30 | public struct ConditionalInterceptor<Interceptor: Sendable>: Sendable {
|
28 | 31 | public struct Subject: Sendable {
|
29 |
| - internal enum Wrapped: Sendable { |
30 |
| - case all |
31 |
| - case services(Set<ServiceDescriptor>) |
32 |
| - case methods(Set<MethodDescriptor>) |
33 |
| - } |
34 | 32 |
|
35 |
| - private let wrapped: Wrapped |
| 33 | + private let predicate: @Sendable (_ descriptor: MethodDescriptor) -> Bool |
36 | 34 |
|
37 | 35 | /// An operation subject specifying an interceptor that applies to all RPCs across all services will be registered with this client.
|
38 |
| - public static var all: Self { .init(wrapped: .all) } |
| 36 | + public static var all: Self { |
| 37 | + Self { _ in true } |
| 38 | + } |
39 | 39 |
|
40 | 40 | /// An operation subject specifying an interceptor that will be applied only to RPCs directed to the specified services.
|
| 41 | + /// |
41 | 42 | /// - Parameters:
|
42 |
| - /// - services: The list of service names for which this interceptor should intercept RPCs. |
| 43 | + /// - services: The list of service descriptors for which this interceptor should intercept RPCs. |
43 | 44 | public static func services(_ services: Set<ServiceDescriptor>) -> Self {
|
44 |
| - Self(wrapped: .services(services)) |
| 45 | + Self { descriptor in |
| 46 | + services.contains(descriptor.service) |
| 47 | + } |
45 | 48 | }
|
46 | 49 |
|
47 | 50 | /// An operation subject specifying an interceptor that will be applied only to RPCs directed to the specified service methods.
|
| 51 | + /// |
48 | 52 | /// - Parameters:
|
49 | 53 | /// - methods: The list of method descriptors for which this interceptor should intercept RPCs.
|
50 | 54 | public static func methods(_ methods: Set<MethodDescriptor>) -> Self {
|
51 |
| - Self(wrapped: .methods(methods)) |
| 55 | + Self { descriptor in |
| 56 | + methods.contains(descriptor) |
| 57 | + } |
52 | 58 | }
|
53 | 59 |
|
54 |
| - @usableFromInline |
55 |
| - package func applies(to descriptor: MethodDescriptor) -> Bool { |
56 |
| - switch self.wrapped { |
57 |
| - case .all: |
58 |
| - return true |
59 |
| - |
60 |
| - case .services(let services): |
61 |
| - return services.contains(descriptor.service) |
| 60 | + /// An operation subject specifying an interceptor that will be applied only to RPCs directed to the specified services or service methods. |
| 61 | + /// |
| 62 | + /// - Parameters: |
| 63 | + /// - services: The list of service descriptors for which this interceptor should intercept RPCs. |
| 64 | + /// - methods: The list of method descriptors for which this interceptor should intercept RPCs. |
| 65 | + @available(gRPCSwift 2.2, *) |
| 66 | + public static func only( |
| 67 | + services: Set<ServiceDescriptor>, |
| 68 | + methods: Set<MethodDescriptor> |
| 69 | + ) -> Self { |
| 70 | + Self { descriptor in |
| 71 | + services.contains(descriptor.service) || methods.contains(descriptor) |
| 72 | + } |
| 73 | + } |
62 | 74 |
|
63 |
| - case .methods(let methods): |
64 |
| - return methods.contains(descriptor) |
| 75 | + /// An operation subject specifying an interceptor that will be applied to all RPCs across all services for this client excluding the specified services or service methods. |
| 76 | + /// |
| 77 | + /// - Parameters: |
| 78 | + /// - services: The list of service descriptors for which this interceptor should **not** intercept RPCs. |
| 79 | + /// - methods: The list of method descriptors for which this interceptor should **not** intercept RPCs. |
| 80 | + @available(gRPCSwift 2.2, *) |
| 81 | + public static func allExcluding( |
| 82 | + services: Set<ServiceDescriptor>, |
| 83 | + methods: Set<MethodDescriptor> |
| 84 | + ) -> Self { |
| 85 | + Self { descriptor in |
| 86 | + !(services.contains(descriptor.service) || methods.contains(descriptor)) |
65 | 87 | }
|
66 | 88 | }
|
| 89 | + |
| 90 | + /// An operation subject specifying an interceptor that will be applied to RPCs whose ``MethodDescriptor`` satisfies a `predicate`. |
| 91 | + /// |
| 92 | + /// - Important: The result of `predicate` is **cached per `MethodDescriptor`** by the client. |
| 93 | + /// The predicate is evaluated the first time a given method is encountered, and that result |
| 94 | + /// is reused for subsequent RPCs of the same method for the lifetime of the client. |
| 95 | + /// As a consequence, the `predicate` closure should be **deterministic**. |
| 96 | + /// Do **not** base it on dynamic state (time, session, feature flags, etc.). |
| 97 | + /// If you need per-call decisions, put that logic inside the interceptor itself. |
| 98 | + /// |
| 99 | + /// - Parameters: |
| 100 | + /// - predicate: A `@Sendable` closure evaluated per RPC. Return `true` to intercept. |
| 101 | + @available(gRPCSwift 2.2, *) |
| 102 | + public static func allMatching( |
| 103 | + _ predicate: @Sendable @escaping (_ descriptor: MethodDescriptor) -> Bool |
| 104 | + ) -> Self { |
| 105 | + Self(predicate: predicate) |
| 106 | + } |
| 107 | + |
| 108 | + @usableFromInline |
| 109 | + package func applies(to descriptor: MethodDescriptor) -> Bool { |
| 110 | + self.predicate(descriptor) |
| 111 | + } |
67 | 112 | }
|
68 | 113 |
|
69 | 114 | /// The interceptor.
|
|
0 commit comments