package handlers import ( "sync" "time" ) // uploadGroupWindow is how long after a batched upload a follow-up upload with // the same X-Warpbox-Batch value (and same account/IP) is folded into the same // box. ShareX sends a multi-file selection as separate back-to-back requests; // the batch header lets it land them in one box. const uploadGroupWindow = 20 * time.Second // uploadBatchHeader is the opt-in request header. Without it, uploads behave // exactly as before (one box per request). With it, requests sharing the same // value (per account/IP) within uploadGroupWindow are grouped into one box. const uploadBatchHeader = "X-Warpbox-Batch" // uploadGrouper tracks the most recent box per batch key so opt-in batched // uploads land in a single box. Each key has its own lock, which also serialises // that key's concurrent uploads so they append to the same box instead of racing // to create several. type uploadGrouper struct { mu sync.Mutex entries map[string]*uploadGroupEntry } type uploadGroupEntry struct { mu sync.Mutex boxID string manageURL string deleteURL string at time.Time } func newUploadGrouper() *uploadGrouper { return &uploadGrouper{entries: make(map[string]*uploadGroupEntry)} } func (g *uploadGrouper) entryFor(key string) *uploadGroupEntry { g.mu.Lock() defer g.mu.Unlock() entry, ok := g.entries[key] if !ok { entry = &uploadGroupEntry{} g.entries[key] = entry } return entry }