You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add object download and preview for Ceph object storage, bringing Ceph to parity with the existing Swift capability.
6
+
7
+
- Stream downloads through the BFF (`downloadObject`) with live progress tracking via `watchDownloadProgress`. Multiple downloads/previews can be in flight at once, each tracked and reported independently.
8
+
- Row-click on an object previews it in a new browser tab when the type is safely renderable (images excluding SVG, video, audio, PDF, and plain text); everything else downloads directly. Scriptable types (HTML, JSON, XML, SVG) are intentionally excluded from preview since they can execute active content when opened from a blob URL.
9
+
- New context-menu **Download** action always forces a file save, regardless of type.
10
+
- The BFF resolves a reliable MIME type from the object key extension when S3/Ceph reports a generic or incorrect `Content-Type` (e.g. the `binary/octet-stream` default, or values set by some upload tools), so files preview correctly even without proper upload metadata.
Downloads an object by streaming its content through the BFF as base64-encoded chunks via a tRPC async iterable (S3 `GetObjectCommand`). The server never buffers the whole object in memory, and per-chunk progress is published so a concurrent `watchDownloadProgress` subscription can drive a progress bar. This is a **direct stream** — no presigned/temporary URLs are issued.
862
+
863
+
**Input:**
864
+
865
+
```typescript
866
+
{
867
+
project_id: string,
868
+
containerName: string,
869
+
objectKey: string,
870
+
filename: string, // Suggested download filename (echoed in the first chunk)
// → wrap in an object URL and trigger an <a download>
909
+
```
910
+
911
+
**Notes:**
912
+
913
+
- Each chunk is base64-encoded because tRPC's iterable transport is JSON/SSE-based and yielded values must be JSON-serializable.
914
+
- `contentType` and `filename` are sent only in the first chunk to avoid repetition.
915
+
- Progress is scoped by `project_id`, so a user can never observe another tenant's transfer.
916
+
- An empty object yields no chunks (the loop simply never runs).
917
+
918
+
**Content-Type resolution:**
919
+
920
+
S3/Ceph often can't be trusted to report a useful `Content-Type` — RGW defaults to `binary/octet-stream` when none was set on upload, and some upload tools store an unrelated type (e.g. `application/x-www-form-urlencoded`). Since the raw stored value directly determines whether the frontend can preview a file inline vs. must force a download, `downloadObject` resolves the type as follows before yielding the first chunk:
921
+
922
+
1. If the object key has a recognized extension (`.jpg`, `.pdf`, `.txt`, `.png`, etc.), the MIME type is derived from that extension and takes priority over whatever S3 returned.
923
+
2. Otherwise (unknown or missing extension — e.g. a UUID-style key), the `ContentType` from the S3 `GetObjectCommand` response is used as-is, falling back to `application/octet-stream` if absent.
924
+
925
+
This means the `contentType` yielded in the first chunk may differ from the object's stored `Content-Type` in S3. Consumers that need the _raw_ stored value (rather than the resolved/display value) should call `getDetails` instead, which returns the S3 metadata unmodified.
926
+
927
+
The Ceph frontend (`ObjectsTableView`) uses this resolved `contentType` to decide row-click behavior: safe browser-previewable types (passive media `image/*` excluding `image/svg+xml`, `video/*`, `audio/*`, plus `application/pdf` and `text/plain`) open in a new tab; everything else downloads. The context-menu **Download** action always forces a download regardless of type.
928
+
929
+
---
930
+
931
+
#### `watchDownloadProgress`
932
+
933
+
Subscribes to live progress for an in-flight download identified by `downloadId`. Open this **before** calling `downloadObject` so no early events are missed; a snapshot of current progress is emitted immediately for late subscribers.
934
+
935
+
**Input:**
936
+
937
+
```typescript
938
+
{
939
+
project_id: string,
940
+
downloadId: string // Same id passed to downloadObject
941
+
}
942
+
```
943
+
944
+
**Output:** an async iterable (subscription) yielding progress:
945
+
946
+
```typescript
947
+
{
948
+
downloaded: number, // cumulative bytes streamed
949
+
total: number, // total object size in bytes (0 if unknown)
950
+
percent: number // 0–100 (0 when total is unknown)
@@ -1564,8 +1687,8 @@ Both can coexist — Ceph RGW supports **both Swift and S3 APIs** on the same cl
1564
1687
1565
1688
2. **Object Upload/Download**
1566
1689
- Upload object (`PutObjectCommand`)
1567
-
- Download object (`GetObjectCommand`)
1568
-
- Streaming upload/download via tRPC (similar to Swift BFF `uploadObject`/`downloadObject`)
1690
+
- ~~Download object (`GetObjectCommand`)~~ ✅ Implemented — streamed through the BFF as a tRPC async iterable, with a `watchDownloadProgress` subscription for progress
1691
+
- Streaming upload via tRPC (similar to Swift BFF `uploadObject`)
1569
1692
- Multipart uploads for large files
1570
1693
1571
1694
3. **Object Manipulation**
@@ -1790,7 +1913,7 @@ openstack endpoint list --service ceph
Copy file name to clipboardExpand all lines: packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectBrowserView.tsx
Copy file name to clipboardExpand all lines: packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.test.tsx
Copy file name to clipboardExpand all lines: packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Objects/ObjectToastNotifications.tsx
0 commit comments