Use adapter pattern for handlers
This commit is contained in:
parent
5466c615aa
commit
27bc86490e
6 changed files with 181 additions and 164 deletions
15
adapters.go
Normal file
15
adapters.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Adapter is an HTTP middleware
|
||||
type Adapter func(http.Handler) http.Handler
|
||||
|
||||
// Adapt applies adapters to an HTTP handler function
|
||||
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
|
||||
for i := len(adapters) - 1; i >= 0; i-- {
|
||||
h = adapters[i](h)
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
188
api.go
188
api.go
|
@ -19,49 +19,17 @@ type CopyObjectInfo struct {
|
|||
}
|
||||
|
||||
// CreateBucketHandler creates a new bucket
|
||||
func (s *Server) CreateBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var bucket minio.BucketInfo
|
||||
func (s *Server) CreateBucketHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var bucket minio.BucketInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&bucket)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
err = s.s3.MakeBucket(bucket.Name, "")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
||||
err = json.NewEncoder(w).Encode(bucket)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// CreateObjectHandler allows to upload a new object
|
||||
func (s *Server) CreateObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
var copy CopyObjectInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(©)
|
||||
err := json.NewDecoder(r.Body).Decode(&bucket)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
var copyConds = minio.NewCopyConditions()
|
||||
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
|
||||
fmt.Println(copy)
|
||||
fmt.Println(objectSource)
|
||||
err = s.s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
|
||||
err = s.s3.MakeBucket(bucket.Name, "")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
|
@ -69,77 +37,119 @@ func (s *Server) CreateObjectHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
err = json.NewEncoder(w).Encode(copy)
|
||||
|
||||
err = json.NewEncoder(w).Encode(bucket)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
err := r.ParseMultipartForm(32 << 20)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
// CreateObjectHandler allows to upload a new object
|
||||
func (s *Server) CreateObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
var copy CopyObjectInfo
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(©)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
var copyConds = minio.NewCopyConditions()
|
||||
objectSource := fmt.Sprintf("/%s/%s", copy.SourceBucketName, copy.SourceObjectName)
|
||||
fmt.Println(copy)
|
||||
fmt.Println(objectSource)
|
||||
err = s.s3.CopyObject(copy.BucketName, copy.ObjectName, objectSource, copyConds)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
err = json.NewEncoder(w).Encode(copy)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
err := r.ParseMultipartForm(32 << 20)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
file, handler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = s.s3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = s.s3.PutObject(vars["bucketName"], handler.Filename, file, "application/octet-stream")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteBucketHandler deletes a bucket
|
||||
func (s *Server) DeleteBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
func (s *Server) DeleteBucketHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s.s3.RemoveBucket(vars["bucketName"])
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err := s.s3.RemoveBucket(vars["bucketName"])
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteObjectHandler deletes an object
|
||||
func (s *Server) DeleteObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
func (s *Server) DeleteObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
err := s.s3.RemoveObject(vars["bucketName"], vars["objectName"])
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err := s.s3.RemoveObject(vars["bucketName"], vars["objectName"])
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
// GetObjectHandler downloads an object to the client
|
||||
func (s *Server) GetObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
objectName := vars["objectName"]
|
||||
func (s *Server) GetObjectHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
objectName := vars["objectName"]
|
||||
|
||||
object, err := s.s3.GetObject(vars["bucketName"], objectName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
object, err := s.s3.GetObject(vars["bucketName"], objectName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", objectName))
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", objectName))
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
|
||||
_, err = io.Copy(w, object)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, err = io.Copy(w, object)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
10
logger.go
10
logger.go
|
@ -7,9 +7,9 @@ import (
|
|||
)
|
||||
|
||||
// Logger logs HTTP requests
|
||||
func Logger() Middleware {
|
||||
return func(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
func Logger() Adapter {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
|
||||
defer func() {
|
||||
|
@ -21,7 +21,7 @@ func Logger() Middleware {
|
|||
)
|
||||
}()
|
||||
|
||||
next(w, r)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
16
main.go
16
main.go
|
@ -29,15 +29,15 @@ func main() {
|
|||
router.
|
||||
Methods("GET").
|
||||
Path("/").
|
||||
HandlerFunc(Chain(IndexHandler, Logger()))
|
||||
Handler(Adapt(IndexHandler(), Logger()))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets").
|
||||
HandlerFunc(Chain(s.BucketsPageHandler, Logger()))
|
||||
Handler(Adapt(s.BucketsPageHandler(), Logger()))
|
||||
router.
|
||||
Methods("GET").
|
||||
Path("/buckets/{bucketName}").
|
||||
HandlerFunc(Chain(s.BucketPageHandler, Logger()))
|
||||
Handler(Adapt(s.BucketPageHandler(), Logger()))
|
||||
|
||||
api := router.PathPrefix("/api").Subrouter()
|
||||
|
||||
|
@ -45,23 +45,23 @@ func main() {
|
|||
buckets.
|
||||
Methods("POST").
|
||||
Path("").
|
||||
HandlerFunc(Chain(s.CreateBucketHandler, Logger()))
|
||||
Handler(Adapt(s.CreateBucketHandler(), Logger()))
|
||||
buckets.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}").
|
||||
HandlerFunc(Chain(s.DeleteBucketHandler, Logger()))
|
||||
Handler(Adapt(s.DeleteBucketHandler(), Logger()))
|
||||
buckets.
|
||||
Methods("POST").
|
||||
Path("/{bucketName}/objects").
|
||||
HandlerFunc(Chain(s.CreateObjectHandler, Logger()))
|
||||
Handler(Adapt(s.CreateObjectHandler(), Logger()))
|
||||
buckets.
|
||||
Methods("GET").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
HandlerFunc(Chain(s.GetObjectHandler, Logger()))
|
||||
Handler(Adapt(s.GetObjectHandler(), Logger()))
|
||||
buckets.
|
||||
Methods("DELETE").
|
||||
Path("/{bucketName}/objects/{objectName}").
|
||||
HandlerFunc(Chain(s.DeleteObjectHandler, Logger()))
|
||||
Handler(Adapt(s.DeleteObjectHandler(), Logger()))
|
||||
|
||||
log.Fatal(http.ListenAndServe(":"+port, router))
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Middleware is an HTTP middleware
|
||||
type Middleware func(http.HandlerFunc) http.HandlerFunc
|
||||
|
||||
// Chain applies middleware to an HTTP handler function
|
||||
func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
|
||||
for i := len(middlewares) - 1; i >= 0; i-- {
|
||||
f = middlewares[i](f)
|
||||
}
|
||||
return f
|
||||
}
|
102
pages.go
102
pages.go
|
@ -22,70 +22,76 @@ type ObjectWithIcon struct {
|
|||
}
|
||||
|
||||
// BucketPageHandler shows the details page of a bucket
|
||||
func (s *Server) BucketPageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
bucketName := mux.Vars(r)["bucketName"]
|
||||
var objects []ObjectWithIcon
|
||||
func (s *Server) BucketPageHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
bucketName := mux.Vars(r)["bucketName"]
|
||||
var objects []ObjectWithIcon
|
||||
|
||||
lp := path.Join("templates", "layout.html")
|
||||
bp := path.Join("templates", "bucket.html")
|
||||
lp := path.Join("templates", "layout.html")
|
||||
bp := path.Join("templates", "bucket.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, bp)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
objectCh := s.s3.ListObjectsV2(bucketName, "", false, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
t, err := template.ParseFiles(lp, bp)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
objectWithIcon := ObjectWithIcon{object, icon(object.Key)}
|
||||
objects = append(objects, objectWithIcon)
|
||||
}
|
||||
|
||||
bucketPage := BucketPage{
|
||||
BucketName: bucketName,
|
||||
Objects: objects,
|
||||
}
|
||||
doneCh := make(chan struct{})
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", bucketPage)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
objectCh := s.s3.ListObjectsV2(bucketName, "", false, doneCh)
|
||||
for object := range objectCh {
|
||||
if object.Err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
objectWithIcon := ObjectWithIcon{object, icon(object.Key)}
|
||||
objects = append(objects, objectWithIcon)
|
||||
}
|
||||
|
||||
bucketPage := BucketPage{
|
||||
BucketName: bucketName,
|
||||
Objects: objects,
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", bucketPage)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// BucketsPageHandler shows all buckets
|
||||
func (s *Server) BucketsPageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
lp := path.Join("templates", "layout.html")
|
||||
ip := path.Join("templates", "index.html")
|
||||
func (s *Server) BucketsPageHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
lp := path.Join("templates", "layout.html")
|
||||
ip := path.Join("templates", "index.html")
|
||||
|
||||
t, err := template.ParseFiles(lp, ip)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
t, err := template.ParseFiles(lp, ip)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
buckets, err := s.s3.ListBuckets()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
buckets, err := s.s3.ListBuckets()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = t.ExecuteTemplate(w, "layout", buckets)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
err = t.ExecuteTemplate(w, "layout", buckets)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// IndexHandler forwards to "/buckets"
|
||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect)
|
||||
func IndexHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/buckets", http.StatusPermanentRedirect)
|
||||
})
|
||||
}
|
||||
|
||||
// icon returns an icon for a file type
|
||||
|
|
Loading…
Reference in a new issue