Skip to content

Commit 63f42db

Browse files
committed
Add swift protocol
1 parent 97a16e7 commit 63f42db

File tree

7 files changed

+258
-15
lines changed

7 files changed

+258
-15
lines changed

cli/cli.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import (
1010
"unicode"
1111

1212
"github.com/alexflint/go-arg"
13-
"github.com/larrabee/s3sync/storage"
1413
"github.com/mattn/go-isatty"
14+
15+
"github.com/larrabee/s3sync/storage"
1516
)
1617

1718
var (
@@ -43,11 +44,11 @@ type args struct {
4344
// Source config
4445
Source string `arg:"positional"`
4546
SourceNoSign bool `arg:"--sn" help:"Don't sign request to source AWS for anonymous access"`
46-
SourceKey string `arg:"--sk" help:"Source AWS key"`
47-
SourceSecret string `arg:"--ss" help:"Source AWS session secret"`
48-
SourceToken string `arg:"--st" help:"Source AWS token"`
49-
SourceRegion string `arg:"--sr" help:"Source AWS Region"`
50-
SourceEndpoint string `arg:"--se" help:"Source AWS Endpoint"`
47+
SourceKey string `arg:"--sk" help:"Source AWS key / Swift User"`
48+
SourceSecret string `arg:"--ss" help:"Source AWS secret / Swift Key"`
49+
SourceToken string `arg:"--st" help:"Source AWS token / Swift Tenant"`
50+
SourceRegion string `arg:"--sr" help:"Source AWS Region / Swift Domain"`
51+
SourceEndpoint string `arg:"--se" help:"Source AWS Endpoint / Swift Auth URL"`
5152
// Target config
5253
Target string `arg:"positional"`
5354
TargetNoSign bool `arg:"--tn" help:"Don't sign request to target AWS for anonymous access"`
@@ -225,6 +226,10 @@ func parseConn(cStr string) (conn connect, err error) {
225226
conn.Type = storage.TypeS3Stream
226227
conn.Bucket = u.Host
227228
conn.Path = strings.TrimPrefix(u.Path, "/")
229+
case "swift":
230+
conn.Type = storage.TypeSwift
231+
conn.Bucket = u.Host
232+
conn.Path = strings.TrimPrefix(u.Path, "/")
228233
case "fs":
229234
conn.Type = storage.TypeFS
230235
conn.Path = strings.TrimPrefix(cStr, "fs://")

cli/setup.go

+15
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import (
1111
"github.com/larrabee/s3sync/storage/fs"
1212
"github.com/larrabee/s3sync/storage/s3"
1313
"github.com/larrabee/s3sync/storage/s3stream"
14+
"github.com/larrabee/s3sync/storage/swift"
1415
)
1516

1617
func setupStorages(ctx context.Context, syncGroup *pipeline.Group, cli *argsParsed) error {
1718
var sourceStorage, targetStorage storage.Storage
19+
var err error
20+
1821
switch cli.Source.Type {
1922
case storage.TypeS3:
2023
sourceStorage = s3.NewS3Storage(cli.SourceNoSign, cli.SourceKey, cli.SourceSecret, cli.SourceToken, cli.SourceRegion, cli.SourceEndpoint,
@@ -26,6 +29,11 @@ func setupStorages(ctx context.Context, syncGroup *pipeline.Group, cli *argsPars
2629
)
2730
case storage.TypeFS:
2831
sourceStorage = fs.NewFSStorage(cli.Source.Path, cli.FSFilePerm, cli.FSDirPerm, os.Getpagesize()*256*32, !cli.FSDisableXattr, cli.ErrorHandlingMask, cli.FSAtomicWrite)
32+
case storage.TypeSwift:
33+
sourceStorage, err = swift.NewStorage(cli.SourceKey, cli.SourceSecret, cli.SourceToken, cli.SourceRegion, cli.SourceEndpoint, cli.Source.Bucket, cli.Source.Path, cli.SkipSSLVerify)
34+
if err != nil {
35+
return err
36+
}
2937
}
3038

3139
switch cli.Target.Type {
@@ -39,6 +47,13 @@ func setupStorages(ctx context.Context, syncGroup *pipeline.Group, cli *argsPars
3947
)
4048
case storage.TypeFS:
4149
targetStorage = fs.NewFSStorage(cli.Target.Path, cli.FSFilePerm, cli.FSDirPerm, 0, !cli.FSDisableXattr, cli.ErrorHandlingMask, cli.FSAtomicWrite)
50+
case storage.TypeSwift:
51+
targetStorage, err = swift.NewStorage(cli.TargetKey, cli.TargetSecret, cli.TargetToken, cli.TargetRegion, cli.TargetEndpoint, cli.Target.Bucket, cli.Target.Path, cli.SkipSSLVerify)
52+
if err != nil {
53+
return err
54+
}
55+
56+
// func NewStorage(user, key, tenant, domain, authUrl string, bucketName, prefix string, skipSSLVerify bool) (*Storage, error) {
4257
}
4358

4459
if sourceStorage == nil {

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ go 1.18
55
require (
66
github.com/alexflint/go-arg v1.4.2
77
github.com/aws/aws-sdk-go v1.44.166
8+
github.com/gophercloud/gophercloud v1.1.1
89
github.com/gosuri/uilive v0.0.3
910
github.com/karrick/godirwalk v1.16.1
1011
github.com/larrabee/ratelimit v1.0.4
1112
github.com/mattn/go-isatty v0.0.12
13+
github.com/ncw/swift/v2 v2.0.1
1214
github.com/pkg/xattr v0.4.2
1315
github.com/sirupsen/logrus v1.8.1
1416
)

go.sum

+9-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ github.com/alexflint/go-arg v1.4.2/go.mod h1:9iRbDxne7LcR/GSvEr7ma++GLpdIU1zrghf
33
github.com/alexflint/go-scalar v1.0.0/go.mod h1:GpHzbCOZXEKMEcygYQ5n/aa4Aq84zbxjy3MxYW0gjYw=
44
github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM=
55
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
6-
github.com/aws/aws-sdk-go v1.42.13 h1:+Nx87T+Bjiq2XybxK6vI98cTEBPLE/hILuZyEenlyEg=
7-
github.com/aws/aws-sdk-go v1.42.13/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
86
github.com/aws/aws-sdk-go v1.44.166 h1:oAn/wJYFoSF2e9iJYkqTlC9IY15ufPnKR1Zt8oZblhg=
97
github.com/aws/aws-sdk-go v1.44.166/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
108
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
119
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1210
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1311
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12+
github.com/gophercloud/gophercloud v1.1.1 h1:MuGyqbSxiuVBqkPZ3+Nhbytk1xZxhmfCB2Rg1cJWFWM=
13+
github.com/gophercloud/gophercloud v1.1.1/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
1414
github.com/gosuri/uilive v0.0.3 h1:kvo6aB3pez9Wbudij8srWo4iY6SFTTxTKOkb+uRCE8I=
1515
github.com/gosuri/uilive v0.0.3/go.mod h1:qkLSc0A5EXSP6B04TrN4oQoxqFI7A8XvoXSlJi8cwk8=
1616
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -29,6 +29,8 @@ github.com/larrabee/ratelimit v1.0.4 h1:cVhspgo8QSRMb76pIWwqSE19ABxRhH4j8kbe35Cs
2929
github.com/larrabee/ratelimit v1.0.4/go.mod h1:jlhboGLs+oa8LIfN4shmd1ONRSkGcwcGqYndDwdpSsc=
3030
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
3131
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
32+
github.com/ncw/swift/v2 v2.0.1 h1:q1IN8hNViXEv8Zvg3Xdis4a3c4IlIGezkYz09zQL5J0=
33+
github.com/ncw/swift/v2 v2.0.1/go.mod h1:z0A9RVdYPjNjXVo2pDOPxZ4eu3oarO1P91fTItcb+Kg=
3234
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3335
github.com/pkg/xattr v0.4.2 h1:fbVxr9lvkToTGgPljVszvFsOdcbSv5BmGABneyxRgZM=
3436
github.com/pkg/xattr v0.4.2/go.mod h1:sBD3RAqlr8Q+RC3FutZcikpT8nyDrIEEBw2J744gVWs=
@@ -42,11 +44,11 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
4244
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
4345
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
4446
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
47+
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
4548
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
4649
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
4750
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
48-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
49-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
51+
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
5052
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
5153
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
5254
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
@@ -59,8 +61,6 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7w
5961
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6062
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
6163
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
62-
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
63-
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6464
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6565
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6666
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
@@ -70,9 +70,9 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
7070
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
7171
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
7272
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
73-
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
7473
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
7574
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
75+
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
7676
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
7777
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
7878
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -81,5 +81,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
8181
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8282
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
8383
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
84-
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
8584
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
85+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
86+
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

storage/s3/retryer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
// Retryer implements basic retry logic
9-
//You can implement the request.Retryer interface.
9+
// You can implement the request.Retryer interface.
1010
type Retryer struct {
1111
// RetryCnt is the number of max retries that will be performed.
1212
// By default, this is zero.

storage/storage.go

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
TypeS3Versioned
2323
TypeFS
2424
TypeS3Stream
25+
TypeSwift
2526
)
2627

2728
// Object contain content and metadata of S3 object.

storage/swift/swift.go

+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package swift
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"crypto/tls"
7+
"io"
8+
"net/http"
9+
"path"
10+
"strings"
11+
12+
"github.com/aws/aws-sdk-go/aws"
13+
"github.com/gophercloud/gophercloud"
14+
"github.com/gophercloud/gophercloud/openstack"
15+
"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
16+
"github.com/gophercloud/gophercloud/pagination"
17+
"github.com/larrabee/ratelimit"
18+
19+
"github.com/larrabee/s3sync/storage"
20+
)
21+
22+
// Storage configuration.
23+
type Storage struct {
24+
conn *gophercloud.ServiceClient
25+
bucket string
26+
prefix string
27+
ctx context.Context
28+
rlBucket ratelimit.Bucket
29+
}
30+
31+
// NewStorage return new configured S3 storage.
32+
//
33+
// You should always create new storage with this constructor.
34+
func NewStorage(user, key, tenant, domain, authUrl string, bucketName, prefix string, skipSSLVerify bool) (*Storage, error) {
35+
st := &Storage{
36+
ctx: context.TODO(),
37+
rlBucket: ratelimit.NewFakeBucket(),
38+
bucket: bucketName,
39+
prefix: prefix,
40+
}
41+
42+
auth := gophercloud.AuthOptions{
43+
IdentityEndpoint: authUrl,
44+
Username: user,
45+
Password: key,
46+
TenantName: tenant,
47+
DomainName: domain,
48+
}
49+
50+
provider, err := openstack.AuthenticatedClient(auth)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
if skipSSLVerify {
56+
tr := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
57+
provider.HTTPClient = http.Client{Transport: tr}
58+
}
59+
60+
client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{})
61+
if err != nil {
62+
return nil, err
63+
}
64+
65+
st.conn = client
66+
67+
return st, nil
68+
}
69+
70+
// WithContext add's context to storage.
71+
func (st *Storage) WithContext(ctx context.Context) {
72+
st.ctx = ctx
73+
st.conn.Context = ctx
74+
}
75+
76+
// WithRateLimit set rate limit (bytes/sec) for storage.
77+
func (st *Storage) WithRateLimit(limit int) error {
78+
bucket, err := ratelimit.NewBucketWithRate(float64(limit), int64(limit))
79+
if err != nil {
80+
return err
81+
}
82+
st.rlBucket = bucket
83+
return nil
84+
}
85+
86+
// List S3 bucket and send founded objects to chan.
87+
func (st *Storage) List(output chan<- *storage.Object) error {
88+
opts := &objects.ListOpts{Full: true, Prefix: st.prefix}
89+
pager := objects.List(st.conn, st.bucket, opts)
90+
91+
err := pager.EachPage(func(page pagination.Page) (bool, error) {
92+
objectList, err := objects.ExtractInfo(page)
93+
if err != nil {
94+
return false, err
95+
}
96+
for _, n := range objectList {
97+
key := strings.Replace(n.Name, st.prefix, "", 1)
98+
key = strings.TrimLeft(key, "/")
99+
output <- &storage.Object{
100+
Key: &key,
101+
ETag: &n.Hash,
102+
ContentType: &n.ContentType,
103+
Mtime: &n.LastModified,
104+
ContentLength: &n.Bytes,
105+
IsLatest: aws.Bool(true),
106+
}
107+
}
108+
return true, nil
109+
})
110+
if err != nil {
111+
return err
112+
}
113+
114+
storage.Log.Debugf("Listing bucket finished")
115+
return nil
116+
117+
}
118+
119+
// PutObject saves object to S3.
120+
// PutObject ignore VersionId, it always save object as latest version.
121+
func (st *Storage) PutObject(obj *storage.Object) error {
122+
opts := objects.CreateOpts{}
123+
if obj.ContentType != nil {
124+
opts.ContentType = *obj.ContentType
125+
}
126+
if obj.Content != nil {
127+
opts.Content = bytes.NewReader(*obj.Content)
128+
}
129+
if obj.ContentDisposition != nil {
130+
opts.ContentDisposition = *obj.ContentDisposition
131+
}
132+
if obj.ContentEncoding != nil {
133+
opts.ContentEncoding = *obj.ContentEncoding
134+
}
135+
if obj.CacheControl != nil {
136+
opts.CacheControl = *obj.CacheControl
137+
}
138+
139+
res := objects.Create(st.conn, st.bucket, path.Join(st.prefix, *obj.Key), opts)
140+
if res.Err != nil {
141+
return res.Err
142+
}
143+
144+
return nil
145+
}
146+
147+
// GetObjectContent read object content and metadata from S3.
148+
func (st *Storage) GetObjectContent(obj *storage.Object) error {
149+
opts := objects.DownloadOpts{}
150+
151+
// Download everything into a DownloadResult struct
152+
res := objects.Download(st.conn, st.bucket, path.Join(st.prefix, *obj.Key), opts)
153+
if res.Err != nil {
154+
return res.Err
155+
}
156+
defer res.Body.Close()
157+
158+
header, err := res.Extract()
159+
if err != nil {
160+
return err
161+
}
162+
163+
buf := bytes.NewBuffer(make([]byte, 0, header.ContentLength))
164+
if _, err := io.Copy(ratelimit.NewWriter(buf, st.rlBucket), res.Body); err != nil {
165+
return err
166+
}
167+
168+
data := buf.Bytes()
169+
obj.Content = &data
170+
obj.ContentType = &header.ContentType
171+
obj.ContentLength = &header.ContentLength
172+
obj.ContentDisposition = &header.ContentDisposition
173+
obj.ContentEncoding = &header.ContentEncoding
174+
obj.ETag = storage.StrongEtag(&header.ETag)
175+
obj.Mtime = &header.LastModified
176+
177+
return nil
178+
}
179+
180+
// GetObjectACL read object ACL from S3.
181+
func (st *Storage) GetObjectACL(obj *storage.Object) error {
182+
return nil
183+
}
184+
185+
// GetObjectMeta update object metadata from S3.
186+
func (st *Storage) GetObjectMeta(obj *storage.Object) error {
187+
opts := objects.GetOpts{}
188+
189+
res := objects.Get(st.conn, st.bucket, path.Join(st.prefix, *obj.Key), opts)
190+
if res.Err != nil {
191+
return res.Err
192+
}
193+
194+
header, err := res.Extract()
195+
if err != nil {
196+
return err
197+
}
198+
199+
obj.ContentType = &header.ContentType
200+
obj.ContentLength = &header.ContentLength
201+
obj.ContentDisposition = &header.ContentDisposition
202+
obj.ContentEncoding = &header.ContentEncoding
203+
obj.ETag = storage.StrongEtag(&header.ETag)
204+
obj.Mtime = &header.LastModified
205+
206+
return nil
207+
}
208+
209+
// DeleteObject remove object from S3.
210+
func (st *Storage) DeleteObject(obj *storage.Object) error {
211+
opts := objects.DeleteOpts{}
212+
213+
res := objects.Delete(st.conn, st.bucket, path.Join(st.prefix, *obj.Key), opts)
214+
if res.Err != nil {
215+
return res.Err
216+
}
217+
218+
return nil
219+
}

0 commit comments

Comments
 (0)