186 lines
3.8 KiB
Go
Executable File
186 lines
3.8 KiB
Go
Executable File
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
minio "github.com/minio/minio-go"
|
|
)
|
|
|
|
var nilLocation = os.Getenv("STORE_REGION")
|
|
|
|
const keyBucket = "key"
|
|
|
|
var bucketNames = []string{}
|
|
|
|
type Storage struct {
|
|
client *minio.Client
|
|
}
|
|
|
|
func assertEnv(key string) (string, error) {
|
|
value := os.Getenv(key)
|
|
if value == "" {
|
|
return "", errors.New(key + " not set")
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
func newStorage() (*Storage, error) {
|
|
var id, loc, secret string
|
|
var err error
|
|
if id, err = assertEnv("STORE_ID"); err != nil {
|
|
return nil, err
|
|
}
|
|
if secret, err = assertEnv("STORE_SECRET"); err != nil {
|
|
return nil, err
|
|
}
|
|
if loc, err = assertEnv("STORE_LOC"); err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err = assertEnv("STORE_REGION"); err != nil {
|
|
return nil, err
|
|
}
|
|
client, err := minio.New(loc, id, secret, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err := makeInitialBuckets(client); err != nil {
|
|
return nil, err
|
|
}
|
|
return &Storage{
|
|
client: client,
|
|
}, err
|
|
}
|
|
|
|
func makeInitialBuckets(client *minio.Client) error {
|
|
buckets, err := client.ListBuckets()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
keysFound := false
|
|
for _, bucketInfo := range buckets {
|
|
if bucketInfo.Name == keyBucket {
|
|
keysFound = true
|
|
}
|
|
bucketNames = append(bucketNames, bucketInfo.Name)
|
|
}
|
|
if !keysFound {
|
|
bucketNames = append(bucketNames, keyBucket)
|
|
}
|
|
for _, bucketName := range bucketNames {
|
|
if err := makeMinioBucket(client, bucketName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func makeMinioBucket(client *minio.Client, bucketName string) error {
|
|
log.Print("Making bucket", bucketName, "...")
|
|
if err := client.MakeBucket(bucketName, nilLocation); err == nil {
|
|
log.Print("...Made", bucketName)
|
|
return nil
|
|
}
|
|
exists, err := client.BucketExists(bucketName)
|
|
if err == nil && exists {
|
|
log.Print("...Exists", bucketName)
|
|
return nil
|
|
}
|
|
log.Print("...Can't make bucket", bucketName, err)
|
|
return err
|
|
}
|
|
|
|
func (s *Storage) makeBucket(bucket string) error {
|
|
if bucket == keyBucket {
|
|
return errors.New("reserved bucket name")
|
|
}
|
|
err := makeMinioBucket(s.client, bucket)
|
|
if err == nil {
|
|
bucketNames = append(bucketNames, bucket)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (s *Storage) toGetKey(fname, id string) string {
|
|
return fmt.Sprintf(
|
|
"%v_%v",
|
|
id,
|
|
strings.Split(fname, ".")[0],
|
|
)
|
|
}
|
|
|
|
func (s *Storage) toSetKey(fname, id string) string {
|
|
return fmt.Sprintf(
|
|
"%v_%v.%v",
|
|
s.toGetKey(fname, id),
|
|
time.Now().UnixNano(),
|
|
strings.Split(fname, ".")[1],
|
|
)
|
|
}
|
|
|
|
func (s *Storage) set(bucket, key, value string) error {
|
|
key = encodeKey(key)
|
|
log.Print("server setting in minio")
|
|
if !validBucket(bucket) {
|
|
log.Print("making bucket", bucket)
|
|
if err := s.makeBucket(bucket); err != nil {
|
|
log.Print("cantmake bucket", bucket)
|
|
return err
|
|
}
|
|
}
|
|
log.Print("putting", key)
|
|
_, err := s.client.PutObject(bucket, key, bytes.NewBuffer([]byte(value)), int64(len(value)), minio.PutObjectOptions{})
|
|
log.Print("put err:", err)
|
|
return err
|
|
}
|
|
|
|
func (s *Storage) get(bucket, key string) (string, error) {
|
|
key = encodeKey(key)
|
|
if !validBucket(bucket) {
|
|
return "", errors.New("unknown bucket")
|
|
}
|
|
done := make(chan struct{})
|
|
defer close(done)
|
|
lastKey := ""
|
|
for obj := range s.client.ListObjectsV2(bucket, key, false, done) {
|
|
if lastKey == "" {
|
|
lastKey = obj.Key
|
|
}
|
|
if obj.Key > lastKey {
|
|
lastKey = obj.Key
|
|
}
|
|
}
|
|
if lastKey == "" {
|
|
return "", errors.New("object not found")
|
|
}
|
|
obj, err := s.client.GetObject(bucket, lastKey, minio.GetObjectOptions{})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
body, err := ioutil.ReadAll(obj)
|
|
return string(body), err
|
|
}
|
|
|
|
func validBucket(bucket string) bool {
|
|
for i := range bucketNames {
|
|
if bucketNames[i] == bucket {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func encodeKey(key string) string {
|
|
return strings.Replace(key, "/", "`", -1)
|
|
}
|
|
|
|
func decodeKey(key string) string {
|
|
return strings.Replace(key, "`", "/", -1)
|
|
}
|