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) } }