Skip to content

Commit

Permalink
feat!: add download URL method to BlobsStorage (storacha#1469)
Browse files Browse the repository at this point in the history
Ensures we don't hardcode the downlaod URL in the implementation.
  • Loading branch information
Alan Shaw authored May 16, 2024
1 parent fb6e5a1 commit 4a2c994
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 18 deletions.
16 changes: 5 additions & 11 deletions packages/upload-api/src/blob/accept.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { code as rawCode } from 'multiformats/codecs/raw'
import * as API from '../types.js'
import { AllocatedMemoryHadNotBeenWrittenTo } from './lib.js'

const R2_REGION = 'auto'
const R2_BUCKET = 'carpark-prod-0'

/**
* @param {API.W3ServiceContext} context
* @returns {API.ServiceMethod<API.BlobAccept, API.BlobAcceptSuccess, API.BlobAcceptFailure>}
Expand All @@ -32,21 +29,18 @@ export function blobAcceptProvider(context) {

const digest = Digest.decode(blob.digest)
const content = createLink(rawCode, digest)
const url =
/** @type {API.URI<'https:'>} */
(
`https://w3s.link/ipfs/${content}?format=raw&origin=${encodeURIComponent(
`r2://${R2_REGION}/${R2_BUCKET}`
)}`
)
const createUrl = await context.blobsStorage.createDownloadUrl(digest.bytes)
if (createUrl.error) {
return createUrl
}

const locationClaim = await Assert.location.delegate({
issuer: context.id,
audience: DID.parse(space),
with: context.id.toDIDKey(),
nb: {
content,
location: [url],
location: [createUrl.ok],
},
expiration: Infinity,
})
Expand Down
2 changes: 2 additions & 0 deletions packages/upload-api/src/types/blob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
Result,
Failure,
DID,
URI,
} from '@ucanto/interface'
import {
Multihash,
Expand Down Expand Up @@ -84,4 +85,5 @@ export interface BlobsStorage {
Failure
>
>
createDownloadUrl: (content: Multihash) => Promise<Result<URI, Failure>>
}
9 changes: 4 additions & 5 deletions packages/upload-api/test/handlers/web3.storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { provisionProvider } from '../helpers/utils.js'
import { createServer, connect } from '../../src/lib.js'
import { alice, bob, createSpace, registerSpace } from '../util.js'
import { parseBlobAddReceiptNext } from '../helpers/blob.js'
import * as Result from '../helpers/result.js'

/**
* @type {API.Tests}
Expand Down Expand Up @@ -611,11 +612,9 @@ export const test = {
// @ts-expect-error nb unknown
const locations = delegation.capabilities[0].nb.location
assert.equal(locations.length, 1)
assert.ok(
locations[0].includes(
`https://w3s.link/ipfs/${content}?format=raw&origin=`
)
)

const loc = Result.unwrap(await context.blobsStorage.createDownloadUrl(digest))
assert.ok(locations.includes(loc))
},
'web3.storage/blob/accept fails to provide site delegation when blob was not stored':
async (assert, context) => {
Expand Down
28 changes: 27 additions & 1 deletion packages/upload-api/test/storage/blobs-storage-tests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as API from '../../src/types.js'

import { sha256 } from 'multiformats/hashes/sha2'
import * as Result from '../helpers/result.js'
import { equals } from 'multiformats/bytes'

/**
* @type {API.Tests}
Expand Down Expand Up @@ -43,4 +44,29 @@ export const test = {
const hasBlob = await blobsStorage.has(blob.digest)
assert.ok(hasBlob.ok)
},

'should create valid download URL for blobs that can be used to read':
async (assert, { blobsStorage }) => {
const data = new Uint8Array([11, 22, 34, 44, 55])
const digest = await sha256.digest(data)
const expires = 60 * 60 * 24 // 1 day

const upload = Result.unwrap(
await blobsStorage.createUploadUrl(digest.bytes, data.length, expires)
)

await fetch(upload.url, {
method: 'PUT',
mode: 'cors',
body: data,
headers: upload.headers,
})

const downloadUrl = Result.unwrap(
await blobsStorage.createDownloadUrl(digest.bytes)
)

const res = await fetch(downloadUrl)
assert.ok(equals(new Uint8Array(await res.arrayBuffer()), data))
}
}
17 changes: 16 additions & 1 deletion packages/upload-api/test/storage/blobs-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class BlobsStorage {
const content = new Map()
if (http) {
const server = http.createServer(async (request, response) => {
const { pathname } = new URL(request.url || '/', url)
if (request.method === 'PUT') {
const buffer = new Uint8Array(
parseInt(request.headers['content-length'] || '0')
Expand All @@ -41,10 +42,17 @@ export class BlobsStorage {
if (checksum !== request.headers['x-amz-checksum-sha256']) {
response.writeHead(400, `checksum mismatch`)
} else {
const { pathname } = new URL(request.url || '/', url)
content.set(pathname, buffer)
response.writeHead(200)
}
} else if (request.method === 'GET') {
const data = content.get(pathname)
if (data) {
response.writeHead(200)
response.write(data)
} else {
response.writeHead(404)
}
} else {
response.writeHead(405)
}
Expand Down Expand Up @@ -202,4 +210,11 @@ export class BlobsStorage {
},
}
}

/** @param {Uint8Array} multihash */
async createDownloadUrl (multihash) {
const digest = digestDecode(multihash)
const url = new URL(this.#bucketPath(digest), this.baseURL)
return ok(/** @type {Types.URI} */ (url.toString()))
}
}

0 comments on commit 4a2c994

Please sign in to comment.