Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add AssetManager #603

Merged
merged 26 commits into from Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c36caa7
First AssetManager implementation
sea-snake Jul 27, 2022
d35f95a
feat: add AssetManager
sea-snake Jul 28, 2022
43255eb
Refactor, remove deps and
sea-snake Sep 26, 2022
dc426b2
Merge pull request #1 from dfinity/main
sea-snake Sep 26, 2022
2fd4213
Merge latest changes from main branch
sea-snake Sep 26, 2022
0376d18
Update concurrency to 16
sea-snake Sep 26, 2022
6058af2
Added verifySha256
sea-snake Sep 26, 2022
4ae6b37
Update @dfinity/assets readme and changelog
sea-snake Sep 26, 2022
c272f10
Remove browsers tests, already covered by node tests
sea-snake Sep 26, 2022
31840a5
Revert browser e2e changes
sea-snake Sep 26, 2022
94b9543
Merge pull request #2 from slide-computer/assets
sea-snake Sep 26, 2022
d50222a
Revert browser e2e changes
sea-snake Sep 26, 2022
04944fb
Merge pull request #3 from slide-computer/assets
sea-snake Sep 26, 2022
bb59721
Revert browser e2e changes
sea-snake Sep 26, 2022
4d871dd
Merge pull request #4 from slide-computer/assets
sea-snake Sep 26, 2022
f2a3e4b
Update @dfinity/assets e2e test and README.md
sea-snake Sep 26, 2022
a879fb6
Merge pull request #5 from slide-computer/assets
sea-snake Sep 26, 2022
5b92dda
Update ReadableBytes
sea-snake Sep 26, 2022
53f7642
Fix linting issues, update jest and ts configs, update JS docs and ad…
sea-snake Sep 29, 2022
613b229
Close Node.js write handle after writing chunks and add additional No…
sea-snake Sep 29, 2022
ad6d6b4
fixing lint erro
krpeacock Sep 29, 2022
4ab2635
Merge branch 'main' into 602-assets
krpeacock Sep 29, 2022
36caeef
Slightly increase timeout so tests with larger assets pass.
sea-snake Oct 1, 2022
29d1f5a
Merge remote-tracking branch 'origin/602-assets' into 602-assets
sea-snake Oct 1, 2022
59feb15
Increase timeout (again) so tests with larger assets pass.
sea-snake Oct 4, 2022
04016ce
Decrease test asset size to reduce E2E test duration.
sea-snake Oct 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/generated/changelog.html
Expand Up @@ -20,6 +20,10 @@ <h2>Version 0.13.4</h2>
<li>
bug: auth-client storage wrapper returns after resolve to avoid idb to be recreated
</li>
<li>
New package: @dfinity/assets. This package provides an asset manager to manage assets
on an assets canister.
</li>
</ul>
<h2>Version 0.13.3</h2>
<ul>
Expand Down
92 changes: 92 additions & 0 deletions e2e/node/basic/assets.test.ts
@@ -0,0 +1,92 @@
/**
* @jest-environment node
*/
import { readFileSync } from 'fs';
import path from 'path';
import agent from '../utils/agent';
import { Actor } from '@dfinity/agent';
import { Principal } from '@dfinity/principal';
import { AssetManager } from '@dfinity/assets';

/**
* Create (pseudo) random bytes Readable
* @param fileName File name of Readable
* @param length Byte length of Readable
*/
const randomBytesReadable = (fileName: string, length: number) => {
const rand = Math.floor(Math.random() * 10000);
return {
fileName,
contentType: 'application/octet-stream',
length,
open: async () => {},
close: async () => {},
slice: async (start: number, end: number) => {
return Uint8Array.from(
Array.from({ length: end - start }).map((_, i) => {
const offset = start + i;
const x = Math.sin(rand + offset) * 10000;
return Math.floor((x - Math.floor(x)) * 256);
}),
);
},
};
};

jest.setTimeout(60000);
describe('assets', () => {
let canisterId: Principal;

const testRandomBytes = async (fileName: string, length: number) => {
const assetManager = new AssetManager({ canisterId, agent: await agent });
const readable = randomBytesReadable(fileName, length);
const key = await assetManager.store(readable);
const asset = await assetManager.get(key);
const sentData = await readable.slice(0, readable.length);
const receivedData = await asset.toUint8Array();
const isCertified = await asset.isCertified();
const isValidSha = await asset.verifySha256(receivedData);
await assetManager.delete(key);

expect(key).toEqual(`/${readable.fileName}`);
expect(asset.contentType).toEqual(readable.contentType);
expect(asset.length).toEqual(readable.length);
expect(Array.from(receivedData).join()).toEqual(Array.from(sentData).join());
expect(isCertified).toBe(true);
expect(isValidSha).toBe(true);
await expect(assetManager.get(key)).rejects.toThrow(/asset not found/);
};

beforeAll(async () => {
const module = readFileSync(path.join(__dirname, '../canisters/assets.wasm'));
canisterId = await Actor.createCanister({ agent: await agent });
await Actor.install({ module }, { canisterId, agent: await agent });
});

afterEach(async () => {
const assetManager = new AssetManager({ canisterId, agent: await agent });
await assetManager.clear();
});

it('store, get and delete 1MB asset (single chunk)', () => testRandomBytes('1MB.bin', 1000000));

it('store, get and delete 3MB asset (multiple chunk)', () => testRandomBytes('3MB.bin', 3000000));

it('batch process assets and verify asset list', async () => {
const assetManager = new AssetManager({ canisterId, agent: await agent });
const batch = assetManager.batch();

// Initial X asset
const x = randomBytesReadable('X.bin', 1000);
await assetManager.store(x);

// Batch store A and B assets and delete X asset
const readables = [randomBytesReadable('A.bin', 1000), randomBytesReadable('B.bin', 1000)];
await batch.delete(`/${x.fileName}`);
await Promise.all(readables.map(readable => batch.store(readable)));
await batch.commit();
await expect(
assetManager.list().then(assets => assets.map(asset => asset.key).sort()),
).resolves.toEqual(readables.map(({ fileName }) => `/${fileName}`).sort());
});
});
Binary file added e2e/node/canisters/assets.wasm
Binary file not shown.
1 change: 1 addition & 0 deletions e2e/node/package.json
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@dfinity/agent": "^0.13.3",
"@dfinity/authentication": "^0.13.3",
"@dfinity/assets": "^0.13.3",
"@dfinity/identity": "^0.13.3",
"@dfinity/principal": "^0.13.3",
"@trust/webcrypto": "^0.9.2",
Expand Down