biolib 1.3.117

BioLib client library and CLI for running applications on BioLib
Documentation
use std::cell::RefCell;
use std::time::{Duration, Instant};

use crate::api::ApiClient;

pub trait RemoteEndpoint {
    fn get_remote_url(&self) -> crate::Result<String>;
}

pub struct RemoteJobStorageEndpoint {
    job_uuid: String,
    job_auth_token: String,
    storage_type: String,
    presigned_url: RefCell<Option<String>>,
    fetched_at: RefCell<Option<Instant>>,
}

// 8-minute TTL matching Python client's RemoteJobStorageEndpoint
const PRESIGNED_URL_TTL: Duration = Duration::from_secs(8 * 60);

impl RemoteJobStorageEndpoint {
    pub fn new(job_uuid: String, job_auth_token: String, storage_type: String) -> Self {
        Self {
            job_uuid,
            job_auth_token,
            storage_type,
            presigned_url: RefCell::new(None),
            fetched_at: RefCell::new(None),
        }
    }
}

impl RemoteEndpoint for RemoteJobStorageEndpoint {
    fn get_remote_url(&self) -> crate::Result<String> {
        let needs_refresh = {
            let url = self.presigned_url.borrow();
            let fetched = self.fetched_at.borrow();
            url.is_none() || fetched.is_none_or(|t| t.elapsed() > PRESIGNED_URL_TTL)
        };

        if needs_refresh {
            let config = crate::Config::load();
            let mut client = ApiClient::new(&config)?;
            let url = client.get_job_storage_download_url(
                &self.job_uuid,
                &self.job_auth_token,
                &self.storage_type,
            )?;
            crate::logging::debug(&format!(
                "Job \"{}\" fetched presigned URL (TTL {}s)",
                self.job_uuid,
                PRESIGNED_URL_TTL.as_secs()
            ));
            *self.presigned_url.borrow_mut() = Some(url);
            *self.fetched_at.borrow_mut() = Some(Instant::now());
        }

        Ok(self.presigned_url.borrow().clone().unwrap())
    }
}