|
1 | | -import type { ReadableStream } from 'node:stream/web' |
2 | | -import { Buffer } from 'node:buffer' |
3 | | -import { randomUUID } from 'node:crypto' |
4 | | - |
5 | | -import { z } from 'zod' |
6 | | -import { logger } from '~/lib/logger' |
7 | | - |
8 | | -import { getStorage } from '~/lib/storage' |
9 | | - |
10 | | -const pathParamsSchema = z.object({ |
11 | | - uploadId: z.coerce.number(), |
12 | | -}) |
13 | | - |
14 | | -export default defineEventHandler(async (event) => { |
15 | | - const parsedPathParams = pathParamsSchema.safeParse(event.context.params) |
16 | | - if (!parsedPathParams.success) |
17 | | - throw createError({ |
18 | | - statusCode: 400, |
19 | | - statusMessage: `Invalid path parameters: ${parsedPathParams.error.message}`, |
20 | | - }) |
21 | | - |
22 | | - if (getQuery(event).comp === 'blocklist') { |
23 | | - setResponseStatus(event, 201) |
24 | | - // prevent random EOF error with in tonistiigi/go-actions-cache caused by missing request id |
25 | | - setHeader(event, 'x-ms-request-id', randomUUID()) |
26 | | - return |
27 | | - } |
28 | | - |
29 | | - const blockId = getQuery(event)?.blockid as string |
30 | | - // if no block id, upload smaller than chunk size |
31 | | - const chunkIndex = blockId ? getChunkIndexFromBlockId(blockId) : 0 |
32 | | - if (chunkIndex === undefined) |
33 | | - throw createError({ |
34 | | - statusCode: 400, |
35 | | - statusMessage: `Invalid block id: ${blockId}`, |
36 | | - }) |
37 | | - |
38 | | - const { uploadId } = parsedPathParams.data |
39 | | - |
40 | | - const stream = getRequestWebStream(event) |
41 | | - if (!stream) { |
42 | | - logger.debug('Upload: Request body is not a stream') |
43 | | - throw createError({ statusCode: 400, statusMessage: 'Request body must be a stream' }) |
44 | | - } |
45 | | - |
46 | | - const storage = await getStorage() |
47 | | - await storage.uploadPart(uploadId, chunkIndex, stream as ReadableStream) |
48 | | - |
49 | | - // prevent random EOF error with in tonistiigi/go-actions-cache caused by missing request id |
50 | | - setHeader(event, 'x-ms-request-id', randomUUID()) |
51 | | - setResponseStatus(event, 201) |
52 | | -}) |
53 | | - |
54 | | -function getChunkIndexFromBlockId(blockIdBase64: string) { |
55 | | - const base64Decoded = Buffer.from(blockIdBase64, 'base64') |
56 | | - |
57 | | - // 64 bytes used by docker buildx |
58 | | - // 48 bytes used by everything else |
59 | | - if (base64Decoded.length === 64) { |
60 | | - return base64Decoded.readUInt32BE(16) |
61 | | - } else if (base64Decoded.length === 48) { |
62 | | - const decoded = base64Decoded.toString('utf8') |
63 | | - |
64 | | - // slice off uuid and convert to number |
65 | | - const index = Number.parseInt(decoded.slice(36)) |
66 | | - if (Number.isNaN(index)) return |
67 | | - |
68 | | - return index |
69 | | - } |
70 | | -} |
| 1 | +export { default } from '~/routes/devstoreaccount1/upload/[uploadId].put' |
0 commit comments