Something went wrong. Try again.
A Transparent and Verifiable Way to Sync the AT Protocol's PLC Directory
Something went wrong. Try again.
Go
at did-resolver
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216package bundle
import ( "fmt" "path/filepath" "time"
"tangled.org/atscan.net/plcbundle/plc")
const ( // BUNDLE_SIZE is the standard number of operations per bundle BUNDLE_SIZE = 10000)
// Bundle represents a PLC bundletype Bundle struct { BundleNumber int `json:"bundle_number"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` Operations []plc.PLCOperation `json:"-"` DIDCount int `json:"did_count"`
Hash string `json:"hash"` // Chain hash (primary) ContentHash string `json:"content_hash"` // Content hash Parent string `json:"parent"`
CompressedHash string `json:"compressed_hash"` CompressedSize int64 `json:"compressed_size"` UncompressedSize int64 `json:"uncompressed_size"` Cursor string `json:"cursor"` BoundaryCIDs []string `json:"boundary_cids,omitempty"` Compressed bool `json:"compressed"` CreatedAt time.Time `json:"created_at"`}
// GetFilePath returns the file path for this bundlefunc (b *Bundle) GetFilePath(bundleDir string) string { return filepath.Join(bundleDir, fmt.Sprintf("%06d.jsonl.zst", b.BundleNumber))}
// GetUncompressedFilePath returns the uncompressed file pathfunc (b *Bundle) GetUncompressedFilePath(bundleDir string) string { return filepath.Join(bundleDir, fmt.Sprintf("%06d.jsonl", b.BundleNumber))}
// OperationCount returns the number of operations (always BUNDLE_SIZE for complete bundles)func (b *Bundle) OperationCount() int { if len(b.Operations) > 0 { return len(b.Operations) } return BUNDLE_SIZE}
// CompressionRatio returns the compression ratiofunc (b *Bundle) CompressionRatio() float64 { if b.CompressedSize == 0 { return 0 } return float64(b.UncompressedSize) / float64(b.CompressedSize)}
// ValidateForSave performs validation before saving (no hash required)func (b *Bundle) ValidateForSave() error { if b.BundleNumber < 1 { return fmt.Errorf("invalid bundle number: %d", b.BundleNumber) } if len(b.Operations) != BUNDLE_SIZE { return fmt.Errorf("invalid operation count: expected %d, got %d", BUNDLE_SIZE, len(b.Operations)) } if b.StartTime.After(b.EndTime) { return fmt.Errorf("start_time is after end_time") } return nil}
// Validate performs full validation (including hashes)func (b *Bundle) Validate() error { if err := b.ValidateForSave(); err != nil { return err } if b.Hash == "" { return fmt.Errorf("missing hash") } if b.CompressedHash == "" { return fmt.Errorf("missing compressed hash") } return nil}
// BundleMetadata represents metadata about a bundletype BundleMetadata struct { BundleNumber int `json:"bundle_number"` StartTime time.Time `json:"start_time"` EndTime time.Time `json:"end_time"` OperationCount int `json:"operation_count"` DIDCount int `json:"did_count"`
// Primary hash - cumulative chain hash (includes all history) Hash string `json:"hash"`
// Content hash - SHA256 of bundle operations only ContentHash string `json:"content_hash"`
// Parent chain hash - links to previous bundle Parent string `json:"parent,omitempty"`
// File hashes and sizes CompressedHash string `json:"compressed_hash"` CompressedSize int64 `json:"compressed_size"` UncompressedSize int64 `json:"uncompressed_size"` Cursor string `json:"cursor"` CreatedAt time.Time `json:"created_at"`}
func (b *Bundle) ToMetadata() *BundleMetadata { return &BundleMetadata{ BundleNumber: b.BundleNumber, StartTime: b.StartTime, EndTime: b.EndTime, OperationCount: b.OperationCount(), DIDCount: b.DIDCount, Hash: b.Hash, // Chain hash ContentHash: b.ContentHash, // Content hash Parent: b.Parent, CompressedHash: b.CompressedHash, CompressedSize: b.CompressedSize, UncompressedSize: b.UncompressedSize, Cursor: b.Cursor, CreatedAt: b.CreatedAt, }}
// VerificationResult contains the result of bundle verificationtype VerificationResult struct { BundleNumber int Valid bool HashMatch bool FileExists bool Error error LocalHash string ExpectedHash string}
// ChainVerificationResult contains the result of chain verificationtype ChainVerificationResult struct { Valid bool ChainLength int BrokenAt int Error string VerifiedBundles []int}
// DirectoryScanResult contains results from scanning a directorytype DirectoryScanResult struct { BundleDir string BundleCount int FirstBundle int LastBundle int MissingGaps []int TotalSize int64 // Compressed size TotalUncompressed int64 // Uncompressed size (NEW) IndexUpdated bool}
// Logger interface for bundle operationstype Logger interface { Printf(format string, v ...interface{}) Println(v ...interface{})}
// Config holds configuration for bundle operationstype Config struct { BundleDir string VerifyOnLoad bool AutoRebuild bool RebuildWorkers int // Number of workers for parallel rebuild (0 = auto-detect) RebuildProgress func(current, total int) // Progress callback for rebuild Logger Logger}
// DefaultConfig returns default configurationfunc DefaultConfig(bundleDir string) *Config { return &Config{ BundleDir: bundleDir, VerifyOnLoad: true, AutoRebuild: true, RebuildWorkers: 0, // 0 means auto-detect CPU count RebuildProgress: nil, // No progress callback by default Logger: nil, }}
// CloneOptions configures cloning behaviortype CloneOptions struct { RemoteURL string Workers int SkipExisting bool ProgressFunc func(downloaded, total int, bytesDownloaded, bytesTotal int64) SaveInterval time.Duration Verbose bool Logger Logger}
// CloneResult contains cloning resultstype CloneResult struct { RemoteBundles int Downloaded int Failed int Skipped int TotalBytes int64 Duration time.Duration Interrupted bool FailedBundles []int}