parent
63d9689214
commit
c23fa26830
@ -0,0 +1,152 @@ |
||||
package inmemory |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto/sha256" |
||||
"fmt" |
||||
"io" |
||||
"log" |
||||
"strings" |
||||
"time" |
||||
|
||||
mstorage "github.com/minio-io/minio/pkg/storage" |
||||
) |
||||
|
||||
type Storage struct { |
||||
bucketdata map[string]storedBucket |
||||
objectdata map[string]storedObject |
||||
} |
||||
|
||||
type storedBucket struct { |
||||
metadata mstorage.BucketMetadata |
||||
// owner string // TODO
|
||||
// id string // TODO
|
||||
} |
||||
|
||||
type storedObject struct { |
||||
metadata mstorage.ObjectMetadata |
||||
data []byte |
||||
} |
||||
|
||||
func (storage *Storage) CopyObjectToWriter(w io.Writer, bucket string, object string) (int64, error) { |
||||
// TODO synchronize access
|
||||
// get object
|
||||
key := bucket + ":" + object |
||||
if val, ok := storage.objectdata[key]; ok { |
||||
objectBuffer := bytes.NewBuffer(val.data) |
||||
written, err := io.Copy(w, objectBuffer) |
||||
return written, err |
||||
} else { |
||||
return 0, mstorage.ObjectNotFound{Bucket: bucket, Path: object} |
||||
} |
||||
} |
||||
|
||||
func (storage *Storage) StoreObject(bucket string, key string, data io.Reader) error { |
||||
objectKey := bucket + ":" + key |
||||
if _, ok := storage.objectdata[objectKey]; ok == true { |
||||
return mstorage.ObjectExists{Bucket: bucket, Key: key} |
||||
} |
||||
var bytesBuffer bytes.Buffer |
||||
newObject := storedObject{} |
||||
if _, ok := io.Copy(&bytesBuffer, data); ok == nil { |
||||
size := bytesBuffer.Len() |
||||
etag := fmt.Sprintf("%x", sha256.Sum256(bytesBuffer.Bytes())) |
||||
newObject.metadata = mstorage.ObjectMetadata{ |
||||
Key: key, |
||||
SecCreated: time.Now().Unix(), |
||||
Size: size, |
||||
ETag: etag, |
||||
} |
||||
newObject.data = bytesBuffer.Bytes() |
||||
} |
||||
storage.objectdata[objectKey] = newObject |
||||
return nil |
||||
} |
||||
|
||||
func (storage *Storage) StoreBucket(bucketName string) error { |
||||
if !isValidBucket(bucketName) { |
||||
return mstorage.BucketNameInvalid{Bucket: bucketName} |
||||
} |
||||
|
||||
if _, ok := storage.bucketdata[bucketName]; ok == true { |
||||
return mstorage.BucketExists{Bucket: bucketName} |
||||
} |
||||
newBucket := storedBucket{} |
||||
newBucket.metadata = mstorage.BucketMetadata{ |
||||
Name: bucketName, |
||||
Created: time.Now().Unix(), |
||||
} |
||||
log.Println(bucketName) |
||||
storage.bucketdata[bucketName] = newBucket |
||||
return nil |
||||
} |
||||
|
||||
func (storage *Storage) ListObjects(bucket, prefix string, count int) []mstorage.ObjectMetadata { |
||||
// TODO prefix and count handling
|
||||
var results []mstorage.ObjectMetadata |
||||
for key, object := range storage.objectdata { |
||||
if strings.HasPrefix(key, bucket+":") { |
||||
results = append(results, object.metadata) |
||||
} |
||||
} |
||||
return results |
||||
} |
||||
|
||||
func (storage *Storage) ListBuckets(prefix string) []mstorage.BucketMetadata { |
||||
// TODO prefix handling
|
||||
var results []mstorage.BucketMetadata |
||||
for _, bucket := range storage.bucketdata { |
||||
results = append(results, bucket.metadata) |
||||
} |
||||
return results |
||||
} |
||||
|
||||
func Start() (chan<- string, <-chan error, *Storage) { |
||||
ctrlChannel := make(chan string) |
||||
errorChannel := make(chan error) |
||||
go start(ctrlChannel, errorChannel) |
||||
return ctrlChannel, errorChannel, &Storage{ |
||||
bucketdata: make(map[string]storedBucket), |
||||
objectdata: make(map[string]storedObject), |
||||
} |
||||
} |
||||
|
||||
func start(ctrlChannel <-chan string, errorChannel chan<- error) { |
||||
close(errorChannel) |
||||
} |
||||
|
||||
func isValidBucket(bucket string) bool { |
||||
l := len(bucket) |
||||
if l < 3 || l > 63 { |
||||
return false |
||||
} |
||||
|
||||
valid := false |
||||
prev := byte('.') |
||||
for i := 0; i < len(bucket); i++ { |
||||
c := bucket[i] |
||||
switch { |
||||
default: |
||||
return false |
||||
case 'a' <= c && c <= 'z': |
||||
valid = true |
||||
case '0' <= c && c <= '9': |
||||
// Is allowed, but bucketname can't be just numbers.
|
||||
// Therefore, don't set valid to true
|
||||
case c == '-': |
||||
if prev == '.' { |
||||
return false |
||||
} |
||||
case c == '.': |
||||
if prev == '.' || prev == '-' { |
||||
return false |
||||
} |
||||
} |
||||
prev = c |
||||
} |
||||
|
||||
if prev == '-' || prev == '.' { |
||||
return false |
||||
} |
||||
return valid |
||||
} |
@ -1,37 +1,37 @@ |
||||
package storage |
||||
|
||||
type GenericError struct { |
||||
bucket string |
||||
path string |
||||
Bucket string |
||||
Path string |
||||
} |
||||
|
||||
type ObjectExists struct { |
||||
bucket string |
||||
key string |
||||
Bucket string |
||||
Key string |
||||
} |
||||
|
||||
type BucketNameInvalid struct { |
||||
bucket string |
||||
Bucket string |
||||
} |
||||
|
||||
type BucketExists struct { |
||||
bucket string |
||||
Bucket string |
||||
} |
||||
|
||||
type ObjectNotFound GenericError |
||||
|
||||
func (self ObjectNotFound) Error() string { |
||||
return "Object not Found: " + self.bucket + "#" + self.path |
||||
return "Object not Found: " + self.Bucket + "#" + self.Path |
||||
} |
||||
|
||||
func (self ObjectExists) Error() string { |
||||
return "Object exists: " + self.bucket + "#" + self.key |
||||
return "Object exists: " + self.Bucket + "#" + self.Key |
||||
} |
||||
|
||||
func (self BucketNameInvalid) Error() string { |
||||
return "Bucket name invalid: " + self.bucket |
||||
return "Bucket name invalid: " + self.Bucket |
||||
} |
||||
|
||||
func (self BucketExists) Error() string { |
||||
return "Bucket exists: " + self.bucket |
||||
return "Bucket exists: " + self.Bucket |
||||
} |
||||
|
Loading…
Reference in new issue