243 lines
4.9 KiB
Go
243 lines
4.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Admin struct {
|
|
name string
|
|
}
|
|
|
|
type UploadState int
|
|
|
|
const (
|
|
inactive UploadState = iota
|
|
active
|
|
completed
|
|
full
|
|
)
|
|
|
|
type UploadFile struct {
|
|
created time.Time
|
|
state UploadState
|
|
finalName string
|
|
}
|
|
|
|
type UploadContext struct {
|
|
maxSize int64
|
|
created time.Time
|
|
lifetime time.Duration
|
|
}
|
|
|
|
type UploadDatabase struct {
|
|
data map[uuid.UUID]*UploadContext
|
|
mtx sync.Mutex
|
|
}
|
|
|
|
var db UploadDatabase
|
|
|
|
func (d *UploadDatabase) commit(size int64, lifefile time.Duration) uuid.UUID {
|
|
id := uuid.New()
|
|
d.mtx.Lock()
|
|
defer d.mtx.Unlock()
|
|
|
|
_, found := d.data[id]
|
|
|
|
if found {
|
|
return uuid.Max
|
|
}
|
|
|
|
ctx := new(UploadContext)
|
|
d.data[id] = ctx
|
|
|
|
ctx.created = time.Now()
|
|
ctx.lifetime = lifefile
|
|
ctx.maxSize = size
|
|
|
|
return id
|
|
}
|
|
|
|
func (d *UploadDatabase) exists(id uuid.UUID) bool {
|
|
d.mtx.Lock()
|
|
defer d.mtx.Unlock()
|
|
_, found := d.data[id]
|
|
return found
|
|
}
|
|
|
|
func (d *UploadDatabase) getSize(id uuid.UUID) int64 {
|
|
d.mtx.Lock()
|
|
defer d.mtx.Unlock()
|
|
return d.data[id].maxSize
|
|
}
|
|
|
|
func initialize() {
|
|
db.data = make(map[uuid.UUID]*UploadContext)
|
|
}
|
|
|
|
func adminHandler(w http.ResponseWriter, r *http.Request) {
|
|
http.ServeFile(w, r, "./html/admin.html")
|
|
}
|
|
|
|
func generateHandler(w http.ResponseWriter, r *http.Request) {
|
|
var maxSizeBytes int64
|
|
var linkLifetime int64
|
|
var id uuid.UUID
|
|
var uploadLink string
|
|
|
|
if r.Method != "POST" {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
var linkSettings struct {
|
|
Lifetime string `json:"lifetime"`
|
|
MaxSize string `json:"maxSize"`
|
|
SizeUnit string `json:"sizeUnit"`
|
|
}
|
|
err := json.NewDecoder(r.Body).Decode(&linkSettings)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Invalid input: %v", err), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
linkLifetime, err = strconv.ParseInt(linkSettings.Lifetime, 10, 64)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Invalid input: %v", err), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
maxSizeBytes, err = strconv.ParseInt(linkSettings.MaxSize, 10, 64)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Invalid input: %v", err), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if linkSettings.SizeUnit == "GB" {
|
|
maxSizeBytes *= 1024 * 1024 * 1024
|
|
} else if linkSettings.SizeUnit == "MB" {
|
|
maxSizeBytes *= 1024 * 1024
|
|
} else {
|
|
http.Error(w, fmt.Sprintf("Invalid input: %v", err), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
id = db.commit(maxSizeBytes, time.Duration(linkLifetime))
|
|
if id == uuid.Max {
|
|
http.Error(w, "Commit failed", http.StatusBadRequest)
|
|
return
|
|
}
|
|
uploadLink = fmt.Sprintf("http://localhost:8080/upload?key=%s", id)
|
|
|
|
response := map[string]string{"uploadLink": uploadLink}
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
}
|
|
|
|
func uploadHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != "GET" {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
id, err := uuid.Parse(r.URL.Query().Get("key"))
|
|
if err != nil || !db.exists(id) {
|
|
http.ServeFile(w, r, "./html/user_bad.html")
|
|
return
|
|
}
|
|
|
|
if !r.URL.Query().Has("limit") {
|
|
q := r.URL.Query()
|
|
q.Set("limit", strconv.FormatInt(db.getSize(id), 10))
|
|
r.URL.RawQuery = q.Encode()
|
|
http.Redirect(w, r, r.URL.String(), http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
http.ServeFile(w, r, "./html/user.html")
|
|
}
|
|
|
|
func fileHandler(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != "POST" {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
id, err := uuid.Parse(r.URL.Query().Get("key"))
|
|
if err != nil || !db.exists(id) {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// ctx := db.activate(id)
|
|
// defer db.deactivate(id)
|
|
// if ctx == nil {
|
|
// w.WriteHeader(http.StatusBadRequest)
|
|
// return
|
|
// }
|
|
|
|
// parse form
|
|
err = r.ParseMultipartForm(10 << 20) // 10MB memory cache
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Retrieve the file from form
|
|
file, handler, err := r.FormFile("file")
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
// Create a new file in the uploads directory
|
|
dst, err := os.Create(filepath.Join("uploads", handler.Filename))
|
|
if err != nil {
|
|
fmt.Fprintf(w, "Error creating file: %v", err)
|
|
return
|
|
}
|
|
defer dst.Close()
|
|
|
|
// Copy the uploaded file to the new file
|
|
_, err = io.Copy(dst, file)
|
|
if err != nil {
|
|
fmt.Fprintf(w, "Error saving file: %v", err)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusAccepted)
|
|
}
|
|
|
|
func main() {
|
|
initialize()
|
|
|
|
os.MkdirAll("uploads", os.ModePerm)
|
|
|
|
http.HandleFunc("/admin", adminHandler)
|
|
http.HandleFunc("/generate", generateHandler)
|
|
http.HandleFunc("/upload", uploadHandler)
|
|
http.HandleFunc("/file", fileHandler)
|
|
|
|
// http.Handle("/", http.FileServer(http.Dir(".")))
|
|
|
|
// Start the server
|
|
fmt.Println("Starting server on :8080")
|
|
err := http.ListenAndServe(":8080", nil)
|
|
if err != nil {
|
|
fmt.Printf("Error starting server: %v", err)
|
|
}
|
|
}
|