use bigml::{wait::BackoffType, WaitOptions};
use serde::{
de::{self, Deserializer, Visitor},
Deserialize,
};
use std::{fmt, marker::PhantomData, str::FromStr, time::Duration};
use crate::common::*;
mod download_file;
mod ls;
mod rm_r;
mod upload_file;
pub(crate) use download_file::download_file;
pub(crate) use ls::ls;
pub(crate) use rm_r::rm_r;
pub(crate) use upload_file::upload_file;
#[cfg(not(debug_assertions))]
pub(crate) const CHUNK_SIZE: u64 = 1024 * 1024;
#[cfg(debug_assertions)]
pub(crate) const CHUNK_SIZE: u64 = 128;
pub(crate) fn parse_gs_url(url: &Url) -> Result<(String, String)> {
if url.scheme() != "gs" {
Err(format_err!("expected a gs:// URL, found {}", url))
} else {
let bucket = url
.host_str()
.ok_or_else(|| format_err!("could not get bucket from {}", url))?
.to_owned();
let object = url.path()[1..].to_owned();
Ok((bucket, object))
}
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct StorageObject {
pub(crate) bucket: String,
pub(crate) name: String,
pub(crate) etag: String,
#[serde(deserialize_with = "deserialize_int::<'_, u64, _>")]
pub(crate) size: u64,
pub(crate) crc32c: String,
#[serde(deserialize_with = "deserialize_int::<'_, i64, _>")]
pub(crate) generation: i64,
#[serde(deserialize_with = "deserialize_int::<'_, i64, _>")]
#[allow(dead_code)]
pub(crate) metageneration: i64,
}
impl StorageObject {
pub(crate) fn to_url_string(&self) -> String {
format!("gs://{}/{}", self.bucket, self.name)
}
}
fn deserialize_int<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: FromStr,
<T as FromStr>::Err: fmt::Display,
D: Deserializer<'de>,
{
struct IntVisitor<T>(PhantomData<T>);
impl<'de, T> Visitor<'de> for IntVisitor<T>
where
T: FromStr,
<T as FromStr>::Err: fmt::Display,
{
type Value = T;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a string containing an integer")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
v.parse::<T>().map_err(E::custom)
}
}
deserializer.deserialize_any(IntVisitor(PhantomData))
}
pub(crate) fn gcs_write_access_denied_wait_options() -> WaitOptions {
WaitOptions::default()
.backoff_type(BackoffType::Exponential)
.retry_interval(Duration::from_secs(10))
.allowed_errors(2)
}