127 lines
3.0 KiB
Go
Raw Normal View History

2022-05-22 22:46:08 +09:00
package main
import (
2022-05-29 09:17:07 +09:00
"fmt"
"io"
2022-05-29 09:30:15 +09:00
"log"
2022-05-22 22:46:08 +09:00
"net/http"
"strings"
2022-05-22 22:46:08 +09:00
"github.com/syumai/workers"
2022-09-13 23:19:32 +09:00
"github.com/syumai/workers/cloudflare"
2022-05-22 22:46:08 +09:00
)
2022-05-29 09:17:07 +09:00
// bucketName is R2 bucket name defined in wrangler.toml.
const bucketName = "BUCKET"
2022-05-29 09:30:15 +09:00
func handleErr(w http.ResponseWriter, msg string, err error) {
log.Println(err)
2022-05-29 09:17:07 +09:00
w.WriteHeader(http.StatusInternalServerError)
w.Header().Set("Content-Type", "text/plain")
2022-05-29 09:17:07 +09:00
w.Write([]byte(msg))
}
2023-02-11 12:37:38 +09:00
type server struct{}
2024-04-17 00:56:47 +09:00
func (s *server) bucket() (*cloudflare.R2Bucket, error) {
return cloudflare.NewR2Bucket(bucketName)
}
func (s *server) post(w http.ResponseWriter, req *http.Request, key string) {
2024-04-17 00:56:47 +09:00
bucket, err := s.bucket()
2023-02-11 12:37:38 +09:00
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)
2022-05-29 09:17:07 +09:00
return
}
for _, obj := range objects.Objects {
if obj.Key == key {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "key %s already exists\n", key)
return
}
}
2023-02-11 12:37:38 +09:00
_, err = bucket.Put(key, req.Body, &cloudflare.R2PutOptions{
2022-09-13 23:19:32 +09:00
HTTPMetadata: cloudflare.R2HTTPMetadata{
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"))
}
2024-04-17 00:56:47 +09:00
func (s *server) get(w http.ResponseWriter, key string) {
// get image object from R2
2024-04-17 00:56:47 +09:00
bucket, err := s.bucket()
2023-02-11 12:37:38 +09:00
if err != nil {
handleErr(w, "failed to initialize R2Bucket\n", err)
return
}
imgObj, err := bucket.Get(key)
2022-05-29 09:17:07 +09:00
if err != nil {
2022-05-29 09:30:15 +09:00
handleErr(w, "failed to get R2Object\n", err)
2022-05-29 09:17:07 +09:00
return
}
if imgObj == nil {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(fmt.Sprintf("image not found: %s", key)))
return
}
2022-05-29 09:17:07 +09:00
w.Header().Set("Cache-Control", "public, max-age=14400")
w.Header().Set("ETag", fmt.Sprintf("W/%s", imgObj.HTTPETag))
contentType := "application/octet-stream"
2022-05-29 11:14:27 +09:00
if imgObj.HTTPMetadata.ContentType != "" {
contentType = imgObj.HTTPMetadata.ContentType
2022-05-29 09:17:07 +09:00
}
w.Header().Set("Content-Type", contentType)
io.Copy(w, imgObj.Body)
}
2024-04-17 00:56:47 +09:00
func (s *server) delete(w http.ResponseWriter, key string) {
// delete image object from R2
2024-04-17 00:56:47 +09:00
bucket, err := s.bucket()
2023-02-11 12:37:38 +09:00
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":
2024-04-17 00:56:47 +09:00
s.get(w, key)
return
case "DELETE":
2024-04-17 00:56:47 +09:00
s.delete(w, key)
return
case "POST":
s.post(w, req, key)
2022-05-29 22:07:41 +09:00
return
default:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("url not found\n"))
return
}
}
2022-05-22 22:46:08 +09:00
func main() {
2023-02-11 12:37:38 +09:00
workers.Serve(&server{})
2022-05-22 22:46:08 +09:00
}