jinshan/pkg/oss/s3.go
2025-06-19 10:35:26 +08:00

180 lines
4.2 KiB
Go

package oss
import (
"context"
"io"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
type S3ClientConfig struct {
Domain string
Region string
AccessKeyID string
SecretAccessKey string
BucketName string
Prefix string
}
var _ IClient = (*S3Client)(nil)
type S3Client struct {
config S3ClientConfig
session *session.Session
client *s3.S3
}
func NewS3Client(config S3ClientConfig) (*S3Client, error) {
awsConfig := aws.NewConfig()
awsConfig.WithRegion(config.Region)
awsConfig.WithCredentials(credentials.NewStaticCredentials(config.AccessKeyID, config.SecretAccessKey, ""))
session, err := session.NewSession(awsConfig)
if err != nil {
return nil, err
}
return &S3Client{
config: config,
session: session,
client: s3.New(session),
}, nil
}
func (c *S3Client) PutObject(ctx context.Context, bucketName, objectName string, reader io.ReadSeeker, objectSize int64, options ...PutObjectOptions) (*PutObjectResult, error) {
if bucketName == "" {
bucketName = c.config.BucketName
}
var opt PutObjectOptions
if len(options) > 0 {
opt = options[0]
}
objectName = formatObjectName(c.config.Prefix, objectName)
input := &s3.PutObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectName),
Body: reader,
ContentType: aws.String(opt.ContentType),
ContentDisposition: aws.String("inline"),
ACL: aws.String("public-read"),
}
if len(opt.UserMetadata) > 0 {
input.Metadata = make(map[string]*string)
for k, v := range opt.UserMetadata {
input.Metadata[k] = aws.String(v)
}
}
output, err := c.client.PutObject(input)
if err != nil {
return nil, err
}
return &PutObjectResult{
URL: c.config.Domain + "/" + objectName,
Key: *input.Key,
ETag: *output.ETag,
Size: objectSize,
}, nil
}
func (c *S3Client) GetObject(ctx context.Context, bucketName, objectName string) (io.ReadCloser, error) {
if bucketName == "" {
bucketName = c.config.BucketName
}
objectName = formatObjectName(c.config.Prefix, objectName)
input := &s3.GetObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectName),
}
output, err := c.client.GetObject(input)
if err != nil {
return nil, err
}
return output.Body, nil
}
func (c *S3Client) RemoveObject(ctx context.Context, bucketName, objectName string) error {
if bucketName == "" {
bucketName = c.config.BucketName
}
objectName = formatObjectName(c.config.Prefix, objectName)
input := &s3.DeleteObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectName),
}
_, err := c.client.DeleteObject(input)
return err
}
func (c *S3Client) RemoveObjectByURL(ctx context.Context, urlStr string) error {
prefix := c.config.Domain + "/"
if !strings.HasPrefix(urlStr, prefix) {
return nil
}
objectName := strings.TrimPrefix(urlStr, prefix)
input := &s3.DeleteObjectInput{
Bucket: aws.String(c.config.BucketName),
Key: aws.String(objectName),
}
_, err := c.client.DeleteObject(input)
return err
}
func (c *S3Client) StatObjectByURL(ctx context.Context, urlStr string) (*ObjectStat, error) {
prefix := c.config.Domain + "/"
if !strings.HasPrefix(urlStr, prefix) {
return nil, nil
}
objectName := strings.TrimPrefix(urlStr, prefix)
return c.StatObject(ctx, c.config.BucketName, objectName)
}
func (c *S3Client) StatObject(ctx context.Context, bucketName, objectName string) (*ObjectStat, error) {
if bucketName == "" {
bucketName = c.config.BucketName
}
objectName = formatObjectName(c.config.Prefix, objectName)
input := &s3.HeadObjectInput{
Bucket: aws.String(bucketName),
Key: aws.String(objectName),
}
output, err := c.client.HeadObject(input)
if err != nil {
return nil, err
}
var metadata map[string]string
if output.Metadata != nil {
metadata = make(map[string]string)
for k, v := range output.Metadata {
metadata[k] = *v
}
}
return &ObjectStat{
Key: objectName,
ETag: *output.ETag,
LastModified: *output.LastModified,
Size: *output.ContentLength,
ContentType: *output.ContentType,
UserMetadata: metadata,
}, nil
}