-
Notifications
You must be signed in to change notification settings - Fork 167
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support CAR file uploads (#178)
A first pass at handling CAR uploads, smaller than 100MB. (no car-chunking here). The aim was the smallest change that woud allow users to create and upload their own CARs and have nft.storage handle it correctly, to unblock users who want to pre-compute the root CID for their files. Turns out it was almost supported already. Good work Spark! - api: check for Content-Type: application/car and handle cluster size vs bytes difference and test it. - api: add a `smoke` mock for posting small car files to cluster. - client: add isCar flag to storeBlob to force application/car content type on upload. - website: add is CAR? check box to file upload form to try it out, and an explainer. - website: update openAPI schema Fixes #172 | upload form | details expanded | |-------------|-------------------| | <img width="904" alt="Screenshot 2021-06-07 at 14 34 39" src="https://user-images.githubusercontent.com/58871/121255774-b6618180-c8a3-11eb-9119-29b32bd0902f.png"> | <img width="904" alt="Screenshot 2021-06-07 at 14 34 50" src="https://user-images.githubusercontent.com/58871/121255797-bfeae980-c8a3-11eb-8b40-d79104e03ecc.png"> License: MIT Signed-off-by: Oli Evans <oli@tableflip.io>
- Loading branch information
Showing
21 changed files
with
721 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const { CarReader } = require('@ipld/car') | ||
|
||
/** | ||
* https://github.com/sinedied/smoke#javascript-mocks | ||
* @typedef {{ buffer: Buffer, originalname: string }} MultrFile | ||
* @param {{ query: Record<string, string>, files: MultrFile[] }} request | ||
*/ | ||
module.exports = async ({ query, files }) => { | ||
const car = await CarReader.fromBytes(files[0].buffer) | ||
const roots = await car.getRoots() | ||
// @ts-ignore | ||
const { cid, bytes } = await car.get(roots[0]) | ||
const result = { | ||
cid: { | ||
'/': cid.toString(), | ||
}, | ||
name: files[0].originalname, | ||
// car uploads may not be unixfs, so get a bytes property instead of `size` https://github.com/ipfs/ipfs-cluster/issues/1362 | ||
bytes: bytes.length, | ||
} | ||
return { | ||
statusCode: 200, | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: query['stream-channels'] === 'false' ? [result] : result, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import * as Block from 'multiformats/block' | ||
import * as Raw from 'multiformats/codecs/raw' | ||
import { sha256 } from 'multiformats/hashes/sha2' | ||
import * as CAR from '../../src/utils/car.js' | ||
|
||
/** | ||
* @param {string} str Data to encode into CAR file. | ||
*/ | ||
export async function createCar(str) { | ||
const value = new TextEncoder().encode(str) | ||
const block = await Block.encode({ | ||
value, | ||
codec: Raw, | ||
hasher: sha256, | ||
}) | ||
const root = block.cid | ||
const car = await CAR.encode([root], [block]) | ||
return { root, car } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules | ||
.DS_Store | ||
dist | ||
dist-ssr | ||
*.local |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# CAR upload demo - nft.storage | ||
|
||
A demo using ipfs-car in the browser to create a CAR file and pre-calculate the CID for an asset then storing it on nft.storage and confirming that it uses the exact same CID for the asset. | ||
|
||
## Getting started | ||
|
||
```console | ||
npm install | ||
npm run dev | ||
|
||
# or | ||
yarn | ||
yarn dev | ||
``` | ||
|
||
Then visit `http://localhost:3000?key=<your nft.storage API KEY here>` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<title>CAR upload - nft.storage</title> | ||
</head> | ||
<body> | ||
<pre id="out"></pre> | ||
<script type="module" src="/main.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { NFTStorage } from 'nft.storage' | ||
import { packToBlob } from 'ipfs-car/pack/blob' | ||
|
||
const endpoint = 'http://api.nft.storage' // the default | ||
const token = | ||
new URLSearchParams(window.location.search).get('key') || 'API_KEY' // your API key from https://nft.storage/manage | ||
|
||
function log(msg) { | ||
msg = JSON.stringify(msg, null, 2) | ||
document.getElementById('out').innerHTML += `${msg}\n` | ||
} | ||
|
||
async function main() { | ||
const store = new NFTStorage({ endpoint, token }) | ||
const data = 'Hello nft.storage!' | ||
|
||
// locally chunk'n'hash the data to get the CID and pack the blocks in to a CAR | ||
const { root, car } = await packToBlob({ | ||
input: [new TextEncoder().encode(data)], | ||
}) | ||
const expectedCid = root.toString() | ||
console.log({ expectedCid }) | ||
|
||
// send the CAR to nft.storage, the returned CID will match the one we created above. | ||
const cid = await store.storeCar(car) | ||
|
||
// verify the service is storing the CID we expect | ||
const cidsMatch = expectedCid === cid | ||
log({ data, cid, expectedCid, cidsMatch }) | ||
|
||
// check that the CID is pinned | ||
const status = await store.status(cid) | ||
log(status) | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"version": "0.0.0", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vite build", | ||
"serve": "vite preview" | ||
}, | ||
"devDependencies": { | ||
"vite": "^2.3.7" | ||
}, | ||
"dependencies": { | ||
"ipfs-car": "^0.2.4", | ||
"nft.storage": "../../../" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import fs from 'fs' | ||
import { packToBlob } from 'ipfs-car/pack/blob' | ||
import { NFTStorage } from '../../src/lib.js' | ||
|
||
const endpoint = 'https://api.nft.storage' // the default | ||
const token = 'API_KEY' // your API key from https://nft.storage/manage | ||
|
||
async function main() { | ||
const storage = new NFTStorage({ endpoint, token }) | ||
|
||
// locally chunk'n'hash the file to get the CID and pack the blocks in to a CAR | ||
const { root, car } = await packToBlob({ | ||
input: fs.createReadStream('pinpie.jpg'), | ||
}) | ||
|
||
const expectedCid = root.toString() | ||
console.log({ expectedCid }) | ||
|
||
// send the CAR to nft.storage, setting isCar to true | ||
const cid = await storage.storeCar(car) | ||
|
||
// verify the service stored the CID we expected | ||
const cidsMatch = expectedCid === cid | ||
console.log({ cid, expectedCid, cidsMatch }) | ||
|
||
// check that the CID is pinned | ||
const status = await storage.status(cid) | ||
console.log(status) | ||
} | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.