Skip to content

WebUI: add ZIP upload with extract/keep dialog - #2935

Closed
Ninja-jr wants to merge 7 commits into
BruceDevices:devfrom
Ninja-jr:Webui_zip
Closed

Ninja-jr wants to merge 7 commits into
BruceDevices:devfrom
Ninja-jr:Webui_zip

Conversation

@Ninja-jr

@Ninja-jr Ninja-jr commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Adds a proper ZIP workflow to the WebUI file browser. Previously, uploading a .zip just wrote the archive as a regular file into the current folder — no extraction, no handling of the archive as a package. The new flow detects .zip uploads, stages them in a temp folder, and offers the user a choice: extract here, extract to a chosen folder, or just keep the file.

What's new

· ZIP detection on upload. When the uploaded file's name ends in .zip, the backend writes it to /.bruce_tmp/ (SD if available, LittleFS otherwise) instead of the current folder. This keeps the archive out of the user's way and makes the "keep the file" case a clean move rather than a re-upload.
· State endpoint. A new GET /upload_state reports whether the most recent upload was a ZIP and, if so, where it landed. The frontend queries this after each successful upload instead of relying on the multipart response body — that response goes through the AsyncWebServer's request pipeline and isn't reliable for structured data.
· Dialog with three actions. After a ZIP upload, the user sees a dialog offering:
· Extract here — extracts into the current folder
· Extract to… — opens a folder picker to choose a destination
· Just keep the file — moves the ZIP from temp to the current folder without extracting
· Extraction via miniz. Uses miniz-esp32 (added to lib_deps). Entry names are sanitized before writing (rejects .., strips leading /, rejects :), so an archive can't escape the target folder.
· Stack-safe extraction. extractZipTo tries the fast path first (mz_zip_reader_init_file), then falls back to loading the archive into a heap buffer if the path can't be resolved through miniz's own file layer. The archive-size cap on the fallback (ZIP_MEM_FALLBACK_LIMIT = 2 MB) prevents OOM on oversized zips. Structs are hoisted out of the extraction loop to keep the WebUI task stack bounded, and a vTaskDelay between entries feeds the RTOS watchdog.
· Serialization guard. A single g_longOpInProgress flag ensures only one long operation (extract or zip upload) runs at a time. Two concurrent requests would otherwise corrupt shared miniz globals or the FS handles.
· Frontend concurrency. _zipBusy prevents double-clicks; all zip dialog buttons are disabled during a request; and a short delay after the response before follow-up requests gives the device time to finish cleanup.

Files changed

· src/core/wifi/webInterface.cpp
· New handleUpload logic for .zip detection, temp staging, and original-name preservation
· New GET /upload_state endpoint
· New POST /extract endpoint (extract or move-only), guarded by g_longOpInProgress
· New extractZipTo() helper
· src/core/wifi/webInterface.h — declares extractZipTo()
· embedded_resources/web_interface/index.html — new .dialog.zip-extract block
· embedded_resources/web_interface/index.js — zip flow (dialog handlers, _zipBusy guard, uploadFile state query, _finishZipFlow)
· platformio.ini — miniz-esp32 added to lib_deps; CONFIG_ASYNC_TCP_STACK_SIZE raised from 4096 to 20480 to accommodate the extraction path

Types of Changes

· New feature (zip install workflow)
· Bugfix (frontend can now safely serialize long operations)

Verification

Built and tested on Cardputer Adv (SD card). Manually verified:

· Upload a .zip → dialog appears with three options
· Extract here → archive contents land in the current folder, count matches
· Extract to… → folder picker shows current path and subfolders; selected folder receives the files
· Just keep the file → the .zip moves from /.bruce_tmp/ to the current folder with its original name
· Cancel (dialog X or ESC) → archive remains in temp, cleaned up on next WebUI restart
· Concurrent requests (double-click, or upload while extracting) → refused with 409, no crash
· Non-zip uploads → unchanged behaviour

User-Facing Change

Uploading a .zip through the WebUI now presents a choice of extraction or keeping the file, rather than dropping the archive into the current folder. Existing file browser behaviour for non-zip uploads is unchanged.

Notes

· miniz-esp32 is used (ROM's rom/miniz.h isn't exposed in Bruce's build). Pinned via lib_deps.
· Small archives extract via the fast path with no extra RAM; the heap-buffer fallback exists for filesystem-setup variations where miniz's internal file layer can't see the same mounts as the Arduino FS object.
· ZIP_MEM_FALLBACK_LIMIT can be raised on PSRAM-equipped boards if larger archives need to be handled.
· Anything left over on the /.bruce_tmp/ folder is cleaned at the next WebUI startup.

Implement zip extraction dialog and functionality.
Added ZIP extraction support and improved upload handling.
Added ZIP extraction support function to web interface.
…rmio.ini

Increased CONFIG_ASYNC_TCP_STACK_SIZE from 4096 to 20480 to allocate more memory for Async TCP and add miniz to lib deps.
Added Miniz buffer flags for configuration.
@Ninja-jr
Ninja-jr marked this pull request as draft October 1, 2026 07:58
@Ninja-jr Ninja-jr closed this Oct 1, 2026
@Ninja-jr
Ninja-jr deleted the Webui_zip branch October 1, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant