Skip to content

Commit

Permalink
feat: add ability to read with offset and length + update to wnfs 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
icidasset committed Feb 18, 2024
1 parent f82472f commit c774541
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 68 deletions.
2 changes: 1 addition & 1 deletion packages/nest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
"multiformats": "^12.1.3",
"p-debounce": "^4.0.0",
"uint8arrays": "^5.0.1",
"wnfs": "0.1.27"
"wnfs": "0.2.0"
},
"devDependencies": {
"@types/assert": "^1.5.9",
Expand Down
36 changes: 25 additions & 11 deletions packages/nest/src/class.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { Blockstore } from 'interface-blockstore'
import type { PrivateForest, PublicDirectory, PublicFile } from 'wnfs'
import type {
PrivateForest,
PublicDirectory,
PublicFile,
PublicNode,
} from 'wnfs'

import { CID } from 'multiformats/cid'
import { AccessKey, PrivateDirectory, PrivateFile, PrivateNode } from 'wnfs'
Expand Down Expand Up @@ -401,7 +406,7 @@ export class FileSystem {
capsuleKey: Uint8Array
},
dataType: D,
options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
): Promise<DataForType<D, V>>
async read<V = unknown>(
path:
Expand All @@ -412,7 +417,7 @@ export class FileSystem {
capsuleKey: Uint8Array
},
dataType: DataType,
options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
): Promise<AnySupportedDataType<V>> {
return await this.#transactionContext().read<DataType, V>(
path,
Expand Down Expand Up @@ -722,25 +727,34 @@ export class FileSystem {

switch (partition.name) {
case 'public': {
const node =
const wnfsBlockstore = Store.wnfs(this.#blockstore)

const node: PublicNode | null | undefined =
partition.segments.length === 0
? this.#rootTree.publicRoot().asNode()
: await this.#rootTree
.publicRoot()
.getNode(partition.segments, Store.wnfs(this.#blockstore))
.getNode(partition.segments, wnfsBlockstore)

if (node === null || node === undefined)
throw new Error('Failed to find needed public node for infusion')

const fileOrDir: PublicFile | PublicDirectory =
node.isFile() === true ? node.asFile() : node.asDir()
const fileOrDir: PublicFile | PublicDirectory = node.isFile()
? node.asFile()
: node.asDir()

const capsuleCID = await fileOrDir
.store(Store.wnfs(this.#blockstore))
.then((a) => CID.decode(a as Uint8Array))
const contentCID =
node.isFile() === true
? CID.decode(node.asFile().contentCid() as Uint8Array)
: capsuleCID

const contentCID = node.isFile()
? CID.decode(
await node
.asFile()
.getRawContentCid(wnfsBlockstore)
.then((u) => u as Uint8Array)
)
: capsuleCID

return {
dataRoot,
Expand Down
5 changes: 1 addition & 4 deletions packages/nest/src/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import type {
} from './types/internal.js'

import * as Store from './store.js'
import * as Unix from './unix.js'

import { searchLatest } from './common.js'

Expand Down Expand Up @@ -51,13 +50,11 @@ export const publicRemove = () => {

export const publicWrite = (bytes: Uint8Array) => {
return async (params: PublicParams): Promise<WnfsPublicResult> => {
const cid = await Unix.importFile(bytes, params.blockstore)

return await params.rootTree
.publicRoot()
.write(
params.pathSegments,
cid.bytes,
bytes,
new Date(),
Store.wnfs(params.blockstore)
)
Expand Down
80 changes: 49 additions & 31 deletions packages/nest/src/queries.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { CID } from 'multiformats/cid'
import type { Blockstore } from 'interface-blockstore'
import type {
AccessKey,
Expand All @@ -8,7 +9,6 @@ import type {
} from 'wnfs'

import { PrivateNode } from 'wnfs'
import { CID } from 'multiformats/cid'

import * as Store from './store.js'
import * as Path from './path.js'
Expand Down Expand Up @@ -105,20 +105,31 @@ export const publicListDirectoryWithKind = () => {

export const publicRead = (options?: { offset: number; length: number }) => {
return async (params: PublicParams): Promise<Uint8Array> => {
const result = await params.rootTree
const wnfsBlockStore = Store.wnfs(params.blockstore)

const node: PublicNode | null | undefined = await params.rootTree
.publicRoot()
.read(params.pathSegments, Store.wnfs(params.blockstore))
.getNode(params.pathSegments, wnfsBlockStore)

return await publicReadFromCID(
CID.decode(result as Uint8Array),
options
)(params)
if (node === null || node === undefined) {
throw new Error('Failed to find public node')
} else if (node.isDir()) {
throw new Error('Expected node to be a file')
}

return await node
.asFile()
.readAt(
options?.offset ?? 0,
options?.length ?? undefined,
wnfsBlockStore
)
}
}

export const publicReadFromCID = (
cid: CID,
options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
) => {
return async (context: PublicContext): Promise<Uint8Array> => {
return await Unix.exportFile(cid, context.blockstore, options)
Expand Down Expand Up @@ -243,46 +254,51 @@ export const privateListDirectoryWithKind = () => {
}
}

export const privateRead = (_options?: { offset: number; length: number }) => {
export const privateRead = (options?: { offset?: number; length?: number }) => {
return async (params: PrivateParams): Promise<Uint8Array> => {
// TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs
// const offset = options?.offset
// const length = options?.length
let node

let bytes
if (params.node.isDir()) {
if (params.remainder.length === 0) {
throw new Error('Expected node to be a file')
}

if (params.node.isFile()) {
bytes = await params.node
.asFile()
.getContent(
params.rootTree.privateForest(),
Store.wnfs(params.blockstore)
)
} else {
const { result } = await params.node
const tmpNode: PrivateNode | null | undefined = await params.node
.asDir()
.read(
.getNode(
params.remainder,
searchLatest(),
params.rootTree.privateForest(),
Store.wnfs(params.blockstore)
)
bytes = result

if (tmpNode === null || tmpNode === undefined) {
throw new Error('Failed to find private node')
} else if (tmpNode.isDir()) {
throw new Error('Expected node to be a file')
}

node = tmpNode
} else {
node = params.node
}

return bytes
return await node
.asFile()
.readAt(
options?.offset ?? 0,
options?.length ?? undefined,
params.rootTree.privateForest(),
Store.wnfs(params.blockstore)
)
}
}

export const privateReadFromAccessKey = (
accessKey: AccessKey,
_options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
) => {
return async (context: PrivateContext): Promise<Uint8Array> => {
// TODO: Respect `offset` and `length` options when private streaming API is exposed in rs-wnfs
// const offset = options?.offset
// const length = options?.length

// Retrieve node
const node = await PrivateNode.load(
accessKey,
Expand All @@ -294,7 +310,9 @@ export const privateReadFromAccessKey = (
const file: PrivateFile = node.asFile()

// TODO: Respect the offset and length options when available in rs-wnfs
return await file.getContent(
return await file.readAt(
options?.offset ?? 0,
options?.length ?? undefined,
context.rootTree.privateForest(),
Store.wnfs(context.blockstore)
)
Expand Down
7 changes: 6 additions & 1 deletion packages/nest/src/references.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ export async function contentCID(

const maybeNode: PublicNode | undefined = result ?? undefined
return maybeNode?.isFile() === true
? CID.decode(maybeNode.asFile().contentCid())
? CID.decode(
await maybeNode
.asFile()
.getRawContentCid(wnfsBlockstore)
.then((u) => u as Uint8Array)
)
: undefined
}

Expand Down
18 changes: 10 additions & 8 deletions packages/nest/src/store.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import type { Blockstore } from 'interface-blockstore'
import type { BlockStore as WnfsBlockStore } from 'wnfs'

import { CID } from 'multiformats/cid'
import { sha256 } from 'multiformats/hashes/sha2'

// 🧩

export interface WnfsBlockStore {
getBlock: (cid: Uint8Array) => Promise<Uint8Array | undefined>
putBlock: (bytes: Uint8Array, code: number) => Promise<Uint8Array>
}
export type { BlockStore as WnfsBlockStore } from 'wnfs'

// 🛠️

Expand All @@ -24,10 +22,14 @@ export function wnfs(blockstore: Blockstore): WnfsBlockStore {
return await blockstore.get(decodedCid)
},

async putBlock(bytes: Uint8Array, code: number): Promise<Uint8Array> {
const c = await cid(bytes, code)
await blockstore.put(c, bytes)
return c.bytes
async hasBlock(cid: Uint8Array): Promise<boolean> {
const decodedCid = CID.decode(cid)
return await blockstore.has(decodedCid)
},

async putBlockKeyed(cid: Uint8Array, bytes: Uint8Array): Promise<void> {
const decodedCid = CID.decode(cid)
await blockstore.put(decodedCid, bytes)
},
}
}
Expand Down
16 changes: 12 additions & 4 deletions packages/nest/src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export class TransactionContext {
capsuleKey: Uint8Array
},
dataType: DataType,
options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
): Promise<DataForType<D, V>>
async read<V = unknown>(
arg:
Expand All @@ -257,7 +257,7 @@ export class TransactionContext {
capsuleKey: Uint8Array
},
dataType: DataType,
options?: { offset: number; length: number }
options?: { offset?: number; length?: number }
): Promise<AnySupportedDataType<V>> {
let bytes

Expand All @@ -268,14 +268,22 @@ export class TransactionContext {
options
)(this.#publicContext())
} else if ('capsuleCID' in arg) {
const wnfsBlockstore = Store.wnfs(this.#blockstore)

// Public content from capsule CID
const publicFile: PublicFile = await PublicFile.load(
arg.capsuleCID.bytes,
Store.wnfs(this.#blockstore)
wnfsBlockstore
)

return await this.read<DataType, V>(
{ contentCID: CID.decode(publicFile.contentCid()) },
{
contentCID: CID.decode(
await publicFile
.getRawContentCid(wnfsBlockstore)
.then((u) => u as Uint8Array)
),
},
dataType,
options
)
Expand Down
Loading

0 comments on commit c774541

Please sign in to comment.