@@ -61,13 +61,14 @@ class ChannelInfo:
6161 """The protocol to use for the channel."""
6262
6363
64- def open_channel (url : str , auth_token : str | None = None ) -> Channel :
64+ def open_channel (url : str , auth_token : str | None = None , rpc_method_prefix : str | None = None ) -> Channel :
6565 """Open a sync gRPC channel to the given URL.
6666
6767 Args:
6868 url: The URL to open a channel to. Depending on the URL, the channel will be a secure (SSL) or insecure channel.
6969 auth_token: Authentication token for the channel. If set, an interceptor channel will be created which adds
7070 the given token as metadata to each request.
71+ rpc_method_prefix: Optional prefix to prepend to each outgoing RPC method path, e.g. `/public`.
7172
7273 Returns:
7374 A sync gRPC channel.
@@ -76,6 +77,8 @@ def open_channel(url: str, auth_token: str | None = None) -> Channel:
7677 interceptors : list [UnaryUnaryClientInterceptor ] = []
7778 if auth_token is not None :
7879 interceptors = [_AuthMetadataInterceptor (auth_token ), * interceptors ] # add auth interceptor as the first one
80+ if rpc_method_prefix is not None :
81+ interceptors = [* interceptors , _RpcMethodPrefixInterceptor (rpc_method_prefix )]
7982
8083 return intercept_channel (_open_channel (channel_info ), * interceptors )
8184
@@ -165,15 +168,63 @@ def intercept_unary_unary(
165168 return continuation (add_metadata (client_call_details , [self ._auth ]), request )
166169
167170
171+ class _RpcMethodPrefixInterceptor (UnaryUnaryClientInterceptor ):
172+ def __init__ (self , prefix : str ) -> None :
173+ """A sync gRPC channel interceptor which prefixes every outgoing RPC method path."""
174+ super ().__init__ ()
175+ self ._prefix = prefix
176+
177+ def intercept_unary_unary (
178+ self ,
179+ continuation : Callable [[ClientCallDetails , RequestType ], ResponseType ],
180+ client_call_details : ClientCallDetails ,
181+ request : RequestType ,
182+ ) -> ResponseType :
183+ return continuation (update_method (client_call_details , self ._prefix ), request )
184+
185+
168186def add_metadata (
169187 client_call_details : ClientCallDetails , additional_metadata : list [tuple [str , str ]]
170188) -> ClientCallDetails :
171189 metadata = [] if client_call_details .metadata is None else list (client_call_details .metadata )
172190 metadata .extend (additional_metadata )
191+ return _replace_call_details (client_call_details , metadata = metadata )
192+
193+
194+ def update_method (client_call_details : ClientCallDetails , prefix : str ) -> ClientCallDetails :
195+ return _replace_call_details (client_call_details , method = prefix_rpc_method (client_call_details .method , prefix ))
196+
197+
198+ def prefix_rpc_method (method : str | bytes , prefix : str ) -> str | bytes :
199+ normalized_prefix = prefix .strip ("/" )
200+ if normalized_prefix == "" :
201+ return method
202+
203+ if isinstance (method , bytes ):
204+ prefix_bytes = f"/{ normalized_prefix } " .encode ()
205+ normalized_method = method if method .startswith (b"/" ) else b"/" + method
206+ if normalized_method == prefix_bytes or normalized_method .startswith (prefix_bytes + b"/" ):
207+ return normalized_method
208+ return prefix_bytes + normalized_method
209+
210+ prefix = f"/{ normalized_prefix } "
211+ normalized_method = method if method .startswith ("/" ) else f"/{ method } "
212+ if normalized_method == prefix or normalized_method .startswith (f"{ prefix } /" ):
213+ return normalized_method
214+
215+ return f"{ prefix } { normalized_method } "
216+
217+
218+ def _replace_call_details (
219+ client_call_details : ClientCallDetails ,
220+ * ,
221+ method : str | bytes | None = None ,
222+ metadata : list [tuple [str , str ]] | None = None ,
223+ ) -> ClientCallDetails :
173224 return ClientCallDetails (
174- client_call_details .method ,
225+ client_call_details .method if method is None else method ,
175226 client_call_details .timeout ,
176- metadata ,
227+ client_call_details . metadata if metadata is None else metadata ,
177228 client_call_details .credentials ,
178229 client_call_details .wait_for_ready ,
179230 )
0 commit comments