// Package shares manages the persistent multi-share configuration stored in shares.json. // Shares are additive to the existing single-dir ShareDir mechanism. package shares import ( "encoding/json" "os" "path/filepath" "sync" ) // Share describes one shared directory entry. type Share struct { Path string `json:"path"` Networks []string `json:"networks"` // ["*"] = global (all networks); otherwise list of network IDs } // Store manages the shares.json file. type Store struct { mu sync.RWMutex path string shares []Share } // Load reads shares.json from dataDir. Returns an empty store if the file doesn't exist. func Load(dataDir string) (*Store, error) { s := &Store{path: filepath.Join(dataDir, "shares.json")} data, err := os.ReadFile(s.path) if os.IsNotExist(err) { return s, nil } if err != nil { return nil, err } if err := json.Unmarshal(data, &s.shares); err != nil { return nil, err } return s, nil } func (s *Store) save() error { data, err := json.MarshalIndent(s.shares, "", " ") if err != nil { return err } return os.WriteFile(s.path, data, 0600) } // All returns a copy of all shares. func (s *Store) All() []Share { s.mu.RLock() defer s.mu.RUnlock() out := make([]Share, len(s.shares)) copy(out, s.shares) return out } // ForNetwork returns all shares visible on networkID (global + network-specific). func (s *Store) ForNetwork(networkID string) []Share { s.mu.RLock() defer s.mu.RUnlock() var out []Share for _, sh := range s.shares { for _, n := range sh.Networks { if n == "*" || n == networkID { out = append(out, sh) break } } } return out } // Add adds a share (no-op if path already present). Persists immediately. func (s *Store) Add(sh Share) error { s.mu.Lock() defer s.mu.Unlock() for i, existing := range s.shares { if existing.Path == sh.Path { s.shares[i].Networks = sh.Networks return s.save() } } s.shares = append(s.shares, sh) return s.save() } // Remove removes the share with the given path. Persists immediately. func (s *Store) Remove(path string) error { s.mu.Lock() defer s.mu.Unlock() for i, sh := range s.shares { if sh.Path == path { s.shares = append(s.shares[:i], s.shares[i+1:]...) return s.save() } } return nil }