(readable: stream.Readable, tus_id: string, offset: number)
| 143 | } |
| 144 | |
| 145 | public override async write(readable: stream.Readable, tus_id: string, offset: number): Promise<number> { |
| 146 | const logger = useLogger(); |
| 147 | const fileData = await this.getFileById(tus_id); |
| 148 | const filePath = fileData.filename_disk!; |
| 149 | |
| 150 | const sudoFilesItemsService = new ItemsService<File>('directus_files', { |
| 151 | schema: this.schema, |
| 152 | }); |
| 153 | |
| 154 | try { |
| 155 | const newOffset = await this.storageDriver.writeChunk( |
| 156 | filePath, |
| 157 | readable, |
| 158 | offset, |
| 159 | fileData.tus_data as ChunkedUploadContext, |
| 160 | ); |
| 161 | |
| 162 | await sudoFilesItemsService.updateOne(fileData.id!, { |
| 163 | tus_data: { |
| 164 | ...fileData.tus_data, |
| 165 | offset: newOffset, |
| 166 | }, |
| 167 | }); |
| 168 | |
| 169 | if (Number(fileData.filesize) === newOffset) { |
| 170 | try { |
| 171 | await this.storageDriver.finishChunkedUpload(filePath, fileData.tus_data as ChunkedUploadContext); |
| 172 | } catch (err) { |
| 173 | await this.remove(fileData.tus_id!); |
| 174 | throw err; |
| 175 | } |
| 176 | |
| 177 | const targetId = fileData.tus_data?.['metadata']?.['id'] as string | undefined; |
| 178 | const isReplacement = targetId && targetId !== fileData.id; |
| 179 | |
| 180 | // If the file is a replacement, delete the old files, and upgrade the temp file. DB record will be cleanup on in onUploadFinish handler |
| 181 | if (isReplacement) { |
| 182 | const replaceData = await sudoFilesItemsService.readOne(targetId, { fields: ['filename_disk'] }); |
| 183 | |
| 184 | // delete the previously saved file and thumbnails to ensure they're generated fresh |
| 185 | for await (const partPath of this.storageDriver.list(targetId)) { |
| 186 | await this.storageDriver.delete(partPath); |
| 187 | } |
| 188 | |
| 189 | // Upgrade the temp file to the final filename |
| 190 | await this.storageDriver.move(filePath, replaceData.filename_disk); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | return newOffset; |
| 195 | } catch (err: any) { |
| 196 | logger.error(err, 'Error writing chunk for upload "%s" at offset %d', tus_id, offset); |
| 197 | |
| 198 | if ('status_code' in err && err.status_code === 500) { |
| 199 | throw err; |
| 200 | } |
| 201 | |
| 202 | throw ERRORS.FILE_WRITE_ERROR; |
no test coverage detected