GraphQL API and utilities for the rpdata project
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.

96 lines
2.4 KiB

  1. package space
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "git.aiterp.net/rpdata/api/internal/config"
  7. "io"
  8. minio "github.com/minio/minio-go"
  9. )
  10. type Client struct {
  11. bucket string
  12. urlRoot string
  13. spaceRoot string
  14. maxSize int64
  15. s3 *minio.Client
  16. }
  17. func (client *Client) MaxSize() int64 {
  18. return client.maxSize
  19. }
  20. // UploadFile uploads the file to the space. This does not do any checks on it, so the endpoints should
  21. // ensure that's all okay.
  22. func (client *Client) UploadFile(ctx context.Context, name string, mimeType string, reader io.Reader, size int64) error {
  23. if size > client.maxSize {
  24. return errors.New("file is too big")
  25. }
  26. _, err := client.s3.PutObjectWithContext(ctx, client.bucket, client.spaceRoot+"/"+name, reader, size, minio.PutObjectOptions{
  27. ContentType: mimeType,
  28. UserMetadata: map[string]string{
  29. "x-amz-acl": "public-read",
  30. },
  31. })
  32. if err != nil {
  33. return err
  34. }
  35. _, err = client.s3.StatObject(client.bucket, client.spaceRoot+"/"+name, minio.StatObjectOptions{})
  36. if err != nil {
  37. return err
  38. }
  39. return nil
  40. }
  41. // RemoveFile removes a file from the space
  42. func (client *Client) RemoveFile(name string) error {
  43. return client.s3.RemoveObject(client.bucket, client.spaceRoot+"/"+name)
  44. }
  45. // DownloadFile opens a file for download, using the same path format as the UploadFile function. Remember to Close it!
  46. // The returned stream also has `ReaderAt` and `Seeker`, but those are impl. details.
  47. func (client *Client) DownloadFile(ctx context.Context, path string) (io.ReadCloser, error) {
  48. return client.s3.GetObjectWithContext(ctx, client.bucket, client.spaceRoot+"/"+path, minio.GetObjectOptions{})
  49. }
  50. // URLFromPath gets the URL from the path returned by UploadFile
  51. func (client *Client) URLFromPath(path string) string {
  52. return client.urlRoot + path
  53. }
  54. // Connect connects to a S3 space.
  55. func Connect(cfg config.Space) (*Client, error) {
  56. client, err := minio.New(cfg.Host, cfg.AccessKey, cfg.SecretKey, true)
  57. if err != nil {
  58. return nil, err
  59. }
  60. exists, err := client.BucketExists(cfg.Bucket)
  61. if err != nil {
  62. return nil, err
  63. }
  64. if !exists {
  65. return nil, errors.New("bucket not found")
  66. }
  67. urlRoot := cfg.URLRoot
  68. if urlRoot == "" {
  69. urlRoot = fmt.Sprintf("https://%s.%s/%s/", cfg.Bucket, cfg.Host, cfg.Root)
  70. } else {
  71. urlRoot += "/" + cfg.Root + "/"
  72. }
  73. return &Client{
  74. bucket: cfg.Bucket,
  75. urlRoot: urlRoot,
  76. spaceRoot: cfg.Root,
  77. maxSize: cfg.MaxSize,
  78. s3: client,
  79. }, nil
  80. }