/
s3.go
151 lines (131 loc) · 3.47 KB
/
s3.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package files
import (
"fmt"
"io"
"mime"
"net/http"
"path/filepath"
// I _really_ don't want to deal with AWS API stuff by hand.
"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"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)
type S3Provider struct {
FileProvider
Region string
Bucket string
Endpoint string
KeyID string
KeySecret string
svc s3.S3
sess session.Session
}
// Setup runs when the application starts up, and allows for things like authentication.
func (s *S3Provider) Setup(args map[string]string) bool {
config := &aws.Config{Region: aws.String(s.Region)}
if s.KeyID != "" && s.KeySecret != "" {
config = &aws.Config{
Region: aws.String(s.Region),
Credentials: credentials.NewStaticCredentials(s.KeyID, s.KeySecret, ""),
}
}
if s.Endpoint != "" {
config.Endpoint = &s.Endpoint
}
ss, err := session.NewSession(config)
s.sess = *ss
if err != nil {
return false
}
s.svc = *s3.New(&s.sess)
return true
}
// GetDirectory fetches a directory's contents.
func (s *S3Provider) GetDirectory(path string) Directory {
resp, err := s.svc.ListObjectsV2(&s3.ListObjectsV2Input{Bucket: aws.String(s.Bucket)})
if err != nil {
fmt.Println(err)
return Directory{}
}
dir := Directory{}
for _, item := range resp.Contents {
ik := *item.Key
// Why is this here? AWS returns a complete list of files, including
// files within subdirectories (prefixed with the dir name). So we can
// ignore directories altogether -- I would prefer to display them but
// not sure what the best method of distinguishing them in ObjectInfo()
// would be.
if ik[len(ik)-1:] == "/" {
continue
}
file := FileInfo{
IsDirectory: false,
Name: *item.Key,
}
dir.Files = append(dir.Files, file)
}
return dir
}
func (s *S3Provider) SendFile(path string) (stream io.Reader, contenttype string, err error) {
req, err := s.svc.GetObject(&s3.GetObjectInput{
Bucket: &s.Bucket,
Key: &path,
})
if err != nil {
return stream, contenttype, err
}
contenttype = mime.TypeByExtension(filepath.Ext(path))
if contenttype == "" {
var buf [512]byte
n, _ := io.ReadFull(req.Body, buf[:])
contenttype = http.DetectContentType(buf[:n])
}
return req.Body, contenttype, err
}
func (s *S3Provider) SaveFile(file io.Reader, filename string, path string) bool {
uploader := s3manager.NewUploader(&s.sess)
_, err := uploader.Upload(&s3manager.UploadInput{
Bucket: &s.Bucket,
Key: &filename,
Body: file,
})
if err != nil {
return false
}
return true
}
func (s *S3Provider) ObjectInfo(path string) (bool, bool, string) {
if path == "" {
return true, true, ""
}
_, err := s.svc.GetObject(&s3.GetObjectInput{
Bucket: &s.Bucket,
Key: &path,
})
if err != nil {
fmt.Println(err)
return false, false, ""
}
return true, false, ""
}
// CreateDirectory will create a directory on services that support it.
func (s *S3Provider) CreateDirectory(path string) bool {
return false
}
// Delete simply deletes a file. This is expected to be a destructive action by default.
func (s *S3Provider) Delete(path string) bool {
_, err := s.svc.DeleteObject(&s3.DeleteObjectInput{Bucket: aws.String(s.Bucket), Key: aws.String(path)})
if err != nil {
return false
}
err = s.svc.WaitUntilObjectNotExists(&s3.HeadObjectInput{
Bucket: aws.String(s.Bucket),
Key: aws.String(path),
})
if err != nil {
return false
}
return true
}