Contains the Concourse pipeline definition for building a line-server container
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
4.2 KiB

  1. package localfs
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "time"
  10. "github.com/andreimarcu/linx-server/backends"
  11. "github.com/andreimarcu/linx-server/helpers"
  12. "github.com/andreimarcu/linx-server/torrent"
  13. )
  14. type LocalfsBackend struct {
  15. metaPath string
  16. filesPath string
  17. }
  18. type MetadataJSON struct {
  19. DeleteKey string `json:"delete_key"`
  20. Sha256sum string `json:"sha256sum"`
  21. Mimetype string `json:"mimetype"`
  22. Size int64 `json:"size"`
  23. Expiry int64 `json:"expiry"`
  24. ArchiveFiles []string `json:"archive_files,omitempty"`
  25. }
  26. func (b LocalfsBackend) Delete(key string) (err error) {
  27. err = os.Remove(path.Join(b.filesPath, key))
  28. if err != nil {
  29. return
  30. }
  31. err = os.Remove(path.Join(b.metaPath, key))
  32. return
  33. }
  34. func (b LocalfsBackend) Exists(key string) (bool, error) {
  35. _, err := os.Stat(path.Join(b.filesPath, key))
  36. return err == nil, err
  37. }
  38. func (b LocalfsBackend) Head(key string) (metadata backends.Metadata, err error) {
  39. f, err := os.Open(path.Join(b.metaPath, key))
  40. if os.IsNotExist(err) {
  41. return metadata, backends.NotFoundErr
  42. } else if err != nil {
  43. return metadata, backends.BadMetadata
  44. }
  45. defer f.Close()
  46. decoder := json.NewDecoder(f)
  47. mjson := MetadataJSON{}
  48. if err := decoder.Decode(&mjson); err != nil {
  49. return metadata, backends.BadMetadata
  50. }
  51. metadata.DeleteKey = mjson.DeleteKey
  52. metadata.Mimetype = mjson.Mimetype
  53. metadata.ArchiveFiles = mjson.ArchiveFiles
  54. metadata.Sha256sum = mjson.Sha256sum
  55. metadata.Expiry = time.Unix(mjson.Expiry, 0)
  56. metadata.Size = mjson.Size
  57. return
  58. }
  59. func (b LocalfsBackend) Get(key string) (metadata backends.Metadata, f io.ReadCloser, err error) {
  60. metadata, err = b.Head(key)
  61. if err != nil {
  62. return
  63. }
  64. f, err = os.Open(path.Join(b.filesPath, key))
  65. if err != nil {
  66. return
  67. }
  68. return
  69. }
  70. func (b LocalfsBackend) writeMetadata(key string, metadata backends.Metadata) error {
  71. metaPath := path.Join(b.metaPath, key)
  72. mjson := MetadataJSON{
  73. DeleteKey: metadata.DeleteKey,
  74. Mimetype: metadata.Mimetype,
  75. ArchiveFiles: metadata.ArchiveFiles,
  76. Sha256sum: metadata.Sha256sum,
  77. Expiry: metadata.Expiry.Unix(),
  78. Size: metadata.Size,
  79. }
  80. dst, err := os.Create(metaPath)
  81. if err != nil {
  82. return err
  83. }
  84. defer dst.Close()
  85. encoder := json.NewEncoder(dst)
  86. err = encoder.Encode(mjson)
  87. if err != nil {
  88. os.Remove(metaPath)
  89. return err
  90. }
  91. return nil
  92. }
  93. func (b LocalfsBackend) Put(key string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
  94. filePath := path.Join(b.filesPath, key)
  95. dst, err := os.Create(filePath)
  96. if err != nil {
  97. return
  98. }
  99. defer dst.Close()
  100. bytes, err := io.Copy(dst, r)
  101. if bytes == 0 {
  102. os.Remove(filePath)
  103. return m, errors.New("Empty file")
  104. } else if err != nil {
  105. os.Remove(filePath)
  106. return m, err
  107. }
  108. m.Expiry = expiry
  109. m.DeleteKey = deleteKey
  110. m.Size = bytes
  111. m.Mimetype, _ = helpers.DetectMime(dst)
  112. m.Sha256sum, _ = helpers.Sha256sum(dst)
  113. m.ArchiveFiles, _ = helpers.ListArchiveFiles(m.Mimetype, m.Size, dst)
  114. err = b.writeMetadata(key, m)
  115. if err != nil {
  116. os.Remove(filePath)
  117. return
  118. }
  119. return
  120. }
  121. func (b LocalfsBackend) Size(key string) (int64, error) {
  122. fileInfo, err := os.Stat(path.Join(b.filesPath, key))
  123. if err != nil {
  124. return 0, err
  125. }
  126. return fileInfo.Size(), nil
  127. }
  128. func (b LocalfsBackend) GetTorrent(fileName string, url string) (t torrent.Torrent, err error) {
  129. chunk := make([]byte, torrent.TORRENT_PIECE_LENGTH)
  130. t = torrent.Torrent{
  131. Encoding: "UTF-8",
  132. Info: torrent.TorrentInfo{
  133. PieceLength: torrent.TORRENT_PIECE_LENGTH,
  134. Name: fileName,
  135. },
  136. UrlList: []string{url},
  137. }
  138. _, f, err := b.Get(fileName)
  139. if err != nil {
  140. return
  141. }
  142. defer f.Close()
  143. for {
  144. n, err := f.Read(chunk)
  145. if err == io.EOF {
  146. break
  147. } else if err != nil {
  148. return t, err
  149. }
  150. t.Info.Length += n
  151. t.Info.Pieces += string(torrent.HashPiece(chunk[:n]))
  152. }
  153. return
  154. }
  155. func (b LocalfsBackend) List() ([]string, error) {
  156. var output []string
  157. files, err := ioutil.ReadDir(b.filesPath)
  158. if err != nil {
  159. return nil, err
  160. }
  161. for _, file := range files {
  162. output = append(output, file.Name())
  163. }
  164. return output, nil
  165. }
  166. func NewLocalfsBackend(metaPath string, filesPath string) LocalfsBackend {
  167. return LocalfsBackend{
  168. metaPath: metaPath,
  169. filesPath: filesPath,
  170. }
  171. }