feat(content): file uploads with public links #94
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/operator-file-uploads"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
- Added Ability to store a file and hand out a URL anyone can open, over an agent's own bucket credentials. - Added Interface `content_blob`: `Blob`, `NatsBlob`, the object metadata encoding and the byte ceiling. - Added Redundancy-free split: the blob layer sits in the SDK because uploader and server are separate processes that must agree on the metadata keys; naming and quota policy stay with the side that owns storage. - Added Interface `POST /api/content`, spooling the body to a temporary file while hashing it — the digest names the object, so it must be known before the store is written, and a video cannot be hashed in memory. - Added Ability to refuse an oversize upload while the body streams, because reading a whole body to discover it was too large is the denial of service the cap exists to prevent. - Added Ability to sniff the media type from the file's own bytes against an allowlist: the stored type is echoed back as `Content-Type` publicly, so an unrecognised one is refused rather than guessed at. - Added Interface 507 with `used_bytes` and `quota_bytes` on a full bucket, which a caller can act on, rather than a 500 carrying a string it cannot. - Added Interface `GET /api/content/{digest}` with `Range`, streaming its windows so a whole-object read never assembles the file in memory. - Added Interface `DELETE /api/content/{digest}` and `GET /api/content/usage`. - Added Function `NatsNsedWorker::jetstream`, so a caller holding a worker opens buckets on that connection instead of dialling a second one. - Improved Ability to answer 503 rather than 404 where `NSED_FILES_BUCKET` is unset, so a misconfigured deployment is distinguishable from a file that was never there.- Added Ability to segment an uploaded video into HLS in the background, storing each segment as its own content-addressed object and a playlist that points at their public URLs. - Fixed Performance problem this exists for: the object store has no server-side range read, so a viewer scrubbing one large file re-reads it from the start on every drag. Segments are small whole-object reads. - Added Interface `GET /api/content/{digest}/status` — the uploader's poll, since a transcode outlives the request that started it. Reports `pending`/`ready`/`failed`/`skipped` plus the playlist URL. - Added Ability to refuse a playlist that names a piece which was not stored: playback failing halfway through is worse than never producing one. - Added Ability to remove everything already stored when a step fails, because a half-stored segmentation costs the operator quota and nothing references it. - Added Redundancy: streams are copied rather than re-encoded, since most uploads are already H.264/AAC. - Added Ability to report `skipped` and keep the original where the host has no ffmpeg — a library user who never asked for a media pipeline gets no failure. - Added Function `Blob::annotate` / `Blob::notes`, recording a pipeline's result against a stored object. - Fixed Bug where annotations went through `update_metadata`, which in async-nats 0.47 writes back only name and description and drops the map. A sidecar object holds them now, off the serving path. - Fixed Bug where concurrent annotations on one digest could lose each other; two uploads of identical bytes share a digest, so that was reachable. - Fixed Bug where a hung ffmpeg held the only transcode slot forever. Killed after 30 minutes, with stderr drained concurrently so a full pipe is not mistaken for a hang. - Fixed Bug where queued uploads each held a spool on disk without bound. At most four wait; past that an upload is stored whole and reported skipped. - Fixed Bug where a playlist URL was offered for a segmentation that had since failed, which fails in the player rather than at the API.feat/operator-file-uploadsto feat(content): file uploads with public links- BREAKING CHANGE Interface: `visibility` is a required part of an upload. Absent, it was silently public — publishing a file whose uploader may have meant otherwise, invisibly, until the link was out. - Fixed Bug where a private upload was segmented into public HLS pieces. Segments are the video, so they inherit the source's visibility and a non-public upload is never queued. - Fixed Bug where a non-`file` multipart part was buffered whole with no ceiling. The route disables the request-level limit so a video can through, so one huge form field could exhaust the process. - Fixed Bug where the cursor-pool guard was held across the broker round trip and the offset skip: a match scrutinee's temporaries outlive the arm, so one reader's seek serialised every read in the bucket. - Fixed Bug where `{digest}` reached the store unvalidated, letting a caller read and delete other objects' annotation sidecars through the reserved prefix. - Fixed Bug where a spool flush error was discarded, storing a short file under the whole file's digest — the one invariant content addressing rests on. - Added Ability to refuse ffmpeg any protocol but `file`, so an uploaded container's external references cannot be muxed into published segments. - Fixed Bug where a cancelled transcode left ffmpeg orphaned, and where probing a wedged binary hung agent startup without bound. - Fixed Bug where an uploader's filename was stored unsanitised for another process to place in a header. - Fixed Bug where test buckets accumulated 29 per run against JetStream's reserved storage. Names derive from the test and are recreated, so the count is bounded and a panic cannot skip teardown. - Fixed Redundancy in three vacuous tests, and gated the real-ffmpeg case behind REQUIRE_FFMPEG as the broker cases are behind REQUIRE_NATS. - Removed Interface churn: `run_control_plane` keeps its nine-argument form, with uploads behind `run_control_plane_with_uploads`.