From cc4329fb12fddc140f4d06b544b0e8e1ef14b5d5 Mon Sep 17 00:00:00 2001 From: "Frederick F. Kautz IV" Date: Tue, 20 Jan 2015 18:39:30 -0800 Subject: [PATCH] List objects in a bucket. --- pkg/storage/storage.go | 42 ++++++++++++--- pkg/webapi/minioapi/definitions.go | 6 +-- pkg/webapi/minioapi/minioapi.go | 82 ++++++++++++++++++++---------- 3 files changed, 91 insertions(+), 39 deletions(-) diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index a4ee08c3a..c20f0603b 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -3,13 +3,25 @@ package storage import ( "bytes" "io" + "log" + "strings" + "time" ) type Storage struct { - data map[string][]byte + data map[string]storedObject } -type ObjectMetadata struct{} +type storedObject struct { + metadata ObjectMetadata + data []byte +} + +type ObjectMetadata struct { + Key string + SecCreated int64 + Size int +} type GenericError struct { bucket string @@ -27,7 +39,7 @@ func (storage *Storage) CopyObjectToWriter(w io.Writer, bucket string, object st // get object key := bucket + ":" + object if val, ok := storage.data[key]; ok { - objectBuffer := bytes.NewBuffer(val) + objectBuffer := bytes.NewBuffer(val.data) written, err := io.Copy(w, objectBuffer) return written, err } else { @@ -35,16 +47,30 @@ func (storage *Storage) CopyObjectToWriter(w io.Writer, bucket string, object st } } -func (storage *Storage) StoreObject(bucket string, object string, data io.Reader) { - key := bucket + ":" + object +func (storage *Storage) StoreObject(bucket string, key string, data io.Reader) { + objectKey := bucket + ":" + key var bytesBuffer bytes.Buffer + newObject := storedObject{} if _, ok := io.Copy(&bytesBuffer, data); ok == nil { - storage.data[key] = bytesBuffer.Bytes() + newObject.metadata = ObjectMetadata{ + Key: key, + SecCreated: time.Now().Unix(), + Size: len(bytesBuffer.Bytes()), + } + newObject.data = bytesBuffer.Bytes() } + storage.data[objectKey] = newObject } func (storage *Storage) ListObjects(bucket, prefix string, count int) []ObjectMetadata { - return []ObjectMetadata{} + var results []ObjectMetadata + for key, object := range storage.data { + log.Println(key) + if strings.HasPrefix(key, bucket+":") { + results = append(results, object.metadata) + } + } + return results } func Start() (chan<- string, <-chan error, *Storage) { @@ -52,7 +78,7 @@ func Start() (chan<- string, <-chan error, *Storage) { errorChannel := make(chan error) go start(ctrlChannel, errorChannel) return ctrlChannel, errorChannel, &Storage{ - data: make(map[string][]byte), + data: make(map[string]storedObject), } } diff --git a/pkg/webapi/minioapi/definitions.go b/pkg/webapi/minioapi/definitions.go index e03247e1e..bf8216237 100644 --- a/pkg/webapi/minioapi/definitions.go +++ b/pkg/webapi/minioapi/definitions.go @@ -7,9 +7,9 @@ import ( type ListResponse struct { XMLName xml.Name `xml:"ListBucketResult"` Name string `xml:"Name"` - Prefix string + toragerefix string Marker string - MaxKeys int32 + MaxKeys int IsTruncated bool Contents []Content `xml:"Contents",innerxml` } @@ -18,7 +18,7 @@ type Content struct { Key string LastModified string ETag string - Size uint64 + Size int StorageClass string Owner Owner } diff --git a/pkg/webapi/minioapi/minioapi.go b/pkg/webapi/minioapi/minioapi.go index f9466cf20..b5974a892 100644 --- a/pkg/webapi/minioapi/minioapi.go +++ b/pkg/webapi/minioapi/minioapi.go @@ -2,9 +2,11 @@ package minioapi import ( "bytes" + "encoding/json" "encoding/xml" "log" "net/http" + "time" "github.com/gorilla/mux" mstorage "github.com/minio-io/minio/pkg/storage" @@ -14,12 +16,17 @@ type minioApi struct { storage *mstorage.Storage } +type encoder interface { + Encode(v interface{}) error +} + func HttpHandler(storage *mstorage.Storage) http.Handler { mux := mux.NewRouter() api := minioApi{ storage: storage, } - mux.HandleFunc("/", api.listHandler).Methods("GET") + mux.HandleFunc("/", api.listBucketsHandler).Methods("GET") + mux.HandleFunc("/{bucket}/", api.listObjectsHandler).Methods("GET") mux.HandleFunc("/{bucket}/{object:.*}", api.getObjectHandler).Methods("GET") mux.HandleFunc("/{bucket}/{object:.*}", api.putObjectHandler).Methods("PUT") return mux @@ -49,14 +56,18 @@ func (server *minioApi) getObjectHandler(w http.ResponseWriter, req *http.Reques } } -func (server *minioApi) listHandler(w http.ResponseWriter, req *http.Request) { +func (server *minioApi) listBucketsHandler(w http.ResponseWriter, req *http.Request) { + w.Write([]byte("/")) +} + +func (server *minioApi) listObjectsHandler(w http.ResponseWriter, req *http.Request) { vars := mux.Vars(req) //delimiter, ok := vars["delimiter"] //encodingType, ok := vars["encoding-type"] //marker, ok := vars["marker"] //maxKeys, ok := vars["max-keys"] - bucket := "bucket" + bucket := vars["bucket"] //bucket, ok := vars["bucket"] //if ok == false { // w.WriteHeader(http.StatusBadRequest) @@ -67,14 +78,26 @@ func (server *minioApi) listHandler(w http.ResponseWriter, req *http.Request) { prefix = "" } + contentType := "xml" + + if req.Header["Accept"][0] == "application/json" { + contentType = "json" + } + objects := server.storage.ListObjects(bucket, prefix, 1000) response := generateListResult(objects) var bytesBuffer bytes.Buffer - xmlEncoder := xml.NewEncoder(&bytesBuffer) - xmlEncoder.Encode(response) + var encoder encoder + if contentType == "json" { + w.Header().Set("Content-Type", "application/json") + encoder = json.NewEncoder(&bytesBuffer) + } else { + w.Header().Set("Content-Type", "application/xml") + encoder = xml.NewEncoder(&bytesBuffer) + } + encoder.Encode(response) - w.Header().Set("Content-Type", "application/xml") w.Write(bytesBuffer.Bytes()) } @@ -86,31 +109,34 @@ func (server *minioApi) putObjectHandler(w http.ResponseWriter, req *http.Reques } func generateListResult(objects []mstorage.ObjectMetadata) ListResponse { + contents := []Content{} + owner := Owner{ - ID: "MyID", - DisplayName: "MyDisplayName", + ID: "minio", + DisplayName: "minio", } - contents := []Content{ - Content{ - Key: "one", - LastModified: "two", - ETag: "\"ETag\"", - Size: 1, - StorageClass: "three", - Owner: owner, - }, - Content{ - Key: "four", - LastModified: "five", - ETag: "\"ETag\"", - Size: 1, - StorageClass: "six", + + for _, object := range objects { + content := Content{ + Key: object.Key, + LastModified: formatDate(object.SecCreated), + ETag: object.Key, + Size: object.Size, + StorageClass: "STANDARD", Owner: owner, - }, + } + contents = append(contents, content) } - data := &ListResponse{ - Name: "name", - Contents: contents, + data := ListResponse{ + Name: "name", + Contents: contents, + MaxKeys: len(objects), + IsTruncated: false, } - return *data + return data +} + +func formatDate(sec int64) string { + timeStamp := time.Unix(sec, 0) + return timeStamp.Format("2006-01-02T15:04:05.000Z") }