file.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package file
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/fs"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "sync"
  10. "git.andreafazzi.eu/andrea/probo/pkg/store"
  11. )
  12. type IndexDirFunc[T FileStorable, K store.Storer[T]] func(s *FileStore[T, K]) error
  13. var (
  14. ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.")
  15. )
  16. type FileStorable interface {
  17. store.Storable
  18. Marshal() ([]byte, error)
  19. Unmarshal([]byte) error
  20. }
  21. type FileStorer[T store.Storable] interface {
  22. // store.Storer[T]
  23. Create(T, ...string) (T, error)
  24. ReadAll() []T
  25. Read(string) (T, error)
  26. Update(T, string) (T, error)
  27. Delete(string) (T, error)
  28. }
  29. type FilePathConfig struct {
  30. Dir string
  31. FilePrefix string
  32. FileSuffix string
  33. }
  34. type FileStoreConfig[T FileStorable, K store.Storer[T]] struct {
  35. FilePathConfig
  36. IndexDirFunc func(*FileStore[T, K]) error
  37. CreateEntityFunc func() T
  38. NoIndexOnCreate bool
  39. }
  40. type FileStore[T FileStorable, K store.Storer[T]] struct {
  41. *FileStoreConfig[T, K]
  42. Storer K
  43. lock sync.RWMutex
  44. paths map[string]string
  45. }
  46. func DefaultIndexDirFunc[T FileStorable, K store.Storer[T]](s *FileStore[T, K]) error {
  47. if s.CreateEntityFunc == nil {
  48. return errors.New("CreateEntityFunc cannot be nil!")
  49. }
  50. files, err := os.ReadDir(s.Dir)
  51. if err != nil {
  52. return err
  53. }
  54. entityFiles := make([]fs.DirEntry, 0)
  55. for _, file := range files {
  56. filename := file.Name()
  57. if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) {
  58. entityFiles = append(entityFiles, file)
  59. }
  60. }
  61. for _, file := range entityFiles {
  62. filename := file.Name()
  63. fullPath := filepath.Join(s.Dir, filename)
  64. content, err := os.ReadFile(fullPath)
  65. if err != nil {
  66. return err
  67. }
  68. entity := s.CreateEntityFunc()
  69. err = entity.Unmarshal(content)
  70. if err != nil {
  71. return err
  72. }
  73. mEntity, err := s.Create(entity, fullPath)
  74. if err != nil {
  75. return err
  76. }
  77. s.SetPath(mEntity, fullPath)
  78. }
  79. return nil
  80. }
  81. func NewFileStore[T FileStorable, K store.Storer[T]](config *FileStoreConfig[T, K], storer K) (*FileStore[T, K], error) {
  82. store := &FileStore[T, K]{
  83. FileStoreConfig: config,
  84. Storer: storer,
  85. paths: make(map[string]string, 0),
  86. }
  87. if !config.NoIndexOnCreate {
  88. err := store.IndexDir()
  89. if err != nil {
  90. return nil, err
  91. }
  92. }
  93. return store, nil
  94. }
  95. func (s *FileStore[T, K]) Create(entity T, path ...string) (T, error) {
  96. e, err := s.Storer.Create(entity)
  97. if err != nil {
  98. return e, err
  99. }
  100. data, err := e.Marshal()
  101. if err != nil {
  102. return e, err
  103. }
  104. if len(path) == 0 {
  105. path = append(path, filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)))
  106. }
  107. file, err := os.Create(path[0])
  108. if err != nil {
  109. return e, err
  110. }
  111. defer file.Close()
  112. _, err = file.Write(data)
  113. if err != nil {
  114. return e, err
  115. }
  116. s.SetPath(e, path[0])
  117. return e, nil
  118. }
  119. func (s *FileStore[T, K]) Update(entity T, id string) (T, error) {
  120. e, err := s.Storer.Update(entity, id)
  121. if err != nil {
  122. return e, err
  123. }
  124. filePath := s.GetPath(e)
  125. data, err := e.Marshal()
  126. if err != nil {
  127. return e, err
  128. }
  129. file, err := os.Create(filePath)
  130. if err != nil {
  131. return e, err
  132. }
  133. defer file.Close()
  134. _, err = file.Write(data)
  135. if err != nil {
  136. return e, err
  137. }
  138. return e, nil
  139. }
  140. func (s *FileStore[T, K]) Read(id string) (T, error) {
  141. return s.Storer.Read(id)
  142. }
  143. func (s *FileStore[T, K]) ReadAll() []T {
  144. return s.Storer.ReadAll()
  145. }
  146. func (s *FileStore[T, K]) Delete(id string) (T, error) {
  147. e, err := s.Storer.Delete(id)
  148. if err != nil {
  149. return e, err
  150. }
  151. err = os.Remove(s.GetPath(e))
  152. if err != nil {
  153. return e, err
  154. }
  155. return e, nil
  156. }
  157. func (s *FileStore[T, K]) IndexDir() error {
  158. return s.IndexDirFunc(s)
  159. }
  160. func (s *FileStore[T, K]) GetPath(entity T) string {
  161. s.lock.RLock()
  162. defer s.lock.RUnlock()
  163. return s.paths[entity.GetID()]
  164. }
  165. func (s *FileStore[T, K]) SetPath(entity T, path string) string {
  166. s.lock.Lock()
  167. defer s.lock.Unlock()
  168. s.paths[entity.GetID()] = path
  169. return path
  170. }