mirror of
https://github.com/syumai/workers.git
synced 2025-03-10 17:29:11 +00:00
127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/syumai/workers"
|
|
"github.com/syumai/workers/cloudflare/r2"
|
|
)
|
|
|
|
// bucketName is R2 bucket name defined in wrangler.toml.
|
|
const bucketName = "BUCKET"
|
|
|
|
func handleErr(w http.ResponseWriter, msg string, err error) {
|
|
log.Println(err)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.Write([]byte(msg))
|
|
}
|
|
|
|
type server struct{}
|
|
|
|
func (s *server) bucket() (*r2.Bucket, error) {
|
|
return r2.NewBucket(bucketName)
|
|
}
|
|
|
|
func (s *server) post(w http.ResponseWriter, req *http.Request, key string) {
|
|
bucket, err := s.bucket()
|
|
if err != nil {
|
|
handleErr(w, "failed to initialize R2Bucket\n", err)
|
|
return
|
|
}
|
|
objects, err := bucket.List()
|
|
if err != nil {
|
|
handleErr(w, "failed to list R2Objects\n", err)
|
|
return
|
|
}
|
|
for _, obj := range objects.Objects {
|
|
if obj.Key == key {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
fmt.Fprintf(w, "key %s already exists\n", key)
|
|
return
|
|
}
|
|
}
|
|
_, err = bucket.Put(key, req.Body, &r2.PutOptions{
|
|
HTTPMetadata: r2.HTTPMetadata{
|
|
ContentType: req.Header.Get("Content-Type"),
|
|
},
|
|
CustomMetadata: map[string]string{"custom-key": "custom-value"},
|
|
})
|
|
if err != nil {
|
|
handleErr(w, "failed to put R2Object\n", err)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusCreated)
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.Write([]byte("successfully uploaded image"))
|
|
}
|
|
|
|
func (s *server) get(w http.ResponseWriter, key string) {
|
|
// get image object from R2
|
|
bucket, err := s.bucket()
|
|
if err != nil {
|
|
handleErr(w, "failed to initialize R2Bucket\n", err)
|
|
return
|
|
}
|
|
imgObj, err := bucket.Get(key)
|
|
if err != nil {
|
|
handleErr(w, "failed to get R2Object\n", err)
|
|
return
|
|
}
|
|
if imgObj == nil {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(fmt.Sprintf("image not found: %s", key)))
|
|
return
|
|
}
|
|
w.Header().Set("Cache-Control", "public, max-age=14400")
|
|
w.Header().Set("ETag", fmt.Sprintf("W/%s", imgObj.HTTPETag))
|
|
contentType := "application/octet-stream"
|
|
if imgObj.HTTPMetadata.ContentType != "" {
|
|
contentType = imgObj.HTTPMetadata.ContentType
|
|
}
|
|
w.Header().Set("Content-Type", contentType)
|
|
io.Copy(w, imgObj.Body)
|
|
}
|
|
|
|
func (s *server) delete(w http.ResponseWriter, key string) {
|
|
// delete image object from R2
|
|
bucket, err := s.bucket()
|
|
if err != nil {
|
|
handleErr(w, "failed to initialize R2Bucket\n", err)
|
|
return
|
|
}
|
|
if err := bucket.Delete(key); err != nil {
|
|
handleErr(w, "failed to delete R2Object\n", err)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.Write([]byte("successfully deleted image"))
|
|
}
|
|
|
|
func (s *server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
key := strings.TrimPrefix(req.URL.Path, "/")
|
|
switch req.Method {
|
|
case "GET":
|
|
s.get(w, key)
|
|
return
|
|
case "DELETE":
|
|
s.delete(w, key)
|
|
return
|
|
case "POST":
|
|
s.post(w, req, key)
|
|
return
|
|
default:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte("url not found\n"))
|
|
return
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
workers.Serve(&server{})
|
|
}
|