diff --git a/internal/s3/minio.go b/internal/s3/minio.go new file mode 100644 index 0000000..0b6fbba --- /dev/null +++ b/internal/s3/minio.go @@ -0,0 +1,126 @@ +package s3 + +import ( + "context" + "io" + + "git.kapelle.org/niklas/s3browser/internal/types" + "github.com/minio/minio-go/v7" + "github.com/minio/minio-go/v7/pkg/credentials" +) + +type minioS3 struct { + client *minio.Client +} + +func NewMinio(config types.AppConfig) (S3Service, error) { + client, err := minio.New(config.S3Endoint, &minio.Options{ + Creds: credentials.NewStaticV4(config.S3AccessKey, config.S3SecretKey, ""), + Secure: config.S3SSL, + }) + + if err != nil { + return nil, err + } + + return &minioS3{ + client: client, + }, nil +} + +func (m *minioS3) ListBuckets(ctx context.Context) ([]Bucket, error) { + buckets, err := m.client.ListBuckets(ctx) + if err != nil { + return nil, err + } + var rtn []Bucket + + for _, v := range buckets { + rtn = append(rtn, Bucket(v.Name)) + } + + return rtn, nil +} + +func (m *minioS3) ListObjects(ctx context.Context, id types.ID) ([]types.File, []types.Directory, error) { + var files []types.File + var dirs []types.Directory + + for objInfo := range m.client.ListObjects(ctx, id.Bucket, minio.ListObjectsOptions{}) { + objId := types.ID{ + Bucket: id.Bucket, + Key: objInfo.Key, + } + + objId.Normalize() + + if objId.IsDirectory() { + dirs = append(dirs, *obkInfoToDir(objInfo, objId)) + } else { + files = append(files, *objInfoToFile(objInfo, objId)) + } + } + + return files, dirs, nil + +} + +func (m *minioS3) GetObject(ctx context.Context, id types.ID) (Object, error) { + object, err := m.client.GetObject(ctx, id.Bucket, id.Key, minio.GetObjectOptions{}) + + if err != nil { + return nil, err + } + + return object, nil +} + +func (m *minioS3) PutObject(ctx context.Context, id types.ID, reader io.Reader, objectSize int64) error { + _, err := m.client.PutObject(ctx, id.Bucket, id.Key, reader, objectSize, minio.PutObjectOptions{}) + return err +} + +func (m *minioS3) CopyObject(ctx context.Context, src types.ID, dest types.ID) error { + _, err := m.client.CopyObject(ctx, minio.CopyDestOptions{ + Bucket: dest.Bucket, + Object: dest.Key, + }, minio.CopySrcOptions{ + Bucket: src.Bucket, + Object: src.Key, + }) + + return err +} + +func (m *minioS3) StatObject(ctx context.Context, id types.ID) (*types.File, error) { + info, err := m.client.StatObject(ctx, id.Bucket, id.Key, minio.GetObjectOptions{}) + + if err != nil { + return nil, err + } + + return objInfoToFile(info, id), nil + +} + +func (m *minioS3) RemoveObject(ctx context.Context, id types.ID) error { + return m.client.RemoveObject(ctx, id.Bucket, id.Key, minio.RemoveObjectOptions{}) +} + +func objInfoToFile(objInfo minio.ObjectInfo, id types.ID) *types.File { + return &types.File{ + ID: id, + Name: id.Name(), + Size: objInfo.Size, + ContentType: objInfo.ContentType, + ETag: objInfo.ETag, + LastModified: objInfo.LastModified, + } +} + +func obkInfoToDir(objInfo minio.ObjectInfo, id types.ID) *types.Directory { + return &types.Directory{ + ID: id, + Name: id.Name(), + } +} diff --git a/internal/s3/s3.go b/internal/s3/s3.go new file mode 100644 index 0000000..7d60287 --- /dev/null +++ b/internal/s3/s3.go @@ -0,0 +1,29 @@ +package s3 + +import ( + "context" + "io" + + "git.kapelle.org/niklas/s3browser/internal/types" +) + +type Bucket string + +type Object interface { + io.Reader + io.Seeker + io.ReaderAt + io.Closer +} + +type S3Service interface { + ListBuckets(ctx context.Context) ([]Bucket, error) + + GetObject(ctx context.Context, id types.ID) (Object, error) + PutObject(ctx context.Context, id types.ID, reader io.Reader, objectSize int64) error + + ListObjects(ctx context.Context, id types.ID) ([]types.File, []types.Directory, error) + CopyObject(ctx context.Context, src types.ID, dest types.ID) error + StatObject(ctx context.Context, id types.ID) (*types.File, error) + RemoveObject(ctx context.Context, id types.ID) error +}