Skip to content

Commit 43e76b3

Browse files
committed
add user defined interceptor
1 parent 7351cfd commit 43e76b3

11 files changed

Lines changed: 127 additions & 86 deletions

File tree

src/auth.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,31 @@ impl Interceptor for TokenInterceptor {
2525
Ok(req)
2626
}
2727
}
28+
29+
#[derive(Clone)]
30+
pub struct WrappedInterceptor<I: Send + Sync + 'static + Clone + Interceptor = TokenInterceptor> {
31+
pub inner: Option<I>,
32+
}
33+
34+
impl<I: Send + Sync + 'static + Clone + Interceptor> Default for WrappedInterceptor<I> {
35+
fn default() -> Self {
36+
Self { inner: None }
37+
}
38+
}
39+
40+
impl<I: Send + Sync + 'static + Clone + Interceptor> WrappedInterceptor<I> {
41+
pub fn new(interceptor: I) -> Self {
42+
Self {
43+
inner: Some(interceptor),
44+
}
45+
}
46+
}
47+
48+
impl<I: Send + Sync + 'static + Clone + Interceptor> Interceptor for WrappedInterceptor<I> {
49+
fn call(&mut self, req: Request<()>) -> anyhow::Result<Request<()>, Status> {
50+
match self.inner.as_mut() {
51+
Some(inter) => inter.call(req),
52+
None => Ok(req),
53+
}
54+
}
55+
}

src/qdrant_client/collection.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use tonic::service::Interceptor;
55
use tonic::transport::Channel;
66
use tonic::Status;
77

8+
use crate::auth::WrappedInterceptor;
89
use crate::qdrant::collections_client::CollectionsClient;
910
use crate::qdrant::{
1011
alias_operations, AliasOperations, ChangeAliases, CollectionClusterInfoRequest,
@@ -14,18 +15,18 @@ use crate::qdrant::{
1415
ListCollectionAliasesRequest, ListCollectionsRequest, ListCollectionsResponse, RenameAlias,
1516
UpdateCollection, UpdateCollectionClusterSetupRequest, UpdateCollectionClusterSetupResponse,
1617
};
17-
use crate::qdrant_client::{Qdrant, QdrantResult};
18+
use crate::qdrant_client::{GenericQdrant, QdrantResult};
1819

1920
/// # Collection operations
2021
///
2122
/// Create, update and delete collections, manage collection aliases and collection cluster
2223
/// configuration.
2324
///
2425
/// Documentation: <https://qdrant.tech/documentation/concepts/collections/>
25-
impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
26+
impl<I: Send + Sync + 'static + Clone + Interceptor> GenericQdrant<I> {
2627
pub(super) async fn with_collections_client<T, O: Future<Output = Result<T, Status>>>(
2728
&self,
28-
f: impl Fn(CollectionsClient<InterceptedService<Channel, I>>) -> O,
29+
f: impl Fn(CollectionsClient<InterceptedService<Channel, WrappedInterceptor<I>>>) -> O,
2930
) -> QdrantResult<T> {
3031
let result = self
3132
.channel
@@ -441,6 +442,7 @@ mod tests {
441442
CountPointsBuilder, Distance, PointStruct, SearchPointsBuilder, UpsertPointsBuilder,
442443
VectorParamsBuilder,
443444
};
445+
use crate::Qdrant;
444446

445447
#[tokio::test]
446448
async fn create_collection_and_do_the_search() -> QdrantResult<()> {

src/qdrant_client/config.rs

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ use std::time::Duration;
22

33
use tonic::service::Interceptor;
44

5-
use crate::{auth::TokenInterceptor, Qdrant, QdrantError};
5+
use crate::auth::{TokenInterceptor, WrappedInterceptor};
6+
use crate::qdrant_client::GenericQdrant;
7+
use crate::QdrantError;
68

7-
struct DefaultConfigValues {
9+
struct DefaultConfigValues<I: Send + Sync + 'static + Clone + Interceptor = TokenInterceptor> {
810
timeout: Duration,
911
connect_timeout: Duration,
1012
keep_alive_while_idle: bool,
1113
compression: Option<CompressionEncoding>,
1214
check_compatibility: bool,
1315
pool_size: usize,
16+
interceptor: WrappedInterceptor<I>,
1417
}
1518

16-
impl Default for DefaultConfigValues {
19+
impl<I: Send + Sync + 'static + Clone + Interceptor> Default for DefaultConfigValues<I> {
1720
fn default() -> Self {
1821
Self {
1922
timeout: Duration::from_secs(5),
@@ -22,6 +25,7 @@ impl Default for DefaultConfigValues {
2225
compression: None,
2326
check_compatibility: true,
2427
pool_size: 3,
28+
interceptor: WrappedInterceptor::<I>::default(),
2529
}
2630
}
2731
}
@@ -65,11 +69,11 @@ pub struct QdrantConfig<I: Send + Sync + 'static + Clone + Interceptor = TokenIn
6569
pub pool_size: usize,
6670

6771
/// The interceptor to use for modifying requests
68-
pub interceptor: I,
72+
pub interceptor: WrappedInterceptor<I>,
6973
}
7074

7175
impl<I: Send + Sync + 'static + Clone + Interceptor> QdrantConfig<I> {
72-
fn with_defaults(url: &str, interceptor: I) -> Self {
76+
fn with_defaults(url: &str) -> Self {
7377
let defaults = DefaultConfigValues::default();
7478
Self {
7579
uri: url.to_string(),
@@ -79,12 +83,20 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> QdrantConfig<I> {
7983
compression: defaults.compression,
8084
check_compatibility: defaults.check_compatibility,
8185
pool_size: defaults.pool_size,
82-
interceptor,
86+
interceptor: defaults.interceptor,
8387
}
8488
}
8589

86-
pub fn from_url_with_interceptor(url: &str, interceptor: I) -> Self {
87-
Self::with_defaults(url, interceptor)
90+
/// Start configuring a Qdrant client with an URL
91+
///
92+
/// ```rust,no_run
93+
///# use qdrant_client::config::QdrantConfig;
94+
/// let client = QdrantConfig::from_url("http://localhost:6334").build();
95+
/// ```
96+
///
97+
/// This is normally done through [`Qdrant::from_url`](crate::Qdrant::from_url).
98+
pub fn from_url(url: &str) -> Self {
99+
Self::with_defaults(url)
88100
}
89101

90102
/// Keep the connection alive while idle
@@ -136,6 +148,33 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> QdrantConfig<I> {
136148
self
137149
}
138150

151+
/// Set the interceptor to use for this client
152+
///
153+
/// ```no_run
154+
/// use qdrant_client::GenericQdrant;
155+
/// use tonic::service::Interceptor;
156+
/// use tonic::{Request, Status};
157+
///
158+
/// #[derive(Clone)]
159+
/// struct CustomInterceptor;
160+
/// impl Interceptor for CustomInterceptor {
161+
/// fn call(&mut self, req: Request<()>) -> Result<Request<()>, Status> {
162+
/// Ok(req)
163+
/// }
164+
/// }
165+
///
166+
///# async fn connect() -> Result<(), qdrant_client::QdrantError> {
167+
/// let client = GenericQdrant<CustomInterceptor>::from_url("http://localhost:6334")
168+
/// .interceptor(CustomInterceptor)
169+
/// .build()?;
170+
///# Ok(())
171+
///# }
172+
/// ```
173+
pub fn interceptor(mut self, interceptor: I) -> Self {
174+
self.interceptor = WrappedInterceptor::new(interceptor);
175+
self
176+
}
177+
139178
/// Set the timeout for this client
140179
///
141180
/// Also see [`timeout()`](fn@Self::timeout).
@@ -164,9 +203,16 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> QdrantConfig<I> {
164203
self.compression = compression;
165204
}
166205

206+
/// Set the interceptor to use for this client
207+
///
208+
/// Also see [`interceptor()`](fn@Self::interceptor).
209+
pub fn set_interceptor(&mut self, interceptor: I) {
210+
self.interceptor = WrappedInterceptor::new(interceptor);
211+
}
212+
167213
/// Build the configured [`Qdrant`] client
168-
pub fn build(self) -> Result<Qdrant<I>, QdrantError> {
169-
Qdrant::new(self)
214+
pub fn build(self) -> Result<GenericQdrant<I>, QdrantError> {
215+
GenericQdrant::new(self)
170216
}
171217

172218
pub fn skip_compatibility_check(mut self) -> Self {
@@ -182,18 +228,6 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> QdrantConfig<I> {
182228
}
183229

184230
impl QdrantConfig<TokenInterceptor> {
185-
/// Start configuring a Qdrant client with an URL
186-
///
187-
/// ```rust,no_run
188-
///# use qdrant_client::config::QdrantConfig;
189-
/// let client = QdrantConfig::from_url("http://localhost:6334").build();
190-
/// ```
191-
///
192-
/// This is normally done through [`Qdrant::from_url`](crate::Qdrant::from_url).
193-
pub fn from_url(url: &str) -> Self {
194-
Self::with_defaults(url, TokenInterceptor::new(None))
195-
}
196-
197231
/// Set an optional API key
198232
///
199233
/// This method is only available when using the default TokenInterceptor.
@@ -209,15 +243,16 @@ impl QdrantConfig<TokenInterceptor> {
209243
/// .build();
210244
/// ```
211245
pub fn api_key(mut self, api_key: impl AsOptionApiKey) -> Self {
212-
self.interceptor = TokenInterceptor::new(api_key.api_key());
246+
self.interceptor = WrappedInterceptor::new(TokenInterceptor::new(api_key.api_key()));
213247
self
214248
}
215249

216250
/// Set an API key
217251
///
218252
/// Also see [`api_key()`](fn@Self::api_key).
219253
pub fn set_api_key(&mut self, api_key: &str) {
220-
self.interceptor = TokenInterceptor::new(Some(api_key.to_string()));
254+
self.interceptor =
255+
WrappedInterceptor::new(TokenInterceptor::new(Some(api_key.to_string())));
221256
}
222257
}
223258

@@ -226,7 +261,7 @@ impl QdrantConfig<TokenInterceptor> {
226261
/// Connects to `http://localhost:6334` without an API key.
227262
impl Default for QdrantConfig<TokenInterceptor> {
228263
fn default() -> Self {
229-
Self::with_defaults("http://localhost:6334", TokenInterceptor::new(None))
264+
Self::with_defaults("http://localhost:6334")
230265
}
231266
}
232267

src/qdrant_client/index.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use tonic::service::Interceptor;
33
use crate::qdrant::{
44
CreateFieldIndexCollection, DeleteFieldIndexCollection, PointsOperationResponse,
55
};
6-
use crate::qdrant_client::{Qdrant, QdrantResult};
6+
use crate::qdrant_client::{GenericQdrant, QdrantResult};
77

88
/// # Index operations
99
///
1010
/// Manage field and payload indices in collections.
1111
///
1212
/// Documentation: <https://qdrant.tech/documentation/concepts/indexing/>
13-
impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
13+
impl<I: Send + Sync + 'static + Clone + Interceptor> GenericQdrant<I> {
1414
/// Create payload index in a collection.
1515
///
1616
/// ```no_run

src/qdrant_client/mod.rs

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use tonic::service::Interceptor;
2121
use tonic::transport::{Channel, Uri};
2222
use tonic::Status;
2323

24-
use crate::auth::TokenInterceptor;
24+
use crate::auth::{TokenInterceptor, WrappedInterceptor};
2525
use crate::channel_pool::ChannelPool;
2626
use crate::qdrant::{qdrant_client, HealthCheckReply, HealthCheckRequest};
2727
use crate::qdrant_client::config::QdrantConfig;
@@ -33,6 +33,7 @@ pub type QdrantResult<T> = Result<T, QdrantError>;
3333

3434
/// A builder for [`Qdrant`]
3535
pub type QdrantBuilder = QdrantConfig;
36+
pub type Qdrant = GenericQdrant<TokenInterceptor>;
3637

3738
/// API client to interact with a [Qdrant](https://qdrant.tech/) server.
3839
///
@@ -84,7 +85,7 @@ pub type QdrantBuilder = QdrantConfig;
8485
/// - [`upsert_points`](Self::upsert_points) - insert or update points
8586
/// - [`query`](Self::query) - query points with similarity search
8687
#[derive(Clone)]
87-
pub struct Qdrant<I: Send + Sync + 'static + Clone + Interceptor = TokenInterceptor> {
88+
pub struct GenericQdrant<I: Send + Sync + 'static + Clone + Interceptor> {
8889
/// Client configuration
8990
pub config: QdrantConfig<I>,
9091

@@ -95,7 +96,7 @@ pub struct Qdrant<I: Send + Sync + 'static + Clone + Interceptor = TokenIntercep
9596
/// # Construct and connect
9697
///
9798
/// Methods to construct a new Qdrant client.
98-
impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
99+
impl<I: Send + Sync + 'static + Clone + Interceptor> GenericQdrant<I> {
99100
/// Create a new Qdrant client.
100101
///
101102
/// Constructs the client and connects based on the given [`QdrantConfig`](config::QdrantConfig).
@@ -163,42 +164,34 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
163164
Ok(client)
164165
}
165166

166-
/// Build a new Qdrant client with the given URL and custom interceptor.
167+
/// Build a new Qdrant client with the given URL.
167168
///
168169
/// ```no_run
169170
/// use qdrant_client::Qdrant;
170-
/// use tonic::service::Interceptor;
171-
/// use tonic::{Request, Status};
172-
///
173-
/// #[derive(Clone)]
174-
/// struct CustomInterceptor;
175-
/// impl Interceptor for CustomInterceptor {
176-
/// fn call(&mut self, req: Request<()>) -> Result<Request<()>, Status> {
177-
/// Ok(req)
178-
/// }
179-
/// }
180171
///
181172
///# async fn connect() -> Result<(), qdrant_client::QdrantError> {
182-
/// let client = Qdrant::from_url_with_interceptor(
183-
/// "http://localhost:6334",
184-
/// CustomInterceptor
185-
/// ).build()?;
173+
/// let client = Qdrant::from_url("http://localhost:6334").build()?;
186174
///# Ok(())
187175
///# }
188176
/// ```
189-
pub fn from_url_with_interceptor(url: &str, interceptor: I) -> QdrantConfig<I> {
190-
QdrantConfig::<I>::from_url_with_interceptor(url, interceptor)
177+
///
178+
/// See more ways to set up the client [here](Self#set-up).
179+
pub fn from_url(url: &str) -> QdrantConfig<I> {
180+
QdrantConfig::<I>::from_url(url)
191181
}
192182

193183
/// Wraps a channel with the configured interceptor
194-
fn with_interceptor(&self, channel: Channel) -> InterceptedService<Channel, I> {
184+
fn with_interceptor(
185+
&self,
186+
channel: Channel,
187+
) -> InterceptedService<Channel, WrappedInterceptor<I>> {
195188
InterceptedService::new(channel, self.config.interceptor.clone())
196189
}
197190

198191
// Access to raw root qdrant API
199192
async fn with_root_qdrant_client<T, O: Future<Output = Result<T, Status>>>(
200193
&self,
201-
f: impl Fn(qdrant_client::QdrantClient<InterceptedService<Channel, I>>) -> O,
194+
f: impl Fn(qdrant_client::QdrantClient<InterceptedService<Channel, WrappedInterceptor<I>>>) -> O,
202195
) -> QdrantResult<T> {
203196
let result = self
204197
.channel
@@ -240,21 +233,3 @@ impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
240233
.await
241234
}
242235
}
243-
244-
impl Qdrant<TokenInterceptor> {
245-
/// Build a new Qdrant client with the given URL.
246-
///
247-
/// ```no_run
248-
/// use qdrant_client::Qdrant;
249-
///
250-
///# async fn connect() -> Result<(), qdrant_client::QdrantError> {
251-
/// let client = Qdrant::from_url("http://localhost:6334").build()?;
252-
///# Ok(())
253-
///# }
254-
/// ```
255-
///
256-
/// See more ways to set up the client [here](Self#set-up).
257-
pub fn from_url(url: &str) -> QdrantBuilder {
258-
QdrantBuilder::from_url(url)
259-
}
260-
}

src/qdrant_client/payload.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use tonic::service::Interceptor;
33
use crate::qdrant::{
44
ClearPayloadPoints, DeletePayloadPoints, PointsOperationResponse, SetPayloadPoints,
55
};
6-
use crate::qdrant_client::{Qdrant, QdrantResult};
6+
use crate::qdrant_client::{GenericQdrant, QdrantResult};
77

88
/// # Payload operations
99
///
1010
/// Manage point payloads.
1111
///
1212
/// Documentation: <https://qdrant.tech/documentation/concepts/payload/>
13-
impl<I: Send + Sync + 'static + Clone + Interceptor> Qdrant<I> {
13+
impl<I: Send + Sync + 'static + Clone + Interceptor> GenericQdrant<I> {
1414
/// Set payload of points.
1515
///
1616
/// Sets only the given payload values on a point, leaving other existing payloads in place.

0 commit comments

Comments
 (0)