Skip to content

Commit 1889bdf

Browse files
authored
Merge pull request #2967 from appwrite/multiple-file-bucket
feat: support multiple file uploads in bucket
2 parents 1b2598a + a9187aa commit 1889bdf

File tree

3 files changed

+383
-202
lines changed

3 files changed

+383
-202
lines changed

src/lib/stores/uploader.ts

Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const temporaryFunctions = (region: string, projectId: string) => {
3939
return new Functions(clientProject);
4040
};
4141

42+
const MAX_CONCURRENT_UPLOADS = 5;
43+
4244
const createUploader = () => {
4345
const { subscribe, set, update } = writable<Uploader>({
4446
isOpen: false,
@@ -58,6 +60,85 @@ const createUploader = () => {
5860
});
5961
};
6062

63+
const uploadFile = async (
64+
region: string,
65+
projectId: string,
66+
bucketId: string,
67+
id: string,
68+
file: File,
69+
permissions: string[]
70+
) => {
71+
const newFile: UploaderFile = {
72+
$id: id,
73+
resourceId: bucketId,
74+
name: file.name,
75+
size: file.size,
76+
progress: 0,
77+
status: 'pending'
78+
};
79+
update((n) => {
80+
n.isOpen = true;
81+
n.isCollapsed = false;
82+
n.files.unshift(newFile);
83+
return n;
84+
});
85+
try {
86+
const uploadedFile = await temporaryStorage(region, projectId).createFile({
87+
bucketId,
88+
fileId: id ?? ID.unique(),
89+
file,
90+
permissions,
91+
onProgress: (progress) => {
92+
newFile.$id = progress.$id;
93+
newFile.progress = progress.progress;
94+
newFile.status = progress.progress === 100 ? 'success' : 'pending';
95+
updateFile(progress.$id, newFile);
96+
}
97+
});
98+
newFile.$id = uploadedFile.$id;
99+
newFile.progress = 100;
100+
newFile.status = 'success';
101+
updateFile(newFile.$id, newFile);
102+
} catch (e) {
103+
newFile.status = 'failed';
104+
newFile.error = e?.message ?? 'Upload failed';
105+
updateFile(newFile.$id, newFile);
106+
throw e;
107+
}
108+
};
109+
110+
const uploadFiles = async (
111+
region: string,
112+
projectId: string,
113+
bucketId: string,
114+
files: { id: string; file: File }[],
115+
permissions: string[]
116+
) => {
117+
const results: PromiseSettledResult<void>[] = [];
118+
const executing = new Set<Promise<void>>();
119+
120+
for (const { id, file } of files) {
121+
const task = uploadFile(region, projectId, bucketId, id, file, permissions).then(
122+
() => {
123+
results.push({ status: 'fulfilled', value: undefined });
124+
executing.delete(task);
125+
},
126+
(reason) => {
127+
results.push({ status: 'rejected', reason });
128+
executing.delete(task);
129+
}
130+
);
131+
executing.add(task);
132+
133+
if (executing.size >= MAX_CONCURRENT_UPLOADS) {
134+
await Promise.race(executing);
135+
}
136+
}
137+
138+
await Promise.all(executing);
139+
return results;
140+
};
141+
61142
return {
62143
subscribe,
63144

@@ -78,45 +159,8 @@ const createUploader = () => {
78159
isCollapsed: false,
79160
files: []
80161
}),
81-
uploadFile: async (
82-
region: string,
83-
projectId: string,
84-
bucketId: string,
85-
id: string,
86-
file: File,
87-
permissions: string[]
88-
) => {
89-
const newFile: UploaderFile = {
90-
$id: id,
91-
resourceId: bucketId,
92-
name: file.name,
93-
size: file.size,
94-
progress: 0,
95-
status: 'pending'
96-
};
97-
update((n) => {
98-
n.isOpen = true;
99-
n.isCollapsed = false;
100-
n.files.unshift(newFile);
101-
return n;
102-
});
103-
const uploadedFile = await temporaryStorage(region, projectId).createFile({
104-
bucketId,
105-
fileId: id ?? ID.unique(),
106-
file,
107-
permissions,
108-
onProgress: (progress) => {
109-
newFile.$id = progress.$id;
110-
newFile.progress = progress.progress;
111-
newFile.status = progress.progress === 100 ? 'success' : 'pending';
112-
updateFile(progress.$id, newFile);
113-
}
114-
});
115-
newFile.$id = uploadedFile.$id;
116-
newFile.progress = 100;
117-
newFile.status = 'success';
118-
updateFile(newFile.$id, newFile);
119-
},
162+
uploadFile,
163+
uploadFiles,
120164
uploadSiteDeployment: async ({
121165
siteId,
122166
code,

0 commit comments

Comments
 (0)