Read credentials from Redis
parent
ce971a32b8
commit
bf94a2e2bf
|
@ -0,0 +1,35 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* types */
|
||||||
|
|
||||||
|
type credential struct {
|
||||||
|
AccessKey string
|
||||||
|
SecretKey string
|
||||||
|
// Region is critical when signing requests.
|
||||||
|
Region string
|
||||||
|
// Endpoint is the base URL of the bucket, including the bucket name (in either the domain or path).
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// https://bucketname.s3.us-west-2.amazonaws.com
|
||||||
|
// http://my-minio.example.com/bucket-name
|
||||||
|
Endpoint string
|
||||||
|
// ACL is an optional canned ACL to set on objects
|
||||||
|
ACL string
|
||||||
|
// Prefix is a string to prepend to object keys
|
||||||
|
Prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cred credential) validate() error {
|
||||||
|
if strings.HasSuffix(cred.Endpoint, "/") {
|
||||||
|
return fmt.Errorf("%w: endpoint should not end with slash", errBadRequest)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(cred.Prefix, "/") {
|
||||||
|
return fmt.Errorf("%w: prefix should not start with slash", errBadRequest)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -40,6 +39,13 @@ type createMultipartUploadRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleCreateMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
func handleCreateMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
cred, err := getCredential(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
r := createMultipartUploadReq{}
|
r := createMultipartUploadReq{}
|
||||||
decoder := json.NewDecoder(req.Body)
|
decoder := json.NewDecoder(req.Body)
|
||||||
if err := decoder.Decode(&r); err != nil {
|
if err := decoder.Decode(&r); err != nil {
|
||||||
|
@ -52,14 +58,6 @@ func handleCreateMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred := credential{
|
|
||||||
AccessKey: os.Getenv("MINIO_ACCESS_KEY"),
|
|
||||||
SecretKey: os.Getenv("MINIO_SECRET_KEY"),
|
|
||||||
Region: os.Getenv("MINIO_REGION_NAME"),
|
|
||||||
Endpoint: os.Getenv("MINIO_ENDPOINT"),
|
|
||||||
Prefix: os.Getenv("PREFIX"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Derive the object key
|
// Derive the object key
|
||||||
key := cred.Prefix + r.Filename
|
key := cred.Prefix + r.Filename
|
||||||
|
|
||||||
|
@ -82,6 +80,12 @@ type getUploadedPartsRes []part
|
||||||
|
|
||||||
func handleGetUploadedParts(w http.ResponseWriter, req *http.Request) {
|
func handleGetUploadedParts(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
|
cred, err := getCredential(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
uploadID := vars["uploadID"]
|
uploadID := vars["uploadID"]
|
||||||
key := req.URL.Query().Get("key")
|
key := req.URL.Query().Get("key")
|
||||||
|
|
||||||
|
@ -90,14 +94,6 @@ func handleGetUploadedParts(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred := credential{
|
|
||||||
AccessKey: os.Getenv("MINIO_ACCESS_KEY"),
|
|
||||||
SecretKey: os.Getenv("MINIO_SECRET_KEY"),
|
|
||||||
Region: os.Getenv("MINIO_REGION_NAME"),
|
|
||||||
Endpoint: os.Getenv("MINIO_ENDPOINT"),
|
|
||||||
Prefix: os.Getenv("PREFIX"),
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := make(getUploadedPartsRes, 0, 0)
|
parts := make(getUploadedPartsRes, 0, 0)
|
||||||
var nextPartNumberMarker uint32
|
var nextPartNumberMarker uint32
|
||||||
for {
|
for {
|
||||||
|
@ -127,6 +123,12 @@ type signPartUploadRes struct {
|
||||||
|
|
||||||
func handleSignPartUpload(w http.ResponseWriter, req *http.Request) {
|
func handleSignPartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
|
cred, err := getCredential(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
uploadID := vars["uploadID"]
|
uploadID := vars["uploadID"]
|
||||||
key := req.URL.Query().Get("key")
|
key := req.URL.Query().Get("key")
|
||||||
partNumber, err := strconv.ParseUint(vars["uploadPart"], 10, 16)
|
partNumber, err := strconv.ParseUint(vars["uploadPart"], 10, 16)
|
||||||
|
@ -140,14 +142,6 @@ func handleSignPartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred := credential{
|
|
||||||
AccessKey: os.Getenv("MINIO_ACCESS_KEY"),
|
|
||||||
SecretKey: os.Getenv("MINIO_SECRET_KEY"),
|
|
||||||
Region: os.Getenv("MINIO_REGION_NAME"),
|
|
||||||
Endpoint: os.Getenv("MINIO_ENDPOINT"),
|
|
||||||
Prefix: os.Getenv("PREFIX"),
|
|
||||||
}
|
|
||||||
|
|
||||||
params := make(url.Values)
|
params := make(url.Values)
|
||||||
params.Add("partNumber", strconv.FormatUint(partNumber, 10))
|
params.Add("partNumber", strconv.FormatUint(partNumber, 10))
|
||||||
params.Add("uploadId", uploadID)
|
params.Add("uploadId", uploadID)
|
||||||
|
@ -182,6 +176,12 @@ func (r completeMultipartUploadReq) validate() error {
|
||||||
|
|
||||||
func handleCompleteMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
func handleCompleteMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
|
cred, err := getCredential(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
uploadID := vars["uploadID"]
|
uploadID := vars["uploadID"]
|
||||||
key := req.URL.Query().Get("key")
|
key := req.URL.Query().Get("key")
|
||||||
|
|
||||||
|
@ -202,14 +202,6 @@ func handleCompleteMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred := credential{
|
|
||||||
AccessKey: os.Getenv("MINIO_ACCESS_KEY"),
|
|
||||||
SecretKey: os.Getenv("MINIO_SECRET_KEY"),
|
|
||||||
Region: os.Getenv("MINIO_REGION_NAME"),
|
|
||||||
Endpoint: os.Getenv("MINIO_ENDPOINT"),
|
|
||||||
Prefix: os.Getenv("PREFIX"),
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := completeMultipartUpload(key, uploadID, r.Parts, cred)
|
result, err := completeMultipartUpload(key, uploadID, r.Parts, cred)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, req, fmt.Errorf("%w: %s", errInternalServerError, err))
|
errorResponse(w, req, fmt.Errorf("%w: %s", errInternalServerError, err))
|
||||||
|
@ -224,6 +216,12 @@ func handleCompleteMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
func handleAbortMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
func handleAbortMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
|
cred, err := getCredential(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
uploadID := vars["uploadID"]
|
uploadID := vars["uploadID"]
|
||||||
key := req.URL.Query().Get("key")
|
key := req.URL.Query().Get("key")
|
||||||
|
|
||||||
|
@ -232,15 +230,7 @@ func handleAbortMultipartUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cred := credential{
|
err = abortMultipartUpload(key, uploadID, cred)
|
||||||
AccessKey: os.Getenv("MINIO_ACCESS_KEY"),
|
|
||||||
SecretKey: os.Getenv("MINIO_SECRET_KEY"),
|
|
||||||
Region: os.Getenv("MINIO_REGION_NAME"),
|
|
||||||
Endpoint: os.Getenv("MINIO_ENDPOINT"),
|
|
||||||
Prefix: os.Getenv("PREFIX"),
|
|
||||||
}
|
|
||||||
|
|
||||||
err := abortMultipartUpload(key, uploadID, cred)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, req, fmt.Errorf("%w: %s", errInternalServerError, err))
|
errorResponse(w, req, fmt.Errorf("%w: %s", errInternalServerError, err))
|
||||||
return
|
return
|
||||||
|
|
55
handlers.go
55
handlers.go
|
@ -1,9 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
var globalStore store
|
var globalStore store
|
||||||
|
@ -16,6 +21,38 @@ func setupHandlers() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* credentials */
|
||||||
|
|
||||||
|
func getCredential(id string) (credential, error) {
|
||||||
|
cred := credential{}
|
||||||
|
|
||||||
|
b, err := globalStore.get(id)
|
||||||
|
if err != nil {
|
||||||
|
return cred, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(b, &cred)
|
||||||
|
if err != nil {
|
||||||
|
return cred, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cred, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCredential(id string, cred credential, expire time.Duration) error {
|
||||||
|
b, err := json.Marshal(cred)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = globalStore.put(id, b, expire)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
/* templates */
|
/* templates */
|
||||||
|
|
||||||
var tmpl = template.Must(template.ParseFS(assets, "web/*.tmpl"))
|
var tmpl = template.Must(template.ParseFS(assets, "web/*.tmpl"))
|
||||||
|
@ -23,5 +60,23 @@ var tmpl = template.Must(template.ParseFS(assets, "web/*.tmpl"))
|
||||||
/* upload template */
|
/* upload template */
|
||||||
|
|
||||||
func handleUpload(w http.ResponseWriter, req *http.Request) {
|
func handleUpload(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
_, err := getCredential(vars["id"])
|
||||||
|
if errors.Is(err, errNotFound) {
|
||||||
|
errorResponseStatus(w, req, err)
|
||||||
|
tmpl.ExecuteTemplate(w, "upload-not-found.tmpl", nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
errorResponse(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tmpl.ExecuteTemplate(w, "upload.tmpl", nil)
|
tmpl.ExecuteTemplate(w, "upload.tmpl", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create template */
|
||||||
|
|
||||||
|
func handleCreate(w http.ResponseWriter, req *http.Request) {
|
||||||
|
tmpl.ExecuteTemplate(w, "create.tmpl", nil)
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ var errNotFound = errors.New("not found")
|
||||||
var errBadRequest = errors.New("bad request")
|
var errBadRequest = errors.New("bad request")
|
||||||
var errInternalServerError = errors.New("internal server error")
|
var errInternalServerError = errors.New("internal server error")
|
||||||
|
|
||||||
func errorResponse(w http.ResponseWriter, req *http.Request, err error) {
|
func errorResponseStatus(w http.ResponseWriter, req *http.Request, err error) {
|
||||||
errorMessage := err.Error()
|
errorMessage := err.Error()
|
||||||
errorStatus := http.StatusInternalServerError
|
errorStatus := http.StatusInternalServerError
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@ func errorResponse(w http.ResponseWriter, req *http.Request, err error) {
|
||||||
errorStatus = http.StatusInternalServerError
|
errorStatus = http.StatusInternalServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("%s %s: %s", req.Method, req.URL.Path, errorMessage)
|
log.Printf("%s %s: %s", req.Method, req.RequestURI, errorMessage)
|
||||||
w.WriteHeader(errorStatus)
|
w.WriteHeader(errorStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func errorResponse(w http.ResponseWriter, req *http.Request, err error) {
|
||||||
|
errorResponseStatus(w, req, err)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func middlewareLogger(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Do stuff here
|
||||||
|
log.Printf("%s: %s", r.Method, r.RequestURI)
|
||||||
|
// Call the next handler, which can be another middleware in the chain, or the final handler.
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
16
main.go
16
main.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
@ -20,16 +21,22 @@ func main() {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupS3()
|
|
||||||
setupHandlers()
|
setupHandlers()
|
||||||
|
setupS3()
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
uploadRouter := router.PathPrefix("/{id}").Subrouter()
|
router.Use(middlewareLogger)
|
||||||
router.PathPrefix("/assets").Handler(http.FileServer(http.FS(assetsWeb)))
|
|
||||||
|
|
||||||
uploadRouter.Path("").HandlerFunc(handleUpload)
|
router.Methods(http.MethodGet).PathPrefix("/assets").Handler(http.FileServer(http.FS(assetsWeb)))
|
||||||
|
router.Methods(http.MethodGet).Path("/favicon.ico").Handler(http.FileServer(http.FS(assetsWeb)))
|
||||||
|
router.Methods(http.MethodGet).Path("/").HandlerFunc(handleCreate)
|
||||||
|
uploadRouter := router.PathPrefix("/{id}").Subrouter()
|
||||||
|
|
||||||
|
uploadTemplateRouter := uploadRouter.Path("").Subrouter()
|
||||||
s3Router := uploadRouter.PathPrefix("/s3/multipart").Subrouter()
|
s3Router := uploadRouter.PathPrefix("/s3/multipart").Subrouter()
|
||||||
|
|
||||||
|
uploadTemplateRouter.Methods(http.MethodGet).Path("").HandlerFunc(handleUpload)
|
||||||
|
|
||||||
s3Router.Methods(http.MethodPost).Path("").HandlerFunc(handleCreateMultipartUpload)
|
s3Router.Methods(http.MethodPost).Path("").HandlerFunc(handleCreateMultipartUpload)
|
||||||
s3Router.Methods(http.MethodGet).Path("/{uploadID}").HandlerFunc(handleGetUploadedParts)
|
s3Router.Methods(http.MethodGet).Path("/{uploadID}").HandlerFunc(handleGetUploadedParts)
|
||||||
s3Router.Methods(http.MethodGet).Path("/{uploadID}/{uploadPart}").HandlerFunc(handleSignPartUpload)
|
s3Router.Methods(http.MethodGet).Path("/{uploadID}/{uploadPart}").HandlerFunc(handleSignPartUpload)
|
||||||
|
@ -42,6 +49,7 @@ func main() {
|
||||||
ReadTimeout: 5 * time.Second,
|
ReadTimeout: 5 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
}
|
}
|
||||||
|
log.Printf("listeining on %s", listen)
|
||||||
err = server.ListenAndServe()
|
err = server.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
26
s3.go
26
s3.go
|
@ -52,32 +52,6 @@ func stripETag(t string) string {
|
||||||
return strings.TrimSuffix(strings.TrimPrefix(t, "\""), "\"")
|
return strings.TrimSuffix(strings.TrimPrefix(t, "\""), "\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
/* types */
|
|
||||||
|
|
||||||
type credential struct {
|
|
||||||
AccessKey string
|
|
||||||
SecretKey string
|
|
||||||
// Region is critical when signing requests.
|
|
||||||
Region string
|
|
||||||
// Endpoint is the base URL of the bucket, including the bucket name (in either the domain or path).
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// https://bucketname.s3.us-west-2.amazonaws.com
|
|
||||||
// http://my-minio.example.com/bucket-name
|
|
||||||
Endpoint string
|
|
||||||
// ACL is an optional canned ACL to set on objects
|
|
||||||
ACL string
|
|
||||||
// Prefix is a string to prepend to object keys
|
|
||||||
Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cred credential) validate() error {
|
|
||||||
if strings.HasSuffix(cred.Endpoint, "/") {
|
|
||||||
return fmt.Errorf("%w: endpoint should not end with slash", errBadRequest)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initiateMultipartUpload */
|
/* initiateMultipartUpload */
|
||||||
|
|
||||||
type initiateMultipartUploadResult struct {
|
type initiateMultipartUploadResult struct {
|
||||||
|
|
12
store.go
12
store.go
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
var errKeyCollision = errors.New("key collision")
|
var errKeyCollision = errors.New("key collision")
|
||||||
var errKeyNotFound = fmt.Errorf("key %w", errNotFound)
|
var errKeyNotFound = fmt.Errorf("key %w", errNotFound)
|
||||||
|
var errInvalidConnectionType = errors.New("invalid connection type")
|
||||||
|
|
||||||
type store interface {
|
type store interface {
|
||||||
put(key string, data []byte, expire time.Duration) error
|
put(key string, data []byte, expire time.Duration) error
|
||||||
|
@ -38,15 +39,14 @@ func newRedisStore(connection string) (*redisStore, error) {
|
||||||
var err error
|
var err error
|
||||||
if rtype == "simple" {
|
if rtype == "simple" {
|
||||||
client, err = (radix.PoolConfig{}).New(ctx, "tcp", connectionParts[1])
|
client, err = (radix.PoolConfig{}).New(ctx, "tcp", connectionParts[1])
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
} else if rtype == "cluster" {
|
} else if rtype == "cluster" {
|
||||||
clusterAddrs := strings.Split(connectionParts[1], ",")
|
clusterAddrs := strings.Split(connectionParts[1], ",")
|
||||||
client, err = (radix.ClusterConfig{}).New(ctx, clusterAddrs)
|
client, err = (radix.ClusterConfig{}).New(ctx, clusterAddrs)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("%w: %#v of string %#v", errInvalidConnectionType, rtype, connection)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, fmt.Errorf("unable to initialize redis store: %w", err)
|
||||||
}
|
}
|
||||||
return &redisStore{client}, nil
|
return &redisStore{client}, nil
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func (s *redisStore) put(key string, data []byte, expire time.Duration) error {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
exists := 0
|
exists := 0
|
||||||
err := s.client.Do(ctx, radix.Cmd(&exists, "EXISTS", key))
|
err := s.client.Do(ctx, radix.Cmd(&exists, "EXISTS", "upl:"+key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ func (s *redisStore) get(key string) ([]byte, error) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var data []byte
|
var data []byte
|
||||||
err := s.client.Do(ctx, radix.Cmd(&data, "GET", key))
|
err := s.client.Do(ctx, radix.Cmd(&data, "GET", "upl:"+key))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,8 @@ import filesize from 'filesize';
|
||||||
import './log.css';
|
import './log.css';
|
||||||
|
|
||||||
class Log {
|
class Log {
|
||||||
constructor(selector) {
|
constructor(selector, key) {
|
||||||
|
this.key = key;
|
||||||
this.target = document.querySelector(selector);
|
this.target = document.querySelector(selector);
|
||||||
this.items = [];
|
this.items = [];
|
||||||
|
|
||||||
|
@ -12,12 +13,12 @@ class Log {
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorageLoad() {
|
localStorageLoad() {
|
||||||
const loaded = JSON.parse(window.localStorage.getItem("log") || "[]");
|
const loaded = JSON.parse(window.localStorage.getItem("log" + this.key) || "[]");
|
||||||
this.items.push(...loaded);
|
this.items.push(...loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorageSave() {
|
localStorageSave() {
|
||||||
window.localStorage.setItem("log", JSON.stringify(this.items));
|
window.localStorage.setItem("log" + this.key, JSON.stringify(this.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
static renderItem(item) {
|
static renderItem(item) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ uppy.use(AwsS3Multipart, {
|
||||||
companionUrl: window.location.pathname,
|
companionUrl: window.location.pathname,
|
||||||
});
|
});
|
||||||
|
|
||||||
const log = new Log('#log-area');
|
const log = new Log('#log-area', window.location.pathname);
|
||||||
|
|
||||||
uppy.on('upload-success', (f, res) => {
|
uppy.on('upload-success', (f, res) => {
|
||||||
log.add({
|
log.add({
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dropbox Not Found</title>
|
||||||
|
<link rel="stylesheet" href="assets/bundle.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="upload-wrapper">
|
||||||
|
<div class="upload">
|
||||||
|
<h1>Dropbox Not Found</h1>
|
||||||
|
<p>The dropbox you are looking for doesn't exist or has expired.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
Loading…
Reference in New Issue