file.go 3.7 KB

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