gos/s3.go
Lunny Xiao 5b01a4dbe2
All checks were successful
continuous-integration/drone/push Build is passing
Fix bug
2020-03-27 10:18:14 +08:00

156 lines
3.0 KiB
Go

// Copyright 2020 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag"
"net/http"
"os"
"path"
"strings"
"time"
"code.gitea.io/log"
minio "github.com/minio/minio-go/v6"
)
var (
endpoint = flag.String("endpoint", "", "s3 endpoint")
accessKeyID = flag.String("accessKeyID", "", "s3 accessKeyID")
secretAccessKey = flag.String("secretAccessKey", "", "s3 secret access key")
bucket = flag.String("bucket", "", "s3 bucket")
useSSL = flag.Bool("useSSL", false, "if use SSL")
)
func buildMinioPath(p string) string {
return strings.TrimPrefix(p, "/")
}
func buildMinioDir(p string) string {
v := buildMinioPath(p)
if !strings.HasSuffix(v, "/") {
return v + "/"
}
return v
}
type s3FileInfo struct {
minio.ObjectInfo
}
func (fi s3FileInfo) IsDir() bool {
return strings.HasSuffix(fi.ObjectInfo.Key, "/")
}
func (fi s3FileInfo) ModTime() time.Time {
return fi.ObjectInfo.LastModified
}
func (fi s3FileInfo) Mode() os.FileMode {
return 0600
}
func (fi s3FileInfo) Name() string {
return path.Base(fi.ObjectInfo.Key)
}
func (fi s3FileInfo) Size() int64 {
return fi.ObjectInfo.Size
}
func (fi s3FileInfo) Sys() interface{} {
return nil
}
type s3File struct {
p string
*minio.Object
info *minio.ObjectInfo
s3 *s3
}
func (f s3File) isDir() bool {
return strings.HasSuffix(f.p, "/")
}
func (f s3File) Stat() (os.FileInfo, error) {
if f.isDir() {
return s3FileInfo{minio.ObjectInfo{Key: f.p}}, nil
}
return &s3FileInfo{*f.info}, nil
}
func (f s3File) Readdir(count int) ([]os.FileInfo, error) {
doneCh := make(chan struct{})
defer close(doneCh)
log.Debug("List all files from %s: %s", f.s3.bucket, f.p)
objectCh := f.s3.client.ListObjects(f.s3.bucket, buildMinioPath(f.p), false, doneCh)
var files []os.FileInfo
for object := range objectCh {
if object.Err != nil {
return nil, object.Err
}
// ignore itself
if object.Key == f.p {
continue
}
files = append(files, s3FileInfo{object})
}
return files, nil
}
type s3 struct {
client *minio.Client
bucket string
}
func (s *s3) Open(name string) (http.File, error) {
p := buildMinioPath(name)
if p == "" {
p = "/"
}
if p == "/" {
return s3File{p, nil, nil, s}, nil
}
log.Debug("GetObject from %s: %s", s.bucket, p)
obj, err := s.client.GetObject(s.bucket, p, minio.GetObjectOptions{})
if err != nil {
return nil, err
}
if !strings.HasSuffix(name, "/") {
info, err := obj.Stat()
if err != nil {
if realErr, ok := err.(minio.ErrorResponse); ok && realErr.Code == "NoSuchKey" {
return nil, os.ErrNotExist
}
return nil, err
}
return s3File{p, obj, &info, s}, nil
}
return s3File{p, obj, nil, s}, nil
}
func s3FileSystem(endpoint, accessKeyID, secretAccessKey, bucket string, useSSL bool) (http.FileSystem, error) {
client, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL)
if err != nil {
return nil, err
}
return &s3{
client: client,
bucket: bucket,
}, nil
}