use std::collections::HashMap; use serde::{Deserialize, Serialize}; use worker::*; use crate::claim::SitesStore; #[derive(Deserialize)] #[serde(untagged)] pub enum RepoEntry { New { rkey: String, #[serde(default)] is_index: bool, }, Legacy(bool), } impl RepoEntry { pub fn is_index(&self) -> bool { match self { RepoEntry::New { is_index, .. } => *is_index, RepoEntry::Legacy(b) => *b, } } pub fn rkey<'a>(&'a self, name: &'a str) -> &'a str { match self { RepoEntry::New { rkey, .. } => rkey.as_str(), RepoEntry::Legacy(_) => name, } } } #[derive(Deserialize)] pub struct DomainMapping { #[serde(default)] pub did: String, #[serde(default)] pub repos: HashMap, } impl DomainMapping { pub fn index_repo(&self) -> Option<(&str, &RepoEntry)> { self.repos.iter().find_map(|(name, entry)| { if entry.is_index() { Some((name.as_str(), entry)) } else { None } }) } } #[derive(Serialize)] struct MappingEntry { rkey: String, #[serde(default)] is_index: bool, } #[derive(Serialize)] struct WriteMapping { did: String, repos: HashMap, } pub async fn rebuild_for_domain( kv: &KvStore, store: &SitesStore, domain: &str, ) -> Result<(), String> { match store.mapping_rows_for_domain(domain).await? { None => { kv.put(domain, "{}") .map_err(|e| e.to_string())? .execute() .await .map_err(|e| e.to_string())?; } Some((owner_did, sites_list)) => { let mut repos = HashMap::with_capacity(sites_list.len()); for (name, rkey, is_index) in sites_list { repos.insert(name, MappingEntry { rkey, is_index }); } let mapping = WriteMapping { did: owner_did, repos, }; let raw = serde_json::to_string(&mapping).map_err(|e| e.to_string())?; kv.put(domain, raw) .map_err(|e| e.to_string())? .execute() .await .map_err(|e| e.to_string())?; } } Ok(()) } pub async fn delete_r2_prefix(bucket: &Bucket, prefix: &str) -> Result<(), String> { let mut cursor: Option = None; loop { let mut list = bucket.list().prefix(prefix.to_string()).limit(1000); if let Some(c) = cursor { list = list.cursor(c); } let objects = list.execute().await.map_err(|e| e.to_string())?; let keys: Vec = objects.objects().iter().map(|o| o.key()).collect(); if !keys.is_empty() { bucket .delete_multiple(keys) .await .map_err(|e| e.to_string())?; } if !objects.truncated() { break; } match objects.cursor() { Some(c) => cursor = Some(c), None => break, } } Ok(()) }