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.

183 lines
4.0 KiB

  1. package s3
  2. import (
  3. "io"
  4. "io/ioutil"
  5. "os"
  6. "strconv"
  7. "time"
  8. "github.com/andreimarcu/linx-server/backends"
  9. "github.com/andreimarcu/linx-server/helpers"
  10. "github.com/aws/aws-sdk-go/aws"
  11. "github.com/aws/aws-sdk-go/aws/session"
  12. "github.com/aws/aws-sdk-go/service/s3"
  13. "github.com/aws/aws-sdk-go/service/s3/s3manager"
  14. )
  15. type S3Backend struct {
  16. bucket string
  17. svc *s3.S3
  18. }
  19. func (b S3Backend) Delete(key string) error {
  20. input := &s3.DeleteObjectInput{
  21. Bucket: aws.String(b.bucket),
  22. Key: aws.String(key),
  23. }
  24. _, err := b.svc.DeleteObject(input)
  25. if err != nil {
  26. return err
  27. }
  28. return nil
  29. }
  30. func (b S3Backend) Exists(key string) (bool, error) {
  31. input := &s3.HeadObjectInput{
  32. Bucket: aws.String(b.bucket),
  33. Key: aws.String(key),
  34. }
  35. _, err := b.svc.HeadObject(input)
  36. return err == nil, err
  37. }
  38. func (b S3Backend) Head(key string) (metadata backends.Metadata, err error) {
  39. input := &s3.HeadObjectInput{
  40. Bucket: aws.String(b.bucket),
  41. Key: aws.String(key),
  42. }
  43. result, err := b.svc.HeadObject(input)
  44. if err != nil {
  45. return
  46. }
  47. metadata, err = unmapMetadata(result.Metadata)
  48. return
  49. }
  50. func (b S3Backend) Get(key string) (metadata backends.Metadata, r io.ReadCloser, err error) {
  51. input := &s3.GetObjectInput{
  52. Bucket: aws.String(b.bucket),
  53. Key: aws.String(key),
  54. }
  55. result, err := b.svc.GetObject(input)
  56. if err != nil {
  57. return
  58. }
  59. metadata, err = unmapMetadata(result.Metadata)
  60. r = result.Body
  61. return
  62. }
  63. func mapMetadata(m backends.Metadata) map[string]*string {
  64. return map[string]*string{
  65. "Expiry": aws.String(strconv.FormatInt(m.Expiry.Unix(), 10)),
  66. "Delete_key": aws.String(m.DeleteKey),
  67. "Size": aws.String(strconv.FormatInt(m.Size, 10)),
  68. "Mimetype": aws.String(m.Mimetype),
  69. "Sha256sum": aws.String(m.Sha256sum),
  70. }
  71. }
  72. func unmapMetadata(input map[string]*string) (m backends.Metadata, err error) {
  73. expiry, err := strconv.ParseInt(aws.StringValue(input["Expiry"]), 10, 64)
  74. if err != nil {
  75. return
  76. }
  77. m.Expiry = time.Unix(expiry, 0)
  78. m.Size, err = strconv.ParseInt(aws.StringValue(input["Size"]), 10, 64)
  79. if err != nil {
  80. return
  81. }
  82. m.DeleteKey = aws.StringValue(input["Delete_key"])
  83. m.Mimetype = aws.StringValue(input["Mimetype"])
  84. m.Sha256sum = aws.StringValue(input["Sha256sum"])
  85. return
  86. }
  87. func (b S3Backend) Put(key string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
  88. tmpDst, err := ioutil.TempFile("", "linx-server-upload")
  89. if err != nil {
  90. return
  91. }
  92. defer tmpDst.Close()
  93. defer os.Remove(tmpDst.Name())
  94. bytes, err := io.Copy(tmpDst, r)
  95. if bytes == 0 {
  96. return m, backends.FileEmptyError
  97. } else if err != nil {
  98. return m, err
  99. }
  100. m.Expiry = expiry
  101. m.DeleteKey = deleteKey
  102. m.Size = bytes
  103. m.Mimetype, _ = helpers.DetectMime(tmpDst)
  104. m.Sha256sum, _ = helpers.Sha256sum(tmpDst)
  105. // XXX: we may not be able to write this to AWS easily
  106. //m.ArchiveFiles, _ = helpers.ListArchiveFiles(m.Mimetype, m.Size, tmpDst)
  107. uploader := s3manager.NewUploaderWithClient(b.svc)
  108. input := &s3manager.UploadInput{
  109. Bucket: aws.String(b.bucket),
  110. Key: aws.String(key),
  111. Body: tmpDst,
  112. Metadata: mapMetadata(m),
  113. }
  114. _, err = uploader.Upload(input)
  115. if err != nil {
  116. return
  117. }
  118. return
  119. }
  120. func (b S3Backend) Size(key string) (int64, error) {
  121. input := &s3.HeadObjectInput{
  122. Bucket: aws.String(b.bucket),
  123. Key: aws.String(key),
  124. }
  125. result, err := b.svc.HeadObject(input)
  126. if err != nil {
  127. return 0, err
  128. }
  129. return *result.ContentLength, nil
  130. }
  131. func (b S3Backend) List() ([]string, error) {
  132. var output []string
  133. input := &s3.ListObjectsInput{
  134. Bucket: aws.String(b.bucket),
  135. }
  136. results, err := b.svc.ListObjects(input)
  137. if err != nil {
  138. return nil, err
  139. }
  140. for _, object := range results.Contents {
  141. output = append(output, *object.Key)
  142. }
  143. return output, nil
  144. }
  145. func NewS3Backend(bucket string, region string, endpoint string) S3Backend {
  146. awsConfig := &aws.Config{}
  147. if region != "" {
  148. awsConfig.Region = aws.String(region)
  149. }
  150. if endpoint != "" {
  151. awsConfig.Endpoint = aws.String(endpoint)
  152. }
  153. sess := session.Must(session.NewSession(awsConfig))
  154. svc := s3.New(sess)
  155. return S3Backend{bucket: bucket, svc: svc}
  156. }