Skip to content

Commit 7063657

Browse files
committed
add POC
1 parent 8d715dc commit 7063657

File tree

2 files changed

+115
-10
lines changed

2 files changed

+115
-10
lines changed

packages/react-storage/src/components/StorageBrowser/actions/handlers/download.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ function downloadFromUrl(fileName: string, url: string) {
3939
}
4040

4141
export const downloadHandler: DownloadHandler = ({
42-
config,
43-
data: { key },
42+
config,
43+
data: { key },
4444
}): DownloadHandlerOutput => {
4545
const { accountId, credentials, customEndpoint } = config;
4646

@@ -55,14 +55,14 @@ export const downloadHandler: DownloadHandler = ({
5555
expectedBucketOwner: accountId,
5656
},
5757
})
58-
.then(({ url }) => {
59-
downloadFromUrl(key, url.toString());
60-
return { status: 'COMPLETE' as const, value: { url } };
61-
})
62-
.catch((error: Error) => {
63-
const { message } = error;
64-
return { error, message, status: 'FAILED' as const };
65-
});
58+
.then(({ url }) => {
59+
downloadFromUrl(key, url.toString());
60+
return { status: 'COMPLETE' as const, value: { url } };
61+
})
62+
.catch((error: Error) => {
63+
const { message } = error;
64+
return { error, message, status: 'FAILED' as const };
65+
});
6666

6767
return { result };
6868
};
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import {
2+
DownloadHandlerInput,
3+
DownloadHandlerOutput,
4+
} from "@aws-amplify/ui-react-storage/browser";
5+
import { getUrl } from "@aws-amplify/storage/internals";
6+
import {
7+
ZipWriterAddDataOptions,
8+
ZipWriter,
9+
BlobWriter,
10+
BlobReader,
11+
} from "@zip.js/zip.js";
12+
13+
const model = (() => {
14+
let zipWriter: ZipWriter<Blob> | null;
15+
return {
16+
addFile(file: Blob, name: string, options: ZipWriterAddDataOptions) {
17+
if (!zipWriter) {
18+
zipWriter = new ZipWriter(new BlobWriter("application/zip"), {
19+
bufferedWrite: true,
20+
});
21+
}
22+
return zipWriter.add(name, new BlobReader(file), options);
23+
},
24+
async getBlobURL() {
25+
if (zipWriter) {
26+
const blobURL = URL.createObjectURL(await zipWriter.close());
27+
zipWriter = null;
28+
return blobURL;
29+
} else {
30+
throw new Error("Zip file closed");
31+
}
32+
},
33+
};
34+
})();
35+
36+
const constructBucket = ({
37+
bucket: bucketName,
38+
region,
39+
}: DownloadHandlerInput["config"]) => ({ bucketName, region });
40+
41+
const download = async ({ config, data: { key } }: DownloadHandlerInput) => {
42+
const { customEndpoint, credentials, accountId } = config;
43+
const { url } = await getUrl({
44+
path: key,
45+
options: {
46+
bucket: constructBucket(config),
47+
customEndpoint,
48+
locationCredentialsProvider: credentials,
49+
validateObjectExistence: true,
50+
contentDisposition: "attachment",
51+
expectedBucketOwner: accountId,
52+
},
53+
});
54+
const response = await fetch(url, { mode: "cors" });
55+
const blob = await response.blob();
56+
const [filename] = key.split("/").reverse();
57+
await model.addFile(blob, filename, {});
58+
};
59+
60+
const customDownloadHandler = (() => {
61+
const q = new Set<string>();
62+
let timer: ReturnType<typeof setTimeout>;
63+
return (input: DownloadHandlerInput): DownloadHandlerOutput => {
64+
const {
65+
data: { key },
66+
} = input;
67+
const [, folder] = key.split("/").reverse();
68+
q.add(key);
69+
const result = download(input)
70+
.then(() => {
71+
q.delete(key);
72+
return {
73+
status: "COMPLETE",
74+
};
75+
})
76+
.catch((e) => {
77+
const error = e as Error;
78+
q.delete(key);
79+
return {
80+
status: "FAILED",
81+
message: error.message,
82+
error,
83+
};
84+
})
85+
.finally(() => {
86+
if (timer) clearTimeout(timer);
87+
timer = setTimeout(() => {
88+
if (q.size === 0) {
89+
model.getBlobURL().then((blobURL) => {
90+
if (blobURL) {
91+
const anchor = document.createElement("a");
92+
const clickEvent = new MouseEvent("click");
93+
anchor.href = blobURL;
94+
anchor.download = `${folder || "archive"}.zip`;
95+
anchor.dispatchEvent(clickEvent);
96+
}
97+
});
98+
}
99+
}, 250);
100+
});
101+
return { result: result as DownloadHandlerOutput["result"] };
102+
};
103+
})();
104+
105+
export { customDownloadHandler };

0 commit comments

Comments
 (0)