gemini_rust/file_search/
operation_handle.rs1use std::sync::Arc;
2use std::time::{Duration, Instant};
3use tracing::instrument;
4
5use crate::client::{Error, GeminiClient};
6use crate::file_search::model::{Operation, OperationResult};
7
8#[derive(Debug, Clone)]
14pub struct OperationHandle {
15 client: Arc<GeminiClient>,
16 operation: Operation,
17}
18
19impl OperationHandle {
20 pub fn new(client: Arc<GeminiClient>, operation: Operation) -> Self {
21 Self { client, operation }
22 }
23
24 pub fn name(&self) -> &str {
25 &self.operation.name
26 }
27
28 pub fn is_done(&self) -> bool {
29 self.operation.done.unwrap_or(false)
30 }
31
32 pub fn result(&self) -> Option<&OperationResult> {
33 self.operation.result.as_ref()
34 }
35
36 #[instrument(skip_all, fields(operation.name = %self.operation.name))]
37 pub async fn refresh(&mut self) -> Result<(), Error> {
38 self.operation = self.client.get_operation(&self.operation.name).await?;
39 Ok(())
40 }
41
42 #[instrument(skip_all, fields(
43 operation.name = %self.operation.name,
44 poll.interval.secs = interval.as_secs(),
45 timeout.secs = timeout.as_ref().map(|d| d.as_secs()),
46 ))]
47 pub async fn wait_until_done(
48 &mut self,
49 interval: Duration,
50 timeout: Option<Duration>,
51 ) -> Result<(), Error> {
52 let start = Instant::now();
53
54 while !self.operation.done.unwrap_or(false) {
55 if let Some(timeout) = timeout {
56 if start.elapsed() >= timeout {
57 return Err(Error::OperationTimeout {
58 name: self.operation.name.clone(),
59 });
60 }
61 }
62
63 tokio::time::sleep(interval).await;
64 self.refresh().await?;
65 }
66
67 if let Some(OperationResult::Error { error }) = &self.operation.result {
68 return Err(Error::OperationFailed {
69 name: self.operation.name.clone(),
70 code: error.code,
71 message: error.message.clone(),
72 });
73 }
74
75 Ok(())
76 }
77}