use super::{ encryption::BucketSSEConfig, event, lifecycle::lifecycle::Lifecycle, objectlock, policy::bucket_policy::BucketPolicy, quota::BucketQuota, replication, tags::Tags, target::BucketTargets, versioning::Versioning, }; use byteorder::{BigEndian, ByteOrder, LittleEndian}; use rmp_serde::Serializer as rmpSerializer; use serde::Serializer; use serde::{Deserialize, Deserializer, Serialize}; use std::collections::HashMap; use std::fmt::Display; use std::str::FromStr; use time::OffsetDateTime; use tracing::error; use crate::bucket::tags; use crate::config::common::{read_config, save_config}; use crate::config::error::ConfigError; use crate::error::{Error, Result}; use crate::disk::BUCKET_META_PREFIX; use crate::store::ECStore; use crate::store_api::StorageAPI; pub const BUCKET_METADATA_FILE: &str = ".metadata.bin"; pub const BUCKET_METADATA_FORMAT: u16 = 1; pub const BUCKET_METADATA_VERSION: u16 = 1; #[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "PascalCase", default)] pub struct BucketMetadata { pub name: String, pub created: OffsetDateTime, pub lock_enabled: bool, // 虽然标记为不使用,但可能需要保留 pub policy_config_json: Vec, pub notification_config_xml: Vec, pub lifecycle_config_xml: Vec, pub object_lock_config_xml: Vec, pub versioning_config_xml: Vec, pub encryption_config_xml: Vec, pub tagging_config_xml: Vec, pub quota_config_json: Vec, pub replication_config_xml: Vec, pub bucket_targets_config_json: Vec, pub bucket_targets_config_meta_json: Vec, pub policy_config_updated_at: OffsetDateTime, pub object_lock_config_updated_at: OffsetDateTime, pub encryption_config_updated_at: OffsetDateTime, pub tagging_config_updated_at: OffsetDateTime, pub quota_config_updated_at: OffsetDateTime, pub replication_config_updated_at: OffsetDateTime, pub versioning_config_updated_at: OffsetDateTime, pub lifecycle_config_updated_at: OffsetDateTime, pub notification_config_updated_at: OffsetDateTime, pub bucket_targets_config_updated_at: OffsetDateTime, pub bucket_targets_config_meta_updated_at: OffsetDateTime, #[serde(skip)] pub new_field_updated_at: OffsetDateTime, #[serde(skip)] pub policy_config: Option, #[serde(skip)] pub notification_config: Option, #[serde(skip)] pub lifecycle_config: Option, #[serde(skip)] pub object_lock_config: Option, #[serde(skip)] pub versioning_config: Option, #[serde(skip)] pub sse_config: Option, #[serde(skip)] pub tagging_config: Option, #[serde(skip)] pub quota_config: Option, #[serde(skip)] pub replication_config: Option, #[serde(skip)] pub bucket_target_config: Option, #[serde(skip)] pub bucket_target_config_meta: Option>, } impl Default for BucketMetadata { fn default() -> Self { Self { name: Default::default(), created: OffsetDateTime::UNIX_EPOCH, lock_enabled: Default::default(), policy_config_json: Default::default(), notification_config_xml: Default::default(), lifecycle_config_xml: Default::default(), object_lock_config_xml: Default::default(), versioning_config_xml: Default::default(), encryption_config_xml: Default::default(), tagging_config_xml: Default::default(), quota_config_json: Default::default(), replication_config_xml: Default::default(), bucket_targets_config_json: Default::default(), bucket_targets_config_meta_json: Default::default(), policy_config_updated_at: OffsetDateTime::UNIX_EPOCH, object_lock_config_updated_at: OffsetDateTime::UNIX_EPOCH, encryption_config_updated_at: OffsetDateTime::UNIX_EPOCH, tagging_config_updated_at: OffsetDateTime::UNIX_EPOCH, quota_config_updated_at: OffsetDateTime::UNIX_EPOCH, replication_config_updated_at: OffsetDateTime::UNIX_EPOCH, versioning_config_updated_at: OffsetDateTime::UNIX_EPOCH, lifecycle_config_updated_at: OffsetDateTime::UNIX_EPOCH, notification_config_updated_at: OffsetDateTime::UNIX_EPOCH, bucket_targets_config_updated_at: OffsetDateTime::UNIX_EPOCH, bucket_targets_config_meta_updated_at: OffsetDateTime::UNIX_EPOCH, new_field_updated_at: OffsetDateTime::UNIX_EPOCH, policy_config: Default::default(), notification_config: Default::default(), lifecycle_config: Default::default(), object_lock_config: Default::default(), versioning_config: Default::default(), sse_config: Default::default(), tagging_config: Default::default(), quota_config: Default::default(), replication_config: Default::default(), bucket_target_config: Default::default(), bucket_target_config_meta: Default::default(), } } } impl BucketMetadata { pub fn new(name: &str) -> Self { BucketMetadata { name: name.to_string(), ..Default::default() } } pub fn save_file_path(&self) -> String { format!("{}/{}/{}", BUCKET_META_PREFIX, self.name.as_str(), BUCKET_METADATA_FILE) } // fn msg_size(&self) -> usize { // unimplemented!() // } pub fn marshal_msg(&self) -> Result> { let mut buf = Vec::new(); self.serialize(&mut rmpSerializer::new(&mut buf).with_struct_map())?; Ok(buf) } pub fn unmarshal(buf: &[u8]) -> Result { let t: BucketMetadata = rmp_serde::from_slice(buf)?; Ok(t) } pub fn check_header(buf: &[u8]) -> Result<()> { if buf.len() <= 4 { return Err(Error::msg("read_bucket_metadata: data invalid")); } // TODO: check version Ok(()) } fn default_timestamps(&mut self) { if self.tagging_config_updated_at == OffsetDateTime::UNIX_EPOCH { self.tagging_config_updated_at = self.created } } async fn save(&mut self, api: &ECStore) -> Result<()> { self.parse_all_configs(api)?; let mut buf: Vec = vec![0; 4]; LittleEndian::write_u16(&mut buf[0..2], BUCKET_METADATA_FORMAT); LittleEndian::write_u16(&mut buf[2..4], BUCKET_METADATA_VERSION); let data = self.marshal_msg()?; buf.extend_from_slice(&data); save_config(api, self.save_file_path().as_str(), &buf).await?; Ok(()) } fn parse_all_configs(&mut self, _api: &ECStore) -> Result<()> { if !self.tagging_config_xml.is_empty() { self.tagging_config = Some(tags::Tags::unmarshal(&self.tagging_config_xml)?); } Ok(()) } } pub async fn load_bucket_metadata(api: &ECStore, bucket: &str) -> Result { load_bucket_metadata_parse(api, bucket, true).await } async fn load_bucket_metadata_parse(api: &ECStore, bucket: &str, parse: bool) -> Result { let mut bm = match read_bucket_metadata(api, bucket).await { Ok(res) => res, Err(err) => { if let Some(e) = err.downcast_ref::() { if !ConfigError::is_not_found(&e) { return Err(err); } } BucketMetadata::new(bucket) } }; bm.default_timestamps(); if parse { bm.parse_all_configs(api)?; } // TODO: parse_all_configs Ok(bm) } async fn read_bucket_metadata(api: &ECStore, bucket: &str) -> Result { if bucket.is_empty() { error!("bucket name empty"); return Err(Error::msg("invalid argument")); } let bm = BucketMetadata::new(&bucket); let file_path = bm.save_file_path(); let data = read_config(api, &file_path).await?; BucketMetadata::check_header(&data)?; BucketMetadata::unmarshal(&data[4..]) } fn _deserialize_from_str<'de, S, D>(deserializer: D) -> core::result::Result where S: FromStr, S::Err: Display, D: Deserializer<'de>, { // let s: String = Deserialize::deserialize(deserializer)?; // S::from_str(&s).map_err(de::Error::custom) unimplemented!() } fn _write_time(t: &OffsetDateTime, s: S) -> Result where S: Serializer, { let mut buf = vec![0x0; 15]; let sec = t.unix_timestamp() - 62135596800; let nsec = t.nanosecond(); buf[0] = 0xc7; // mext8 buf[1] = 0x0c; // 长度 buf[2] = 0x05; // 时间扩展类型 BigEndian::write_u64(&mut buf[3..], sec as u64); BigEndian::write_u32(&mut buf[11..], nsec as u32); s.serialize_bytes(&buf) } #[cfg(test)] mod test { use super::*; #[tokio::test] async fn marshal_msg() { // write_time(OffsetDateTime::UNIX_EPOCH).unwrap(); let bm = BucketMetadata::new("dada"); let buf = bm.marshal_msg().unwrap(); let new = BucketMetadata::unmarshal(&buf).unwrap(); assert_eq!(bm.name, new.name); } }