package storage import ( "encoding/json" "fmt" "os" "path/filepath" ) var _ Storage = (*OSStorage)(nil) type OSStorage struct { root string } func NewOSStorage() (Storage, error) { urd, err := os.UserHomeDir() if err != nil { return nil, fmt.Errorf("不能获取默认的根目录 : %w", err) } return NewOSStorageRooted(urd) } func NewOSStorageRooted(root string) (Storage, error) { if !filepath.IsAbs(root) { return nil, fmt.Errorf("root必须是绝对路径:%s", root) } storageRoot := filepath.Join(root, ".df") s := &OSStorage{root: storageRoot} mighted, err := s.migrateDeprecatedRootStorage() if mighted { if err != nil { return nil, fmt.Errorf("找到不推荐使用的存储,但无法移动到新位置:%w", err) } return s, nil } err = s.mkdirIfNotExists(storageRootPath(s)) return s, err } func (s *OSStorage) Root() string { return s.root } func (s *OSStorage) LoadConfig() (*Config, error) { configFile := configPath(s) f, err := os.Open(configFile) if os.IsNotExist(err) { return newDefaultConfig(), nil } if err != nil { return newDefaultConfig(), fmt.Errorf("没有读到 URI:%w", err) } defer f.Close() config := &Config{} err = json.NewDecoder(f).Decode(config) if err != nil { return newDefaultConfig(), err } return config, nil } func (s *OSStorage) StoreConfig(config *Config) error { configFile := configPath(s) w, err := s.createFile(configFile) if err != nil { return err } defer w.Close() return json.NewEncoder(w).Encode(config) } func (s *OSStorage) createFile(name string) (*os.File, error) { return os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) } func (s *OSStorage) isExist(path string) bool { _, err := os.Stat(path) return !os.IsNotExist(err) } func (s *OSStorage) mkdirIfNotExists(dir string) error { if s.isExist(dir) { return nil } return os.MkdirAll(dir, 0700) } // 合并弃用的根目录 func (s *OSStorage) migrateDeprecatedRootStorage() (bool, error) { oldRoot, err := os.UserConfigDir() if err != nil { return false, err } src := filepath.Join(oldRoot, "fyne", ID, "vvv") _, err = os.Stat(src) if os.IsNotExist(err) { return false, err } dest := storageRootPath(s) err = os.Rename(src, dest) if err != nil { return false, err } return true, nil }