1// +build example
2
3package main
4
5import (
6	"fmt"
7	"log"
8	"os"
9	"sync"
10
11	"github.com/aws/aws-sdk-go/aws"
12	"github.com/aws/aws-sdk-go/aws/session"
13	"github.com/aws/aws-sdk-go/service/s3/s3manager"
14)
15
16type CustomReader struct {
17	fp      *os.File
18	size    int64
19	read    int64
20	signMap map[int64]struct{}
21	mux     sync.Mutex
22}
23
24func (r *CustomReader) Read(p []byte) (int, error) {
25	return r.fp.Read(p)
26}
27
28func (r *CustomReader) ReadAt(p []byte, off int64) (int, error) {
29	n, err := r.fp.ReadAt(p, off)
30	if err != nil {
31		return n, err
32	}
33
34	r.mux.Lock()
35	// Ignore the first signature call
36	if _, ok := r.signMap[off]; ok {
37		// Got the length have read( or means has uploaded), and you can construct your message
38		r.read += int64(n)
39		fmt.Printf("\rtotal read:%d    progress:%d%%", r.read, int(float32(r.read*100)/float32(r.size)))
40	} else {
41		r.signMap[off] = struct{}{}
42	}
43	r.mux.Unlock()
44	return n, err
45}
46
47func (r *CustomReader) Seek(offset int64, whence int) (int64, error) {
48	return r.fp.Seek(offset, whence)
49}
50
51func main() {
52	if len(os.Args) < 4 {
53		log.Println("USAGE ERROR: AWS_REGION=us-west-2 go run -tags example putObjWithProcess.go <bucket> <key for object> <local file name>")
54		return
55	}
56
57	bucket := os.Args[1]
58	key := os.Args[2]
59	filename := os.Args[3]
60
61	sess, err := session.NewSession()
62	if err != nil {
63		log.Fatalf("failed to load session, %v", err)
64	}
65
66	file, err := os.Open(filename)
67	if err != nil {
68		log.Fatalf("failed to open file %v, %v", filename, err)
69	}
70
71	fileInfo, err := file.Stat()
72	if err != nil {
73		log.Fatalf("failed to stat file %v, %v", filename, err)
74		return
75	}
76
77	reader := &CustomReader{
78		fp:      file,
79		size:    fileInfo.Size(),
80		signMap: map[int64]struct{}{},
81	}
82
83	uploader := s3manager.NewUploader(sess, func(u *s3manager.Uploader) {
84		u.PartSize = 5 * 1024 * 1024
85		u.LeavePartsOnError = true
86	})
87
88	output, err := uploader.Upload(&s3manager.UploadInput{
89		Bucket: aws.String(bucket),
90		Key:    aws.String(key),
91		Body:   reader,
92	})
93	if err != nil {
94		log.Fatalf("failed to put file %v, %v", filename, err)
95		return
96	}
97
98	fmt.Println()
99	log.Println(output.Location)
100}
101