s3.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package storage
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "os"
  7. "strings"
  8. "time"
  9. "github.com/langgenius/dify-plugin-daemon/internal/core/aws"
  10. )
  11. type S3 struct{}
  12. func (s *S3) Read(path string) ([]byte, error) {
  13. reader, err := s.ReadStream(path)
  14. if err != nil {
  15. return nil, err
  16. }
  17. defer reader.Close()
  18. return io.ReadAll(reader)
  19. }
  20. func (s *S3) ReadStream(path string) (io.ReadCloser, error) {
  21. return aws.StreamDownloadFromS3(context.Background(), path)
  22. }
  23. func (s *S3) Write(path string, data []byte) error {
  24. return aws.StreamUploadToS3(context.Background(), path, io.NopCloser(bytes.NewReader(data)))
  25. }
  26. func (s *S3) WriteStream(path string, data io.Reader) error {
  27. return aws.StreamUploadToS3(context.Background(), path, data)
  28. }
  29. func (s *S3) List(path string) ([]FileInfo, error) {
  30. keys, err := aws.ListFromS3(context.Background(), path)
  31. if err != nil {
  32. return nil, err
  33. }
  34. file_infos := make([]FileInfo, len(keys))
  35. for i, key := range keys {
  36. head, err := aws.HeadObject(context.Background(), key)
  37. if err != nil {
  38. return nil, err
  39. }
  40. is_dir := strings.HasSuffix(key, "/")
  41. file_infos[i] = &s3FileInfo{
  42. name: strings.TrimSuffix(key, "/"),
  43. size: *head.ContentLength,
  44. modTime: *head.LastModified,
  45. isDir: is_dir,
  46. }
  47. }
  48. return file_infos, nil
  49. }
  50. func (s *S3) Stat(path string) (FileInfo, error) {
  51. head, err := aws.HeadObject(context.Background(), path)
  52. if err != nil {
  53. return nil, err
  54. }
  55. return &s3FileInfo{
  56. name: path,
  57. size: *head.ContentLength,
  58. modTime: *head.LastModified,
  59. }, nil
  60. }
  61. func (s *S3) Delete(path string) error {
  62. return aws.DeleteFromS3(context.Background(), path)
  63. }
  64. func (s *S3) Mkdir(path string, perm os.FileMode) error {
  65. // S3 doesn't have directories, so this is a no-op
  66. return nil
  67. }
  68. func (s *S3) Rename(oldpath, newpath string) error {
  69. // S3 doesn't support rename directly, so we need to copy and delete
  70. reader, err := s.ReadStream(oldpath)
  71. if err != nil {
  72. return err
  73. }
  74. defer reader.Close()
  75. err = aws.StreamUploadToS3(context.Background(), newpath, reader)
  76. if err != nil {
  77. return err
  78. }
  79. return s.Delete(oldpath)
  80. }
  81. func (s *S3) Exists(path string) (bool, error) {
  82. _, err := aws.HeadObject(context.Background(), path)
  83. if err != nil {
  84. // TODO: Check if error is specifically "not found" error
  85. return false, nil
  86. }
  87. return true, nil
  88. }
  89. type s3FileInfo struct {
  90. name string
  91. size int64
  92. modTime time.Time
  93. isDir bool
  94. }
  95. func (fi *s3FileInfo) Name() string { return fi.name }
  96. func (fi *s3FileInfo) Size() int64 { return fi.size }
  97. func (fi *s3FileInfo) Mode() os.FileMode { return 0 }
  98. func (fi *s3FileInfo) ModTime() time.Time { return fi.modTime }
  99. func (fi *s3FileInfo) IsDir() bool { return fi.isDir }
  100. func (fi *s3FileInfo) Sys() interface{} { return nil }