#[doc = include_str!("../README.md")]
use aws_sdk_s3::operation::get_object_attributes::GetObjectAttributesError;
use errors::{AreSameError, ObjectChecksumError};
use log::{debug, error};
use std::io::Error;
use std::path::Path;
mod base64;
mod errors;
#[derive(Debug, PartialEq)]
pub enum Checksum {
Crc64Nvme(u64),
}
pub enum ChecksumType {
Crc64Nvme,
}
pub fn checksum_type(checksum: &Checksum) -> ChecksumType {
match checksum {
Checksum::Crc64Nvme(_) => ChecksumType::Crc64Nvme,
}
}
pub fn file_checksum(t: ChecksumType, path: &Path) -> Result<Checksum, Error> {
match t {
ChecksumType::Crc64Nvme => {
let mut digest = crc64fast_nvme::Digest::new();
digest.write(std::fs::read(path)?.as_slice());
Ok(Checksum::Crc64Nvme(digest.sum64()))
}
}
}
pub async fn object_checksum(
client: &aws_sdk_s3::Client,
uri: &s3uri::S3Uri,
) -> Result<Option<Checksum>, ObjectChecksumError> {
match &uri.key {
Some(k) => {
let response = client
.get_object_attributes()
.bucket(&uri.bucket)
.key(k)
.object_attributes(aws_sdk_s3::types::ObjectAttributes::Checksum)
.send()
.await;
match response {
Ok(attributes) => match attributes.checksum {
Some(checksum_attribute) => match checksum_attribute.checksum_crc64_nvme {
Some(checksum_crc64_nvme) => match base64::to_u64(&checksum_crc64_nvme) {
Ok(checksum) => Ok(Some(Checksum::Crc64Nvme(checksum))),
Err(e) => Err(e.into()),
},
None => Ok(None),
},
None => Ok(None),
},
Err(err) => match err.into_service_error() {
GetObjectAttributesError::NoSuchKey(_) => {
Err(ObjectChecksumError::ObjectNotFound(uri.clone()))
}
e => Err(e.into()),
},
}
}
None => Err(ObjectChecksumError::UriHasNoKey(uri.clone())),
}
}
pub async fn are_same(
client: &aws_sdk_s3::Client,
local: &Path,
remote: &s3uri::S3Uri,
) -> Result<bool, AreSameError> {
match object_checksum(client, remote).await {
Ok(opt_checksum) => match opt_checksum {
Some(remote_checksum) => {
match file_checksum(checksum_type(&remote_checksum), local) {
Ok(local_checksum) => {
let same = remote_checksum == local_checksum;
debug!("{local:?}={local_checksum:?}; {remote}={remote_checksum:?}; same={same}");
Ok(same)
}
Err(e) => {
error!("file_checksum failed ({e})");
Err(e.into())
}
}
}
None => {
debug!("{remote} has no checksum");
Ok(false)
}
},
Err(e) => {
error!("object_checksum failed ({e})");
Err(e.into())
}
}
}