package main

import (
	"context"
	"log"
	"os"
	"fmt"
	"time"
	"io"
	"io/ioutil"
	"strings"
	"net/http"
	"crypto/tls"
	"strconv"

	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
    "github.com/google/uuid"
)

func main() {
	fmt.Printf("endpoint,nanoseconds\n")

    // Initial setup
	_, isSSL := os.LookupEnv("SSL");
	opts := minio.Options {
		Creds:  credentials.NewStaticV4(os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY"), ""),
		Secure: isSSL,
	}

	if region, ok := os.LookupEnv("REGION"); ok {
		opts.Region = region
	}

	if _, ok := os.LookupEnv("SSL_INSECURE"); ok {
		opts.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
	}

	mc, err := minio.New(os.Getenv("ENDPOINT"), &opts)

	if err != nil {
		log.Fatal("failed connect", err)
		return
	}

    // Create Bucket
    buck := uuid.New().String()
    err = mc.MakeBucket(context.Background(), buck, minio.MakeBucketOptions{ })
    if err != nil {
        log.Fatal(err)
        return
    }

    // List Buckets
	for i := 0; i < 100; i++ {
		start := time.Now()
		_, err := mc.ListBuckets(context.Background())
		elapsed := time.Since(start)
		if err != nil {
			log.Fatal("failed listbucket: ", err)
		return
		}
		fmt.Printf("listbuckets,%v\n", elapsed.Nanoseconds())
	}

    // PutObject
	for i := 0; i < 100; i++ {
		istr := strconv.Itoa(i)
		content := istr + " hello world " + istr
		start := time.Now()
		_, err := mc.PutObject(context.Background(), buck, "element"+istr, strings.NewReader(content), int64(len(content)), minio.PutObjectOptions{ContentType:"application/octet-stream"})
		elapsed := time.Since(start)
		if err != nil {
			log.Fatal("failed putObject: ",err)
			return
		}
		fmt.Printf("putobject,%v\n", elapsed.Nanoseconds())
	}

    // ListObject
	for i := 0; i < 100; i++ {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		start := time.Now()
		objectCh := mc.ListObjects(ctx, buck, minio.ListObjectsOptions{
			Recursive: true,
		})
		for object := range objectCh {
			if object.Err != nil {
				log.Fatal(object.Err)
				return
			}
		}
		elapsed := time.Since(start)
		fmt.Printf("listobjects,%v\n", elapsed.Nanoseconds())
	}

    // GetObject
	for i := 0; i < 100; i++ {
		istr := strconv.Itoa(i)
		start := time.Now()
		object, err := mc.GetObject(context.Background(), buck, "element"+istr, minio.GetObjectOptions{})
		if err != nil {
			log.Fatal(err)
			return
		}
		if _, err = io.Copy(ioutil.Discard, object) ; err != nil {
			log.Fatal("failed getobject: ", err)
			return
		}
		elapsed := time.Since(start)
		fmt.Printf("getobject,%v\n", elapsed.Nanoseconds())
	}

    // RemoveObject
	for i := 0; i < 100; i++ {
		istr := strconv.Itoa(i)
		start := time.Now()
		err = mc.RemoveObject(context.Background(), buck, "element"+istr, minio.RemoveObjectOptions{})
		elapsed := time.Since(start)
		if err != nil {
			log.Fatal(err)
			return
		}
		fmt.Printf("removeobject,%v\n", elapsed.Nanoseconds())
	}

    // RemoveBucket
    err = mc.RemoveBucket(context.Background(), buck)
    if err != nil {
        log.Fatal(err)
        return
    }
}
