use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct ContainerLayerId {
pub service: String,
pub instance_id: String,
}
impl ContainerLayerId {
pub fn new(service: impl Into<String>, instance_id: impl Into<String>) -> Self {
Self {
service: service.into(),
instance_id: instance_id.into(),
}
}
#[must_use]
pub fn to_key(&self) -> String {
format!("{}_{}", self.service, self.instance_id)
}
}
impl std::fmt::Display for ContainerLayerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}/{}", self.service, self.instance_id)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LayerSnapshot {
pub digest: String,
pub size_bytes: u64,
pub compressed_size_bytes: u64,
pub created_at: chrono::DateTime<chrono::Utc>,
pub file_count: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncState {
pub container_id: ContainerLayerId,
pub local_digest: Option<String>,
pub remote_digest: Option<String>,
pub last_sync: Option<chrono::DateTime<chrono::Utc>>,
pub pending_upload: Option<PendingUpload>,
}
impl SyncState {
#[must_use]
pub fn new(container_id: ContainerLayerId) -> Self {
Self {
container_id,
local_digest: None,
remote_digest: None,
last_sync: None,
pending_upload: None,
}
}
#[must_use]
pub fn needs_upload(&self) -> bool {
match (&self.local_digest, &self.remote_digest) {
(Some(local), Some(remote)) => local != remote,
(Some(_), None) => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PendingUpload {
pub upload_id: String,
pub object_key: String,
pub total_parts: u32,
pub completed_parts: HashMap<u32, CompletedPart>,
pub part_size: u64,
pub local_tarball_path: PathBuf,
pub started_at: chrono::DateTime<chrono::Utc>,
pub digest: String,
}
impl PendingUpload {
#[must_use]
pub fn missing_parts(&self) -> Vec<u32> {
(1..=self.total_parts)
.filter(|p| !self.completed_parts.contains_key(p))
.collect()
}
#[must_use]
pub fn is_complete(&self) -> bool {
self.completed_parts.len() == self.total_parts as usize
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompletedPart {
pub part_number: u32,
pub e_tag: String,
}