Skip to content

Commit

Permalink
chore: remove legacy upload codepath (#2580)
Browse files Browse the repository at this point in the history
plus feature flag and related tests
  • Loading branch information
travis authored Apr 15, 2024
1 parent 766a7c1 commit 88c05a9
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 480 deletions.
8 changes: 0 additions & 8 deletions decisions/20240313-try-w3up.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,6 @@ configures how nft.storage will authenticate to web3.storage when sending invoca
configures the capabilities that nft.storage has access to when interacting with web3.storage to store nfts. These capabilities will usually be UCAN delegations whose audience is the identifier of `W3_NFTSTORAGE_PRINCIPAL`.
W3_NFTSTORAGE_PROOF needs to have proof rooted in W3_NFTSTORAGE_SPACE that authorize W3_NFTSTORAGE_PRINCIPAL to store in W3_NFTSTORAGE_SPACE.

##### `W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS` Environment Variable

configures feature switch for which nftstorage accounts will have new uploads stored in web3.storage.

Note: this environment variable may not be a permanent addition to the codebase. It's only meant to be used as a feature switch that decouples enabling the new functionality from deploying the new code. After testing, we may remove or change this feature switch when it is no longer useful.

Format: JSON Array of email address strings.

#### UI Changes

None. But the existing UI workflow of uploading via https://nft.storage/files/ and form should behave just like they do now. But after this change, there should be a new side effect, which is that the upload should appear in the listing of uploads for the configured `W3_NFTSTORAGE_SPACE` (e.g. via w3cli `w3 ls` or in console.web3.storage).
Expand Down
8 changes: 0 additions & 8 deletions packages/api/src/bindings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,6 @@ export interface ServiceConfiguration {

/** did:key of the w3up space in which to store NFTs */
W3_NFTSTORAGE_SPACE?: string

/**
* JSON array of strings that are emails whose uploads should be uploaded via w3up.
* This is meant as a feature switch to test new functionality,
* and this configuration may be removed once the feature switch isn't needed to limit access.
*/
W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS?: string
}

export interface Ucan {
Expand Down Expand Up @@ -161,7 +154,6 @@ export interface RouteContext {
W3_NFTSTORAGE_PRINCIPAL?: string
W3_NFTSTORAGE_PROOF?: string
W3_NFTSTORAGE_SPACE?: string
W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS?: string
w3up?: W3upClient
contentClaims?: ContentClaimsClient
}
Expand Down
3 changes: 0 additions & 3 deletions packages/api/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ export function serviceConfigFromVariables(vars) {
W3_NFTSTORAGE_PRINCIPAL: vars.W3_NFTSTORAGE_PRINCIPAL,
W3_NFTSTORAGE_PROOF: vars.W3_NFTSTORAGE_PROOF,
W3_NFTSTORAGE_SPACE: vars.W3_NFTSTORAGE_SPACE,
W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS:
vars.W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS,
}
}

Expand Down Expand Up @@ -136,7 +134,6 @@ export function loadConfigVariables() {
'W3_NFTSTORAGE_SPACE',
'W3_NFTSTORAGE_PRINCIPAL',
'W3_NFTSTORAGE_PROOF',
'W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS',
]

for (const name of optional) {
Expand Down
51 changes: 3 additions & 48 deletions packages/api/src/routes/nfts-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,6 @@ export async function nftUpload(event, ctx) {
return new JSONResponse({ ok: true, value: toNFTResponse(upload) })
}

/**
* returns whether w3up uploading feature is enabled given context + event
* @param {object} context - context of server operation, e.g. including configuration of feature switch
* @param {string} [context.W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS] - JSON array of allowed emails
* @param {object} event - specific event for which we should determine whether w3up feature is enabled
* @param {object} event.user
* @param {string} event.user.email - email address of user associated with event
*/
function w3upFeatureSwitchEnabled(context, event) {
// const { W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS = '[]' } = context
// const allowedEmails = JSON.parse(W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS)
// if (!Array.isArray(allowedEmails)) return false
// const eventHasAllowedEmail = allowedEmails.find(
// (allowed) => allowed === event.user.email
// )
return true
}

/**
* @typedef {{
* event: FetchEvent,
Expand Down Expand Up @@ -170,10 +152,8 @@ export async function uploadCarWithStat(
/** @type {(() => Promise<void>)|undefined} */
let checkDagStructureTask
const backupUrls = []
// @ts-expect-error email is not expected in types
if (ctx.w3up && w3upFeatureSwitchEnabled(ctx, { user })) {
const { w3up } = ctx

const { w3up } = ctx
if (w3up) {
// we perform store/add and upload/add concurrently to save time.
await Promise.all([
w3up.capability.store.add(car),
Expand Down Expand Up @@ -204,32 +184,7 @@ export async function uploadCarWithStat(
}
}
} else {
const carBytes = new Uint8Array(await car.arrayBuffer())
const [s3Backup, r2Backup] = await Promise.all([
ctx.s3Uploader.uploadCar(carBytes, stat.cid, user.id, metadata),
ctx.r2Uploader.uploadCar(carBytes, stat.cid, user.id, metadata),
])
backupUrls.push(s3Backup.url, r2Backup.url)

// no need to ask linkdex if it's Complete or Unknown
if (stat.structure === 'Partial') {
// ask linkdex for the dag structure across the set of CARs in S3 for this upload.
checkDagStructureTask = async () => {
try {
const structure = await ctx.linkdexApi.getDagStructure(s3Backup.key)
if (structure === 'Complete') {
return ctx.db.updatePinStatus(
upload.content_cid,
elasticPin(structure)
)
}
} catch (/** @type {any} */ err) {
if (err.code !== MissingApiUrlCode) {
throw err
}
}
}
}
throw new Error('w3up not defined, cannot upload')
}
const xName = event.request.headers.get('x-name')
let name = xName && decodeURIComponent(xName)
Expand Down
2 changes: 0 additions & 2 deletions packages/api/src/utils/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ export async function getContext(event, params) {
W3_NFTSTORAGE_PRINCIPAL: config.W3_NFTSTORAGE_PRINCIPAL,
W3_NFTSTORAGE_PROOF: config.W3_NFTSTORAGE_PROOF,
W3_NFTSTORAGE_SPACE: config.W3_NFTSTORAGE_SPACE,
W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS:
config.W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS,
}
let w3up
if (
Expand Down
26 changes: 26 additions & 0 deletions packages/api/test/bindings.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ProviderInput } from '@ucanto/server'
import { InferInvokedCapability } from '@ucanto/client'
import { Store, Upload, Filecoin } from '@web3-storage/capabilities'
import { FilecoinInfoSuccess } from '@web3-storage/capabilities/types'
import { Server as HttpServer } from 'http'

interface MockW3upOptions {
did?: string
onHandleFilecoinInfo?: (
invocation: ProviderInput<InferInvokedCapability<typeof Filecoin.info>>
) => Promise<FilecoinInfoSuccess | undefined>
onHandleUploadGet?: (
invocation: ProviderInput<InferInvokedCapability<typeof Upload.get>>
) => Promise<UploadGetSuccess | undefined>
onHandleStoreAdd?: (
invocation: ProviderInput<InferInvokedCapability<typeof Store.add>>
) => Promise<void>
onHandleUploadAdd?: (
invocation: ProviderInput<InferInvokedCapability<typeof Upload.add>>
) => Promise<void>
}

interface MockW3up {
server: HttpServer
did: string
}
10 changes: 9 additions & 1 deletion packages/api/test/maintenance.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ import {
getMiniflareContext,
setupMiniflareContext,
} from './scripts/test-context.js'
import {
createMockW3upServer,
w3upMiniflareOverrides,
} from './utils/w3up-testing.js'

/** @typedef {import('../src/middleware/maintenance.js').Mode} Mode */

test.before(async (t) => {
await setupMiniflareContext(t)
await setupMiniflareContext(t, {
overrides: {
...(await w3upMiniflareOverrides(await createMockW3upServer())),
},
})
})

/**
Expand Down
110 changes: 36 additions & 74 deletions packages/api/test/nfts-get.spec.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
import test from 'ava'
import { createServer } from 'node:http'
import { ed25519 } from '@ucanto/principal'
import { delegate, parseLink } from '@ucanto/core'
import { base64 } from 'multiformats/bases/base64'
import { parseLink } from '@ucanto/core'
import { createClientWithUser } from './scripts/helpers.js'
import { fixtures } from './scripts/fixtures.js'
import {
getMiniflareContext,
setupMiniflareContext,
} from './scripts/test-context.js'
import {
createMockW3up,
locate,
encodeDelegationAsCid,
createMockW3upServer,
w3upMiniflareOverrides,
} from './utils/w3up-testing.js'

const nftStorageSpace = ed25519.generate()
const nftStorageApiPrincipal = ed25519.generate()
const nftStorageAccountEmailAllowListedForW3up = '[email protected]'
const mockW3upDID = 'did:web:test.web3.storage'
/**
* @type {import('@web3-storage/access').PieceLink}
*/
Expand All @@ -45,73 +37,43 @@ const mockDeals = [
const cidWithShards = parseLink(
'bafybeiccy35oi3gajocq5bbg7pnaxb3kv5ibtdz3tc3kari53qhbjotzey'
)
const mockW3up = Promise.resolve(
(async function () {
const server = createServer(
await createMockW3up({
did: mockW3upDID,
// @ts-expect-error not returning a full upload get response for now
async onHandleUploadGet(invocation) {
if (invocation.capability.nb.root?.equals(cidWithShards)) {
return {
// grabbed this shard CID from staging, it should correspond to a piece named bafkzcibeslzwmewd4pugjanyiayot5m76a67dvdir25v6ms6kbuozy2sxotplrrrce
shards: [
parseLink(
'bagbaieragf62xatg3bqrfafdy3lpk2fte7526kvxnltqsnhjr45cz6jjk7mq'
),
],
}
} else {
return {
shards: [],
}
}
},
async onHandleFilecoinInfo(invocation) {
if (invocation.capability.nb.piece.equals(mockPieceLink)) {
return {
deals: mockDeals,
aggregates: [],
piece: mockPieceLink,
}
} else {
return undefined
}
},
})
)
server.listen(0)
await new Promise((resolve) =>
server.addListener('listening', () => resolve(undefined))
)
return {
server,
}
})()
)

test.before(async (t) => {
const mockW3up = await createMockW3upServer({
async onHandleUploadGet(invocation) {
if (invocation.capability.nb.root?.equals(cidWithShards)) {
return {
// grabbed this shard CID from staging, it should correspond to a piece named bafkzcibeslzwmewd4pugjanyiayot5m76a67dvdir25v6ms6kbuozy2sxotplrrrce
shards: [
parseLink(
'bagbaieragf62xatg3bqrfafdy3lpk2fte7526kvxnltqsnhjr45cz6jjk7mq'
),
],
}
} else {
return {
shards: [],
}
}
},
async onHandleFilecoinInfo(invocation) {
if (invocation.capability.nb.piece.equals(mockPieceLink)) {
return {
deals: mockDeals,
aggregates: [],
piece: mockPieceLink,
}
} else {
return undefined
}
},
})
await setupMiniflareContext(t, {
overrides: {
W3UP_URL: locate((await mockW3up).server).url.toString(),
W3UP_DID: mockW3upDID,
W3_NFTSTORAGE_SPACE: (await nftStorageSpace).did(),
W3_NFTSTORAGE_PRINCIPAL: ed25519.format(await nftStorageApiPrincipal),
W3_NFTSTORAGE_PROOF: (
await encodeDelegationAsCid(
await delegate({
issuer: await nftStorageSpace,
audience: await nftStorageApiPrincipal,
capabilities: [
{ can: 'upload/get', with: (await nftStorageSpace).did() },
{ can: 'filecoin/info', with: (await nftStorageSpace).did() },
],
})
)
).toString(base64),
W3_NFTSTORAGE_ENABLE_W3UP_FOR_EMAILS: JSON.stringify([
nftStorageAccountEmailAllowListedForW3up,
]),
...(await w3upMiniflareOverrides(mockW3up, [
'upload/get',
'filecoin/info',
])),
},
})
})
Expand Down
10 changes: 9 additions & 1 deletion packages/api/test/nfts-metaplex-upload.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@ import {
getTestServiceConfig,
setupMiniflareContext,
} from './scripts/test-context.js'
import {
createMockW3upServer,
w3upMiniflareOverrides,
} from './utils/w3up-testing.js'

/** @type {number} */
let metaplexUserId

test.before(async (t) => {
await setupMiniflareContext(t)
await setupMiniflareContext(t, {
overrides: {
...(await w3upMiniflareOverrides(await createMockW3upServer())),
},
})

const config = getTestServiceConfig(t)
const rawClient = getRawClient(config)
Expand Down
13 changes: 12 additions & 1 deletion packages/api/test/nfts-store.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,20 @@ import {
} from './scripts/test-context.js'
import { File, Blob } from 'nft.storage/src/platform.js'
import { FormData } from 'undici'
import {
createMockW3upServer,
w3upMiniflareOverrides,
} from './utils/w3up-testing.js'

const overrides = (async () =>
await w3upMiniflareOverrides(await createMockW3upServer()))()

test.beforeEach(async (t) => {
await setupMiniflareContext(t)
await setupMiniflareContext(t, {
overrides: {
...(await overrides),
},
})
})

test('should store image', async (t) => {
Expand Down
Loading

0 comments on commit 88c05a9

Please sign in to comment.