-
Notifications
You must be signed in to change notification settings - Fork 8
feat: add support for optional unixfs file link writer in create file #62
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
base: main
Are you sure you want to change the base?
Changes from all commits
9b29bd1
a6e23b1
2150521
a33ec24
cb99618
0d339b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -13,6 +13,7 @@ import * as Queue from "./layout/queue.js" | |||||||||||||||||||||||||||||||||||||||||||||||
* readonly metadata: UnixFS.Metadata | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly config: API.EncoderSettings<Layout> | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly writer: API.BlockWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly unixFsFileLinkWriter?: API.UnixFsFileLinkWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* chunker: Chunker.Chunker | ||||||||||||||||||||||||||||||||||||||||||||||||
* layout: Layout | ||||||||||||||||||||||||||||||||||||||||||||||||
* nodeQueue: Queue.Queue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -25,6 +26,7 @@ import * as Queue from "./layout/queue.js" | |||||||||||||||||||||||||||||||||||||||||||||||
* readonly metadata: UnixFS.Metadata | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly config: API.EncoderSettings<Layout> | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly writer: API.BlockWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly unixFsFileLinkWriter?: API.UnixFsFileLinkWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly rootID: Layout.NodeID | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly end?: Task.Fork<void, never> | ||||||||||||||||||||||||||||||||||||||||||||||||
* chunker?: null | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -39,6 +41,7 @@ import * as Queue from "./layout/queue.js" | |||||||||||||||||||||||||||||||||||||||||||||||
* readonly metadata: UnixFS.Metadata | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly config: API.EncoderSettings<Layout> | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly writer: API.BlockWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly unixFsFileLinkWriter?: API.UnixFsFileLinkWriter | ||||||||||||||||||||||||||||||||||||||||||||||||
* readonly link: Layout.Link | ||||||||||||||||||||||||||||||||||||||||||||||||
* chunker?: null | ||||||||||||||||||||||||||||||||||||||||||||||||
* layout?: null | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -63,6 +66,7 @@ import * as Queue from "./layout/queue.js" | |||||||||||||||||||||||||||||||||||||||||||||||
* |{type:"write", bytes:Uint8Array} | ||||||||||||||||||||||||||||||||||||||||||||||||
* |{type:"link", link:API.EncodedFile} | ||||||||||||||||||||||||||||||||||||||||||||||||
* |{type:"block"} | ||||||||||||||||||||||||||||||||||||||||||||||||
* |{type:"fileLink"} | ||||||||||||||||||||||||||||||||||||||||||||||||
* |{type: "close"} | ||||||||||||||||||||||||||||||||||||||||||||||||
* |{type: "end"} | ||||||||||||||||||||||||||||||||||||||||||||||||
* } Message | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -82,6 +86,9 @@ export const update = (message, state) => { | |||||||||||||||||||||||||||||||||||||||||||||||
/* c8 ignore next 2 */ | ||||||||||||||||||||||||||||||||||||||||||||||||
case "block": | ||||||||||||||||||||||||||||||||||||||||||||||||
return { state, effect: Task.none() } | ||||||||||||||||||||||||||||||||||||||||||||||||
/* c8 ignore next 2 */ | ||||||||||||||||||||||||||||||||||||||||||||||||
case "fileLink": | ||||||||||||||||||||||||||||||||||||||||||||||||
return { state, effect: Task.none() } | ||||||||||||||||||||||||||||||||||||||||||||||||
case "close": | ||||||||||||||||||||||||||||||||||||||||||||||||
return close(state) | ||||||||||||||||||||||||||||||||||||||||||||||||
case "end": | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -96,9 +103,10 @@ export const update = (message, state) => { | |||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.BlockWriter} writer | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {UnixFS.Metadata} metadata | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.EncoderSettings} config | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.InitOptions} [options] | ||||||||||||||||||||||||||||||||||||||||||||||||
* @returns {State<Layout>} | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
export const init = (writer, metadata, config) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
export const init = (writer, metadata, config, options = {}) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||
status: "open", | ||||||||||||||||||||||||||||||||||||||||||||||||
metadata, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -116,6 +124,7 @@ export const init = (writer, metadata, config) => { | |||||||||||||||||||||||||||||||||||||||||||||||
// overhead. | ||||||||||||||||||||||||||||||||||||||||||||||||
// @see https://github.com/Gozala/vectrie | ||||||||||||||||||||||||||||||||||||||||||||||||
nodeQueue: Queue.mutable(), | ||||||||||||||||||||||||||||||||||||||||||||||||
unixFsFileLinkWriter: options.unixFsFileLinkWriter, | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -188,11 +197,23 @@ export const link = (state, { id, link, block }) => { | |||||||||||||||||||||||||||||||||||||||||||||||
? state.end.resume() | ||||||||||||||||||||||||||||||||||||||||||||||||
: Task.none() | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
if (!state.unixFsFileLinkWriter) { | ||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||
state: newState, | ||||||||||||||||||||||||||||||||||||||||||||||||
effect: Task.listen({ | ||||||||||||||||||||||||||||||||||||||||||||||||
link: Task.effects(tasks), | ||||||||||||||||||||||||||||||||||||||||||||||||
block: writeBlock(state.writer, block), | ||||||||||||||||||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||||||||||||||||
state: newState, | ||||||||||||||||||||||||||||||||||||||||||||||||
effect: Task.listen({ | ||||||||||||||||||||||||||||||||||||||||||||||||
link: Task.effects(tasks), | ||||||||||||||||||||||||||||||||||||||||||||||||
block: writeBlock(state.writer, block), | ||||||||||||||||||||||||||||||||||||||||||||||||
fileLink: writeFileLink(state.unixFsFileLinkWriter, link), | ||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+200
to
+216
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Nit: This feels more straightforward to me personally. P.S.: See my other more comments that make this remark obsolete |
||||||||||||||||||||||||||||||||||||||||||||||||
end, | ||||||||||||||||||||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -203,7 +224,7 @@ export const link = (state, { id, link, block }) => { | |||||||||||||||||||||||||||||||||||||||||||||||
* @param {State<Layout>} state | ||||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Update<Layout>} | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
export const close = state => { | ||||||||||||||||||||||||||||||||||||||||||||||||
export const close = (state) => { | ||||||||||||||||||||||||||||||||||||||||||||||||
if (state.status === "open") { | ||||||||||||||||||||||||||||||||||||||||||||||||
const { chunks } = Chunker.close(state.chunker) | ||||||||||||||||||||||||||||||||||||||||||||||||
const { layout, ...write } = state.config.fileLayout.write( | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -269,7 +290,7 @@ export const close = state => { | |||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.EncoderSettings} config | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
const encodeLeaves = (leaves, config) => | ||||||||||||||||||||||||||||||||||||||||||||||||
leaves.map(leaf => encodeLeaf(config, leaf, config.fileChunkEncoder)) | ||||||||||||||||||||||||||||||||||||||||||||||||
leaves.map((leaf) => encodeLeaf(config, leaf, config.fileChunkEncoder)) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.EncoderSettings} config | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -286,6 +307,7 @@ const encodeLeaf = function* ({ hasher, linker }, { id, content }, encoder) { | |||||||||||||||||||||||||||||||||||||||||||||||
const link = /** @type {UnixFS.FileLink} */ ({ | ||||||||||||||||||||||||||||||||||||||||||||||||
cid, | ||||||||||||||||||||||||||||||||||||||||||||||||
contentByteLength: content ? content.byteLength : 0, | ||||||||||||||||||||||||||||||||||||||||||||||||
contentByteOffset: content ? content.byteOffset : 0, | ||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. propagates offset to be able to map original content byte offset |
||||||||||||||||||||||||||||||||||||||||||||||||
dagByteLength: bytes.byteLength, | ||||||||||||||||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -297,7 +319,7 @@ const encodeLeaf = function* ({ hasher, linker }, { id, content }, encoder) { | |||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.EncoderSettings} config | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
const encodeBranches = (nodes, config) => | ||||||||||||||||||||||||||||||||||||||||||||||||
nodes.map(node => encodeBranch(config, node)) | ||||||||||||||||||||||||||||||||||||||||||||||||
nodes.map((node) => encodeBranch(config, node)) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||
* @template Layout | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -338,13 +360,30 @@ export const writeBlock = function* (writer, block) { | |||||||||||||||||||||||||||||||||||||||||||||||
writer.write(block) | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {API.UnixFsFileLinkWriter} writer | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {Layout.Link} link | ||||||||||||||||||||||||||||||||||||||||||||||||
* @returns {Task.Task<void, never>} | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
export const writeFileLink = function* (writer, link) { | ||||||||||||||||||||||||||||||||||||||||||||||||
/* c8 ignore next 3 */ | ||||||||||||||||||||||||||||||||||||||||||||||||
if (!writer) { | ||||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
if ((writer.desiredSize || 0) <= 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||
yield* Task.wait(writer.ready) | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
writer.write(link) | ||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||
* @param {Uint8Array|Chunker.Chunk} buffer | ||||||||||||||||||||||||||||||||||||||||||||||||
* @returns | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||
const asUint8Array = buffer => | ||||||||||||||||||||||||||||||||||||||||||||||||
const asUint8Array = (buffer) => | ||||||||||||||||||||||||||||||||||||||||||||||||
buffer instanceof Uint8Array | ||||||||||||||||||||||||||||||||||||||||||||||||
? buffer | ||||||||||||||||||||||||||||||||||||||||||||||||
: buffer.copyTo(new Uint8Array(buffer.byteLength), 0) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -353,4 +392,4 @@ const asUint8Array = buffer => | |||||||||||||||||||||||||||||||||||||||||||||||
* @param {Layout.Node} node | ||||||||||||||||||||||||||||||||||||||||||||||||
* @returns {node is Layout.Leaf} | ||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||
const isLeafNode = node => node.children == null | ||||||||||||||||||||||||||||||||||||||||||||||||
const isLeafNode = (node) => node.children == null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would personally suggest different API design. Specifically instead of passing another stream to write links to I would simply defined something like
That way current consumer can continue using API as is while consumers interested in links could use
.link
to get it. Also streams have.tee()
method allowing to have two different consumers if desired.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kind of regret not just making stream
EncodedFile
in which case we would not have this problem in first place, but perhaps switching to that as breaking change could be another way this could be introduced. You could still have something likecreateFileBlockWriter
for old code and new code could usecreateFileWriter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually thinking more about it I think it would be best to:
createEncodedFileWriter
that takesWriter<EncodedFile>
.createFileBlockWriter
that basically usescreateEncodedFileWriter
and maps values to.block
.createFileWriter
with a deprecation messages suggesting to use one of the above twoI think this would create good migration path without having to introduce additional code paths or complexity.