use aws_sdk_s3::{config::Region, types::Object, Client, Config};
use chrono::NaiveDate;
use crate::file::FileMetadata;
use crate::result::{Error, Result};
const REGION: &str = "us-east-1";
const BUCKET: &str = "noaa-nexrad-level2";
pub async fn list_files(site: &str, date: &NaiveDate) -> Result<Vec<FileMetadata>> {
let prefix = format!("{}/{}", date.format("%Y/%m/%d"), site);
let objects = list_objects(&get_client().await, BUCKET, &prefix)
.await?
.expect("should return objects");
let metas = objects
.iter()
.map(|object| {
let key = object.key().expect("object should have a key");
let parts: Vec<&str> = key.split("/").collect();
let date_string = parts[0..=2].join("/");
let date = NaiveDate::parse_from_str(&date_string, "%Y/%m/%d")
.expect(&format!("file has valid date: \"{}\"", date_string));
let site = parts[3];
let identifier = parts[4..].join("");
FileMetadata::new(site.to_string(), date, identifier)
})
.collect();
Ok(metas)
}
pub async fn download_file(meta: &FileMetadata) -> Result<Vec<u8>> {
let formatted_date = meta.date().format("%Y/%m/%d");
let key = format!("{}/{}/{}", formatted_date, meta.site(), meta.identifier());
Ok(download_object(&get_client().await, BUCKET, &key).await?)
}
async fn download_object(client: &Client, bucket: &str, key: &str) -> Result<Vec<u8>> {
let operation = client.get_object().bucket(bucket).key(key);
let response = operation.send().await.map_err(|_err| Error::S3GetObjectError)?;
let bytes = response.body.collect().await.map_err(|_err| Error::S3StreamingError)?;
Ok(bytes.to_vec())
}
async fn list_objects(client: &Client, bucket: &str, prefix: &str) -> Result<Option<Vec<Object>>> {
let operation = client.list_objects_v2().bucket(bucket).prefix(prefix);
let response = operation.send().await.map_err(|_err| Error::S3ListObjectsError)?;
Ok(response.contents().map(|objects| objects.to_vec()))
}
async fn get_client() -> Client {
Client::from_conf(
Config::builder()
.region(Region::from_static(REGION))
.build(),
)
}