larc r11

85 lines ยท 1.7 KB Raw
1 package mount
2
3 import (
4 "os"
5 "path/filepath"
6 "sync"
7 )
8
9 /* BlobCache provides persistent storage for downloaded blobs.
10 * Uses ~/.cache/larc/blobs/{prefix}/{hash} structure.
11 * Thread-safe for concurrent access. */
12
13 type BlobCache struct {
14 dir string
15 mu sync.RWMutex
16 }
17
18 // NewBlobCache creates a cache in ~/.cache/larc/blobs
19 func NewBlobCache() (*BlobCache, error) {
20 home, err := os.UserHomeDir()
21 if err != nil {
22 return nil, err
23 }
24
25 dir := filepath.Join(home, ".cache", "larc", "blobs")
26 if err := os.MkdirAll(dir, 0755); err != nil {
27 return nil, err
28 }
29
30 return &BlobCache{dir: dir}, nil
31 }
32
33 // NewBlobCacheAt creates a cache at a specific path
34 func NewBlobCacheAt(dir string) (*BlobCache, error) {
35 if err := os.MkdirAll(dir, 0755); err != nil {
36 return nil, err
37 }
38 return &BlobCache{dir: dir}, nil
39 }
40
41 func (c *BlobCache) path(hash string) string {
42 if len(hash) < 2 {
43 return filepath.Join(c.dir, hash)
44 }
45 return filepath.Join(c.dir, hash[:2], hash)
46 }
47
48 // Get retrieves blob from cache, returns nil if not found
49 func (c *BlobCache) Get(hash string) ([]byte, bool) {
50 c.mu.RLock()
51 defer c.mu.RUnlock()
52
53 data, err := os.ReadFile(c.path(hash))
54 if err != nil {
55 return nil, false
56 }
57 return data, true
58 }
59
60 // Put stores blob in cache
61 func (c *BlobCache) Put(hash string, data []byte) error {
62 c.mu.Lock()
63 defer c.mu.Unlock()
64
65 p := c.path(hash)
66 if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
67 return err
68 }
69 return os.WriteFile(p, data, 0644)
70 }
71
72 // Exists checks if blob is cached
73 func (c *BlobCache) Exists(hash string) bool {
74 c.mu.RLock()
75 defer c.mu.RUnlock()
76
77 _, err := os.Stat(c.path(hash))
78 return err == nil
79 }
80
81 // Dir returns cache directory path
82 func (c *BlobCache) Dir() string {
83 return c.dir
84 }
85