25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

176 satır
4.1 KiB

  1. package storage
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "log"
  9. "os"
  10. "path/filepath"
  11. "time"
  12. )
  13. type LocalStorage struct {
  14. Storage
  15. basedir string
  16. logger *log.Logger
  17. cleanupJob chan struct{}
  18. }
  19. func NewLocalStorage(basedir string, cleanupInterval int, logger *log.Logger) (*LocalStorage, error) {
  20. storage := &LocalStorage{basedir: basedir, logger: logger}
  21. ticker := time.NewTicker(time.Duration(cleanupInterval) * time.Hour * 24)
  22. storage.cleanupJob = make(chan struct{})
  23. go func() {
  24. for {
  25. select {
  26. case <-ticker.C:
  27. err := storage.deleteExpired()
  28. log.Printf("error cleaning up expired files: %v", err)
  29. case <-storage.cleanupJob:
  30. ticker.Stop()
  31. return
  32. }
  33. }
  34. }()
  35. return storage, nil
  36. }
  37. func (s *LocalStorage) Type() string {
  38. return "local"
  39. }
  40. func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, metadata Metadata, err error) {
  41. path := filepath.Join(s.basedir, token, filename)
  42. // content type , content length
  43. reader, err = os.Open(path)
  44. if err != nil {
  45. return nil, Metadata{}, err
  46. }
  47. metadata, err = s.Head(token, filename)
  48. if err != nil {
  49. return nil, Metadata{}, err
  50. }
  51. return reader, metadata, nil
  52. }
  53. func (s *LocalStorage) Head(token string, filename string) (metadata Metadata, err error) {
  54. path := filepath.Join(s.basedir, token, fmt.Sprintf("%s.metadata", filename))
  55. fi, err := os.Open(path)
  56. if err != nil {
  57. return
  58. }
  59. err = json.NewDecoder(fi).Decode(&metadata)
  60. if err != nil {
  61. return Metadata{}, err
  62. }
  63. return metadata, nil
  64. }
  65. func (s *LocalStorage) Patch(token string, filename string, reader io.Reader, metadata Metadata) error {
  66. if reader == nil {
  67. return s.Put(token, filename, reader, metadata)
  68. }
  69. return s.putMetadata(token, filename, metadata)
  70. }
  71. func (s *LocalStorage) Put(token string, filename string, reader io.Reader, metadata Metadata) error {
  72. err := s.putMetadata(token, filename, metadata)
  73. if err != nil {
  74. return err
  75. }
  76. err = s.put(token, filename, reader)
  77. if err != nil {
  78. //Delete the metadata if the put failed
  79. _ = s.Delete(token, fmt.Sprintf("%s.metadata", filename))
  80. }
  81. return err
  82. }
  83. func (s *LocalStorage) Delete(token string, filename string) (err error) {
  84. dir := filepath.Join(s.basedir, token)
  85. log.Printf("deleting file %s/%s/%s", dir, token, filename)
  86. // ensure we do not accidentally delete more than the specified file in the folder
  87. if files, err := ioutil.ReadDir(dir); len(files) > 2 || err != nil {
  88. // ignore if we cannot delete the metadata file
  89. _ = os.Remove(filepath.Join(dir, fmt.Sprintf("%s.metadata", filename)))
  90. return os.Remove(filepath.Join(dir, filename))
  91. }
  92. return os.RemoveAll(dir)
  93. }
  94. func (s *LocalStorage) IsNotExist(err error) bool {
  95. if err == nil {
  96. return false
  97. }
  98. return os.IsNotExist(err)
  99. }
  100. func (s *LocalStorage) deleteExpired() error {
  101. // search for all metadata files
  102. metaFiles, err := filepath.Glob(fmt.Sprintf("%s/*/*.metadata", s.basedir))
  103. if err != nil {
  104. log.Printf("error searching for expired files %v \n", err)
  105. return err
  106. }
  107. var meta Metadata
  108. for _, file := range metaFiles {
  109. f, err := os.Open(file)
  110. if err != nil {
  111. log.Printf("error opening file: %s \n", file)
  112. return err
  113. }
  114. err = json.NewDecoder(f).Decode(&meta)
  115. if err == nil {
  116. if time.Now().After(meta.MaxDate) {
  117. // remove folder and all files in it
  118. _ = os.RemoveAll(filepath.Dir(file))
  119. }
  120. }
  121. }
  122. return nil
  123. }
  124. func (s *LocalStorage) put(token string, filename string, reader io.Reader) error {
  125. var f io.WriteCloser
  126. var err error
  127. path := filepath.Join(s.basedir, token)
  128. if err = os.MkdirAll(path, 0700); err != nil && !os.IsExist(err) {
  129. return err
  130. }
  131. if f, err = os.OpenFile(filepath.Join(path, filename), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
  132. return err
  133. }
  134. defer f.Close()
  135. _, err = io.Copy(f, reader)
  136. return err
  137. }
  138. func (s *LocalStorage) putMetadata(token string, filename string, metadata Metadata) error {
  139. buffer := &bytes.Buffer{}
  140. if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
  141. log.Printf("%s", err.Error())
  142. return err
  143. } else if err := s.put(token, fmt.Sprintf("%s.metadata", filename), buffer); err != nil {
  144. log.Printf("%s", err.Error())
  145. return nil
  146. }
  147. return nil
  148. }