From 723191cf5a15b43b8938cf74c6151ccace7f35c8 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Sun, 12 Nov 2023 16:24:33 +0200 Subject: [PATCH 1/7] add io module --- get.mjs | 13 +---- index.mjs | 151 +++++------------------------------------------------- io.mjs | 42 +++++++++++++++ 3 files changed, 56 insertions(+), 150 deletions(-) create mode 100644 io.mjs diff --git a/get.mjs b/get.mjs index b8500a2..868aab7 100644 --- a/get.mjs +++ b/get.mjs @@ -62,12 +62,6 @@ const { tailToDigest } = digest256 * }} Provider */ -/** @type {(address: Address) => string} */ -const getPath = ([address, isRoot]) => { - const dir = isRoot ? 'roots' : 'parts' - return `cdt0/${dir}/${address.substring(0, 2)}/${address.substring(2, 4)}/${address.substring(4)}` -} - /** @type {(state: State) => (block: Block) => void} */ const insertBlock = state => block => { for (let i = 0; i < state.length; i++) { @@ -138,10 +132,6 @@ const nextState = state => { } } -/** @type {(hostName: string) => (address: Address) => Promise} */ -const fetchRead = hostName => address => fetch(`https://${hostName}/${getPath(address)}`) - .then(async (resp) => resp.arrayBuffer().then(buffer => new Uint8Array(buffer))) - /** @type {(provider: Provider) => (root: string) => Promise} */ const get = ({ read, write }) => async (root) => { /** @type {State} */ @@ -194,6 +184,5 @@ const get = ({ read, write }) => async (root) => { } export default { - get, - fetchRead + get } \ No newline at end of file diff --git a/index.mjs b/index.mjs index e6be857..e0d8155 100644 --- a/index.mjs +++ b/index.mjs @@ -1,63 +1,14 @@ -import fs from 'node:fs' -import fsPromises from 'node:fs/promises' -import base32 from './base32.mjs' -import tree from './tree.mjs' -import digest256 from './digest256.mjs' +import { writeFile } from 'fs' import getModule from './get.mjs' +import ioModule from './io.mjs' /** @typedef {import('./tree.mjs').State} StateTree */ /** * @template T * @typedef {import('./subtree.mjs').Nullable} Nullable */ -const { toAddress } = base32 -const { push: pushTree, end: endTree, partialEnd: partialEndTree, pushDigest } = tree -const { tailToDigest } = digest256 -const { get, fetchRead } = getModule - -/** - * second element is root flag - * @typedef {readonly [string, boolean]} Address - */ - -/** - * @typedef {[Address, Uint8Array]} Block - */ - -/** - * @template T - * @typedef {readonly['ok', T]} Ok - */ - -/** - * @template E - * @typedef {readonly['error', E]} Error - */ - -/** - * @template T - * @template E - * @typedef {Ok|Error} Result - */ - -/** - * @typedef {readonly Uint8Array[]} OkOutput - */ - -/** - * @typedef { Result } Output -*/ - -/** - * @typedef { Uint8Array } ReadonlyUint8Array - */ - -/** - * @typedef {[Address, Nullable]} BlockState - */ - -/** - * @typedef { BlockState[] } State -*/ +/** @typedef {import('./get.mjs').Address} Address */ +const { get } = getModule +const { getPath, createFile, readFile, readFileSync, appendFile, appendFileSync, renameFile, fetchRead } = ioModule /** * @typedef {{ @@ -66,112 +17,36 @@ const { get, fetchRead } = getModule * }} Provider */ -/** @type {(address: Address) => string} */ -const getPath = ([address, isRoot]) => { - const dir = isRoot ? 'roots' : 'parts' - return `cdt0/${dir}/${address.substring(0, 2)}/${address.substring(2, 4)}/${address.substring(4)}` -} - -/** @type {(state: State) => (block: Block) => void} */ -const insertBlock = state => block => { - for (let i = 0; i < state.length; i++) { - if (state[i][0][0] === block[0][0]) { - state[i][1] = block[1] - } - } -} - -/** @type {(state: State) => Output} */ -const nextState = state => { - /** @type {Uint8Array[]} */ - let resultBuffer = [] - - while (true) { - const blockLast = state.at(-1) - if (blockLast === undefined) { - return ['ok', resultBuffer] - } - - const blockData = blockLast[1] - if (blockData === null) { - return ['ok', resultBuffer] - } - - state.pop() - - if (blockLast[0][0] === '') { - resultBuffer.push(blockData) - continue - } - - /** @type {StateTree} */ - let verificationTree = [] - const tailLength = blockData[0] - if (tailLength === 32) { - const data = blockData.subarray(1) - for (let byte of data) { - pushTree(verificationTree)(byte) - } - resultBuffer.push(data) - } else { - const tail = blockData.subarray(1, tailLength + 1) - if (tail.length !== 0) { - state.push([['', false], tail]) - } - /** @type {Address[]} */ - let childAddresses = [] - for (let i = tailLength + 1; i < blockData.length; i += 28) { - let hash = 0n - for (let j = 0; j < 28; j++) { - hash += BigInt(blockData[i + j]) << BigInt(8 * j) - } - pushDigest(verificationTree)(hash | (0xffff_ffffn << 224n)) - const childAddress = toAddress(hash) - childAddresses.push([childAddress, false]) - } - pushDigest(verificationTree)(tailToDigest(tail)) - const digest = blockLast[0][1] ? endTree(verificationTree) : partialEndTree(verificationTree) - if (digest === null || toAddress(digest) !== blockLast[0][0]) { - return ['error', `verification failed ${blockLast[0][0]}`] - } - - for (let i = childAddresses.length - 1; i >= 0; i--) { - state.push([childAddresses[i], null]) - } - } - } -} - /** @type {(hostName: string) => Provider} */ const fetchProvider = hostName => ({ read: fetchRead(hostName), - write: path => buffer => fsPromises.appendFile(path, buffer) + write: path => buffer => appendFile(path)(buffer) }) /** @type {Provider} */ const asyncFileProvider = { - read: address => fsPromises.readFile(getPath(address)), - write: path => buffer => fsPromises.appendFile(path, buffer) + read: address => readFile(getPath(address)), + write: path => buffer => appendFile(path)(buffer) } /** @type {Provider} */ const syncFileProvider = { - read: address => Promise.resolve(fs.readFileSync(getPath(address))), - write: path => buffer => Promise.resolve(fs.appendFileSync(path, buffer)) + read: address => Promise.resolve(readFileSync(getPath(address))), + write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)) } /** @type {(provider: Provider) => (root: [string, string]) => Promise} */ const getLocal = ({ read, write }) => async ([root, file]) => { const tempFile = `_temp_${root}` - await fsPromises.writeFile(tempFile, new Uint8Array()) + await createFile(tempFile) /** @type {(buffer: Uint8Array) => Promise} */ - const write = buffer => fsPromises.appendFile(tempFile, buffer) + const write = buffer => appendFile(tempFile)(buffer) const error = await get({ read, write })(root) if (error !== null) { console.error(error) return -1 } - await fsPromises.rename(tempFile, file) + await renameFile(tempFile)(file) return 0 } diff --git a/io.mjs b/io.mjs new file mode 100644 index 0000000..0198044 --- /dev/null +++ b/io.mjs @@ -0,0 +1,42 @@ +import fs from 'node:fs' +import fsPromises from 'node:fs/promises' +/** @typedef {import('./get.mjs').Address} Address */ + +/** @type {(address: Address) => string} */ +const getPath = ([address, isRoot]) => { + const dir = isRoot ? 'roots' : 'parts' + return `cdt0/${dir}/${address.substring(0, 2)}/${address.substring(2, 4)}/${address.substring(4)}` +} + +/** @type {(path: string) => Promise} */ +const createFile = path => fsPromises.writeFile(path, new Uint8Array()) + +/** @type {(path: string) => Promise} */ +const readFile = path => fsPromises.readFile(path) + +/** @type {(path: string) => Promise} */ +const readFileSync = path => Promise.resolve(fs.readFileSync(path)) + +/** @type {(path: string) => (buffer: Uint8Array) => Promise} */ +const appendFile = path => buffer => fsPromises.appendFile(path, buffer) + +/** @type {(path: string) => (buffer: Uint8Array) => Promise} */ +const appendFileSync = path => buffer => Promise.resolve(fs.appendFileSync(path, buffer)) + +/** @type {(oldPath: string) => (newPath: string) => Promise} */ +const renameFile = oldPath => newPath => fsPromises.rename(oldPath, newPath) + +/** @type {(hostName: string) => (address: Address) => Promise} */ +const fetchRead = hostName => address => fetch(`https://${hostName}/${getPath(address)}`) + .then(async (resp) => resp.arrayBuffer().then(buffer => new Uint8Array(buffer))) + +export default { + getPath, + createFile, + readFile, + readFileSync, + appendFile, + appendFileSync, + renameFile, + fetchRead +} \ No newline at end of file From b4811e446056b50f010d75db5dd9dc09d78dd8d7 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Sun, 12 Nov 2023 16:31:35 +0200 Subject: [PATCH 2/7] remove import fs from index --- index.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.mjs b/index.mjs index e0d8155..35d7ce4 100644 --- a/index.mjs +++ b/index.mjs @@ -1,4 +1,3 @@ -import { writeFile } from 'fs' import getModule from './get.mjs' import ioModule from './io.mjs' /** @typedef {import('./tree.mjs').State} StateTree */ From 6eb5d4999459b5f45c29c1b1b32072447725a67a Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Sun, 12 Nov 2023 18:16:53 +0200 Subject: [PATCH 3/7] remove providers from index --- cli.mjs | 4 +++- index.mjs | 37 +++++-------------------------------- io.mjs | 30 +++++++++++++++++++++++++++++- test.mjs | 4 +++- 4 files changed, 40 insertions(+), 35 deletions(-) diff --git a/cli.mjs b/cli.mjs index 3c00e60..f704d57 100644 --- a/cli.mjs +++ b/cli.mjs @@ -1,7 +1,9 @@ #!/usr/bin/env node import index from './index.mjs' -const { get, asyncFileProvider, fetchProvider } = index +import io from './io.mjs' +const { get } = index +const { asyncFileProvider, fetchProvider } = io var args = process.argv.slice(2) diff --git a/index.mjs b/index.mjs index 35d7ce4..227fd99 100644 --- a/index.mjs +++ b/index.mjs @@ -6,41 +6,17 @@ import ioModule from './io.mjs' * @typedef {import('./subtree.mjs').Nullable} Nullable */ /** @typedef {import('./get.mjs').Address} Address */ +/** @typedef {import('./io.mjs').Provider} Provider */ const { get } = getModule -const { getPath, createFile, readFile, readFileSync, appendFile, appendFileSync, renameFile, fetchRead } = ioModule - -/** - * @typedef {{ - * readonly read: (address: Address) => Promise, - * readonly write: (path: string) => (buffer: Uint8Array) => Promise, - * }} Provider -*/ - -/** @type {(hostName: string) => Provider} */ -const fetchProvider = hostName => ({ - read: fetchRead(hostName), - write: path => buffer => appendFile(path)(buffer) -}) - -/** @type {Provider} */ -const asyncFileProvider = { - read: address => readFile(getPath(address)), - write: path => buffer => appendFile(path)(buffer) -} - -/** @type {Provider} */ -const syncFileProvider = { - read: address => Promise.resolve(readFileSync(getPath(address))), - write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)) -} +const { createFile, renameFile } = ioModule /** @type {(provider: Provider) => (root: [string, string]) => Promise} */ const getLocal = ({ read, write }) => async ([root, file]) => { const tempFile = `_temp_${root}` await createFile(tempFile) /** @type {(buffer: Uint8Array) => Promise} */ - const write = buffer => appendFile(tempFile)(buffer) - const error = await get({ read, write })(root) + const writeTempFile = buffer => write(tempFile)(buffer) + const error = await get({ read, write: writeTempFile })(root) if (error !== null) { console.error(error) return -1 @@ -50,8 +26,5 @@ const getLocal = ({ read, write }) => async ([root, file]) => { } export default { - get: getLocal, - syncFileProvider, - asyncFileProvider, - fetchProvider + get: getLocal } \ No newline at end of file diff --git a/io.mjs b/io.mjs index 0198044..a35fb4d 100644 --- a/io.mjs +++ b/io.mjs @@ -2,6 +2,13 @@ import fs from 'node:fs' import fsPromises from 'node:fs/promises' /** @typedef {import('./get.mjs').Address} Address */ +/** + * @typedef {{ +* readonly read: (address: Address) => Promise, +* readonly write: (path: string) => (buffer: Uint8Array) => Promise, +* }} Provider +*/ + /** @type {(address: Address) => string} */ const getPath = ([address, isRoot]) => { const dir = isRoot ? 'roots' : 'parts' @@ -30,6 +37,24 @@ const renameFile = oldPath => newPath => fsPromises.rename(oldPath, newPath) const fetchRead = hostName => address => fetch(`https://${hostName}/${getPath(address)}`) .then(async (resp) => resp.arrayBuffer().then(buffer => new Uint8Array(buffer))) +/** @type {(hostName: string) => Provider} */ +const fetchProvider = hostName => ({ + read: fetchRead(hostName), + write: path => buffer => appendFile(path)(buffer) +}) + +/** @type {Provider} */ +const asyncFileProvider = { + read: address => readFile(getPath(address)), + write: path => buffer => appendFile(path)(buffer) +} + +/** @type {Provider} */ +const syncFileProvider = { + read: address => Promise.resolve(readFileSync(getPath(address))), + write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)) +} + export default { getPath, createFile, @@ -38,5 +63,8 @@ export default { appendFile, appendFileSync, renameFile, - fetchRead + fetchRead, + fetchProvider, + asyncFileProvider, + syncFileProvider } \ No newline at end of file diff --git a/test.mjs b/test.mjs index 15ac7b7..72c04b5 100644 --- a/test.mjs +++ b/test.mjs @@ -4,6 +4,7 @@ import digest256 from './digest256.mjs' import subtree from './subtree.mjs' import tree from './tree.mjs' import index from './index.mjs' +import io from './io.mjs' import fs from 'node:fs' import fsPromises from 'node:fs/promises' /** @typedef {import('./subtree.mjs').State} StateSubTree */ @@ -14,7 +15,8 @@ const { compress } = sha224 const { merge, byteToDigest, len } = digest256 const { highestOne256, height, push: pushSubTree } = subtree const { push: pushTree, end: endTree } = tree -const { get, syncFileProvider, asyncFileProvider, fetchProvider } = index +const { get } = index +const { syncFileProvider, asyncFileProvider, fetchProvider } = io console.log(`test start`) From 1c81813ce20128ad208e148c9523429efb2a90e8 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Sun, 12 Nov 2023 19:06:26 +0200 Subject: [PATCH 4/7] io provider --- index.mjs | 8 +++----- io.mjs | 14 +++++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/index.mjs b/index.mjs index 227fd99..e52e017 100644 --- a/index.mjs +++ b/index.mjs @@ -1,5 +1,4 @@ import getModule from './get.mjs' -import ioModule from './io.mjs' /** @typedef {import('./tree.mjs').State} StateTree */ /** * @template T @@ -8,12 +7,11 @@ import ioModule from './io.mjs' /** @typedef {import('./get.mjs').Address} Address */ /** @typedef {import('./io.mjs').Provider} Provider */ const { get } = getModule -const { createFile, renameFile } = ioModule /** @type {(provider: Provider) => (root: [string, string]) => Promise} */ -const getLocal = ({ read, write }) => async ([root, file]) => { +const getLocal = ({ read, write, create, rename }) => async ([root, file]) => { const tempFile = `_temp_${root}` - await createFile(tempFile) + await create(tempFile) /** @type {(buffer: Uint8Array) => Promise} */ const writeTempFile = buffer => write(tempFile)(buffer) const error = await get({ read, write: writeTempFile })(root) @@ -21,7 +19,7 @@ const getLocal = ({ read, write }) => async ([root, file]) => { console.error(error) return -1 } - await renameFile(tempFile)(file) + await rename(tempFile)(file) return 0 } diff --git a/io.mjs b/io.mjs index a35fb4d..5ad397a 100644 --- a/io.mjs +++ b/io.mjs @@ -6,6 +6,8 @@ import fsPromises from 'node:fs/promises' * @typedef {{ * readonly read: (address: Address) => Promise, * readonly write: (path: string) => (buffer: Uint8Array) => Promise, +* readonly create: (path: string) => Promise, +* readonly rename: (oldPath: string) => (newPath: string) => Promise * }} Provider */ @@ -40,19 +42,25 @@ const fetchRead = hostName => address => fetch(`https://${hostName}/${getPath(ad /** @type {(hostName: string) => Provider} */ const fetchProvider = hostName => ({ read: fetchRead(hostName), - write: path => buffer => appendFile(path)(buffer) + write: path => buffer => appendFile(path)(buffer), + create: path => createFile(path), + rename: oldPath => newPath => renameFile(oldPath)(newPath) }) /** @type {Provider} */ const asyncFileProvider = { read: address => readFile(getPath(address)), - write: path => buffer => appendFile(path)(buffer) + write: path => buffer => appendFile(path)(buffer), + create: path => createFile(path), + rename: oldPath => newPath => renameFile(oldPath)(newPath) } /** @type {Provider} */ const syncFileProvider = { read: address => Promise.resolve(readFileSync(getPath(address))), - write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)) + write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)), + create: path => createFile(path), + rename: oldPath => newPath => renameFile(oldPath)(newPath) } export default { From 0ada1684c187289e8e1d760fbc487427876d3175 Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Mon, 13 Nov 2023 23:03:06 +0200 Subject: [PATCH 5/7] io modules --- cli.mjs | 10 +++---- index.mjs | 48 ++++++++++++++++++++++++++------ io.mjs | 78 ---------------------------------------------------- io/io.mjs | 12 ++++++++ io/node.mjs | 26 ++++++++++++++++++ io/web.mjs | 16 +++++++++++ test.mjs | 24 ++++++++-------- web-test.mjs | 8 ++++-- 8 files changed, 117 insertions(+), 105 deletions(-) delete mode 100644 io.mjs create mode 100644 io/io.mjs create mode 100644 io/node.mjs create mode 100644 io/web.mjs diff --git a/cli.mjs b/cli.mjs index f704d57..fa4d65b 100644 --- a/cli.mjs +++ b/cli.mjs @@ -1,9 +1,9 @@ #!/usr/bin/env node import index from './index.mjs' -import io from './io.mjs' -const { get } = index -const { asyncFileProvider, fetchProvider } = io +import ioNode from './io/node.mjs' +const { getLocal, getRemote } = index +const { node } = ioNode var args = process.argv.slice(2) @@ -14,5 +14,5 @@ if (args.length < 2) { } const hostName = args[2] -const provider = hostName === undefined ? asyncFileProvider : fetchProvider(hostName) -get(provider)([args[0], args[1]]) \ No newline at end of file +const getFunc = hostName === undefined ? getLocal : getRemote(hostName) +getFunc(node)([args[0], args[1]]) \ No newline at end of file diff --git a/index.mjs b/index.mjs index e52e017..59be171 100644 --- a/index.mjs +++ b/index.mjs @@ -5,24 +5,56 @@ import getModule from './get.mjs' * @typedef {import('./subtree.mjs').Nullable} Nullable */ /** @typedef {import('./get.mjs').Address} Address */ -/** @typedef {import('./io.mjs').Provider} Provider */ +/** @typedef {import('./io/io.mjs').IO} IO */ + const { get } = getModule -/** @type {(provider: Provider) => (root: [string, string]) => Promise} */ -const getLocal = ({ read, write, create, rename }) => async ([root, file]) => { +/** @type {(address: Address) => string} */ +const getPath = ([address, isRoot]) => { + const dir = isRoot ? 'roots' : 'parts' + return `cdt0/${dir}/${address.substring(0, 2)}/${address.substring(2, 4)}/${address.substring(4)}` +} + +/** @type {(hostName: string) => (io: IO) => (address: Address) => Promise} */ +const fetchRead = hostName => ({ fetch }) => address => fetch(`https://${hostName}/${getPath(address)}`) + .then(async (resp) => resp.arrayBuffer().then(buffer => new Uint8Array(buffer))) + +/** @type {(io: IO) => (root: [string, string]) => Promise} */ +const getLocal = io => async ([root, file]) => { + const tempFile = `_temp_${root}` + await io.write(tempFile, new Uint8Array()) + /** @type {(address: Address) => Promise} */ + const read = address => io.read(getPath(address)) + /** @type {(buffer: Uint8Array) => Promise} */ + const write = buffer => io.append(tempFile, buffer) + const error = await get({ read, write })(root) + if (error !== null) { + console.error(error) + return -1 + } + await io.rename(tempFile, file) + return 0 +} + +/** @type {(host: string) => (io: IO) => (root: [string, string]) => Promise} */ +const getRemote = host => io => async ([root, file]) => { const tempFile = `_temp_${root}` - await create(tempFile) + await io.write(tempFile, new Uint8Array()) + /** @type {(address: Address) => Promise} */ + const read = fetchRead(host)(io) /** @type {(buffer: Uint8Array) => Promise} */ - const writeTempFile = buffer => write(tempFile)(buffer) - const error = await get({ read, write: writeTempFile })(root) + const write = buffer => io.append(tempFile, buffer) + const error = await get({ read, write })(root) if (error !== null) { console.error(error) return -1 } - await rename(tempFile)(file) + await io.rename(tempFile, file) return 0 } export default { - get: getLocal + getLocal, + getRemote, + fetchRead } \ No newline at end of file diff --git a/io.mjs b/io.mjs deleted file mode 100644 index 5ad397a..0000000 --- a/io.mjs +++ /dev/null @@ -1,78 +0,0 @@ -import fs from 'node:fs' -import fsPromises from 'node:fs/promises' -/** @typedef {import('./get.mjs').Address} Address */ - -/** - * @typedef {{ -* readonly read: (address: Address) => Promise, -* readonly write: (path: string) => (buffer: Uint8Array) => Promise, -* readonly create: (path: string) => Promise, -* readonly rename: (oldPath: string) => (newPath: string) => Promise -* }} Provider -*/ - -/** @type {(address: Address) => string} */ -const getPath = ([address, isRoot]) => { - const dir = isRoot ? 'roots' : 'parts' - return `cdt0/${dir}/${address.substring(0, 2)}/${address.substring(2, 4)}/${address.substring(4)}` -} - -/** @type {(path: string) => Promise} */ -const createFile = path => fsPromises.writeFile(path, new Uint8Array()) - -/** @type {(path: string) => Promise} */ -const readFile = path => fsPromises.readFile(path) - -/** @type {(path: string) => Promise} */ -const readFileSync = path => Promise.resolve(fs.readFileSync(path)) - -/** @type {(path: string) => (buffer: Uint8Array) => Promise} */ -const appendFile = path => buffer => fsPromises.appendFile(path, buffer) - -/** @type {(path: string) => (buffer: Uint8Array) => Promise} */ -const appendFileSync = path => buffer => Promise.resolve(fs.appendFileSync(path, buffer)) - -/** @type {(oldPath: string) => (newPath: string) => Promise} */ -const renameFile = oldPath => newPath => fsPromises.rename(oldPath, newPath) - -/** @type {(hostName: string) => (address: Address) => Promise} */ -const fetchRead = hostName => address => fetch(`https://${hostName}/${getPath(address)}`) - .then(async (resp) => resp.arrayBuffer().then(buffer => new Uint8Array(buffer))) - -/** @type {(hostName: string) => Provider} */ -const fetchProvider = hostName => ({ - read: fetchRead(hostName), - write: path => buffer => appendFile(path)(buffer), - create: path => createFile(path), - rename: oldPath => newPath => renameFile(oldPath)(newPath) -}) - -/** @type {Provider} */ -const asyncFileProvider = { - read: address => readFile(getPath(address)), - write: path => buffer => appendFile(path)(buffer), - create: path => createFile(path), - rename: oldPath => newPath => renameFile(oldPath)(newPath) -} - -/** @type {Provider} */ -const syncFileProvider = { - read: address => Promise.resolve(readFileSync(getPath(address))), - write: path => buffer => Promise.resolve(appendFileSync(path)(buffer)), - create: path => createFile(path), - rename: oldPath => newPath => renameFile(oldPath)(newPath) -} - -export default { - getPath, - createFile, - readFile, - readFileSync, - appendFile, - appendFileSync, - renameFile, - fetchRead, - fetchProvider, - asyncFileProvider, - syncFileProvider -} \ No newline at end of file diff --git a/io/io.mjs b/io/io.mjs new file mode 100644 index 0000000..a138f37 --- /dev/null +++ b/io/io.mjs @@ -0,0 +1,12 @@ +/** + * @typedef {{ +* readonly read: (path: string) => Promise, +* readonly append: (path: string, buffer: Uint8Array) => Promise, +* readonly write: (path: string, buffer: Uint8Array) => Promise, +* readonly rename: (oldPath: string, newPath: string) => Promise +* readonly fetch: (url: string) => Promise +* }} IO +*/ + +export default { +} \ No newline at end of file diff --git a/io/node.mjs b/io/node.mjs new file mode 100644 index 0000000..b24b6d8 --- /dev/null +++ b/io/node.mjs @@ -0,0 +1,26 @@ +import fs from 'node:fs' +import fsPromises from 'node:fs/promises' +/** @typedef {import('./io.mjs').IO} IO */ + +/** @type {IO} */ +const node = { + read: fsPromises.readFile, + append: fsPromises.appendFile, + write: fsPromises.writeFile, + rename: fsPromises.rename, + fetch +} + +/** @type {IO} */ +const nodeSync = { + read: async(path) => fs.readFileSync(path), + append: async(path, buffer) => fs.appendFileSync(path, buffer), + write: async(path, buffer) => fs.writeFileSync(path, buffer), + rename: async(oldPath, newPath) => fs.renameSync(oldPath, newPath), + fetch +} + +export default { + node, + nodeSync +} \ No newline at end of file diff --git a/io/web.mjs b/io/web.mjs new file mode 100644 index 0000000..d798c0a --- /dev/null +++ b/io/web.mjs @@ -0,0 +1,16 @@ +/** @typedef {import('./io.mjs').IO} IO */ + +const notImplemented = () => { throw 'not implemented' } + +/** @type {IO} */ +const web = { + read: notImplemented, + append: notImplemented, + write: notImplemented, + rename: notImplemented, + fetch +} + +export default { + web +} \ No newline at end of file diff --git a/test.mjs b/test.mjs index 72c04b5..c9f11e9 100644 --- a/test.mjs +++ b/test.mjs @@ -4,19 +4,19 @@ import digest256 from './digest256.mjs' import subtree from './subtree.mjs' import tree from './tree.mjs' import index from './index.mjs' -import io from './io.mjs' +import ioNode from './io/node.mjs' import fs from 'node:fs' import fsPromises from 'node:fs/promises' /** @typedef {import('./subtree.mjs').State} StateSubTree */ /** @typedef {import('./tree.mjs').State} StateTree */ -/** @typedef {import('./index.mjs').Provider} Provider */ +/** @typedef {import('./io/io.mjs').IO} IO */ const { toAddress, getParityBit } = base32 const { compress } = sha224 const { merge, byteToDigest, len } = digest256 const { highestOne256, height, push: pushSubTree } = subtree const { push: pushTree, end: endTree } = tree -const { get } = index -const { syncFileProvider, asyncFileProvider, fetchProvider } = io +const { getLocal, getRemote } = index +const { node, nodeSync } = ioNode console.log(`test start`) @@ -233,9 +233,11 @@ const runTest = async (f) => { console.log(`Call to ${f.name} took ${t1 - t0} milliseconds.`); } -/** @type {(provider: Provider) => Promise} */ -const runTestsGet = async (provider) => { - const getWithProvider = get(provider) +/** @typedef {(io: IO) => (root: [string, string]) => Promise} GetFunc*/ + +/** @type {(io: IO) => (getFunc: GetFunc) => Promise} */ +const runTestsGet = io => async (getFunc) => { + const getWithProvider = getFunc(io) const testGet1 = async () => { const exitCode = await getWithProvider(['vqra44skpkefw4bq9k96xt9ks84221dmk1pzaym86cqd6', '_out_list1_async']) if (exitCode !== 0) { throw exitCode } @@ -268,15 +270,13 @@ const runTestsGet = async (provider) => { await runTest(testGetRepeat) } -const testFetchProvider = fetchProvider('410f5a49.blockset-js-test.pages.dev') - const mainTestAsync = async () => { console.log('sync provider') - await runTestsGet(syncFileProvider) + await runTestsGet(nodeSync)(getLocal) console.log('async provider') - await runTestsGet(asyncFileProvider) + await runTestsGet(node)(getLocal) console.log('fetch provider') - await runTestsGet(testFetchProvider) + await runTestsGet(node)(getRemote('410f5a49.blockset-js-test.pages.dev')) } mainTestAsync() \ No newline at end of file diff --git a/web-test.mjs b/web-test.mjs index a1236ed..f35a62c 100644 --- a/web-test.mjs +++ b/web-test.mjs @@ -1,6 +1,10 @@ import getModule from './get.mjs' +import ioWeb from './io/web.mjs' +import index from './index.mjs' /** @typedef {import('./get.mjs').Address} Address */ -const { get, fetchRead } = getModule +const { get } = getModule +const { web } = ioWeb +const { fetchRead } = index // @ts-ignore document.getElementById('download').addEventListener('click', () => { @@ -10,7 +14,7 @@ document.getElementById('download').addEventListener('click', () => { // @ts-ignore const host = document.getElementById('input-host').value let buffer = new Uint8Array() - const fRead = fetchRead(host) + const fRead = fetchRead(host)(web) /** @type {(address: Address) => Promise} */ const read = address => { // @ts-ignore From 5db36796bf2bd8d04fc39128c2ecf71859639daf Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Mon, 13 Nov 2023 23:12:11 +0200 Subject: [PATCH 6/7] add html document to io --- io/io.mjs | 1 + io/node.mjs | 6 ++++-- io/web.mjs | 3 ++- web-test.mjs | 25 +++++++++++++------------ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/io/io.mjs b/io/io.mjs index a138f37..6efdc5c 100644 --- a/io/io.mjs +++ b/io/io.mjs @@ -5,6 +5,7 @@ * readonly write: (path: string, buffer: Uint8Array) => Promise, * readonly rename: (oldPath: string, newPath: string) => Promise * readonly fetch: (url: string) => Promise +* readonly document: Document | undefined * }} IO */ diff --git a/io/node.mjs b/io/node.mjs index b24b6d8..6c6ef89 100644 --- a/io/node.mjs +++ b/io/node.mjs @@ -8,7 +8,8 @@ const node = { append: fsPromises.appendFile, write: fsPromises.writeFile, rename: fsPromises.rename, - fetch + fetch, + document: undefined } /** @type {IO} */ @@ -17,7 +18,8 @@ const nodeSync = { append: async(path, buffer) => fs.appendFileSync(path, buffer), write: async(path, buffer) => fs.writeFileSync(path, buffer), rename: async(oldPath, newPath) => fs.renameSync(oldPath, newPath), - fetch + fetch, + document: undefined } export default { diff --git a/io/web.mjs b/io/web.mjs index d798c0a..af4512e 100644 --- a/io/web.mjs +++ b/io/web.mjs @@ -8,7 +8,8 @@ const web = { append: notImplemented, write: notImplemented, rename: notImplemented, - fetch + fetch, + document } export default { diff --git a/web-test.mjs b/web-test.mjs index f35a62c..0df85cf 100644 --- a/web-test.mjs +++ b/web-test.mjs @@ -6,31 +6,32 @@ const { get } = getModule const { web } = ioWeb const { fetchRead } = index +const d = web.document // @ts-ignore -document.getElementById('download').addEventListener('click', () => { +d.getElementById('download').addEventListener('click', () => { reset() // @ts-ignore - const hash = document.getElementById('input-hash').value + const hash = d.getElementById('input-hash').value // @ts-ignore - const host = document.getElementById('input-host').value + const host = d.getElementById('input-host').value let buffer = new Uint8Array() const fRead = fetchRead(host)(web) /** @type {(address: Address) => Promise} */ const read = address => { // @ts-ignore - document.getElementById('log').innerText += `read from ${address}\n` + d.getElementById('log').innerText += `read from ${address}\n` return fRead(address) } /** @type {(b: Uint8Array) => Promise} */ const write = async (b) => { // @ts-ignore - document.getElementById('log').innerText += `write ${b.length}\n` + d.getElementById('log').innerText += `write ${b.length}\n` buffer = new Uint8Array([...buffer, ...b]) } get({ read, write })(hash).then(exitCode => { if (exitCode !== null) { // @ts-ignore - document.getElementById('log').innerText += `error exit code = ${exitCode}\n` + d.getElementById('log').innerText += `error exit code = ${exitCode}\n` return } @@ -38,22 +39,22 @@ document.getElementById('download').addEventListener('click', () => { const image = new Blob([buffer], { type: 'image/jpeg' }); const imageUrl = URL.createObjectURL(image); // @ts-ignore - document.getElementById('output-image').style.display = 'block' + d.getElementById('output-image').style.display = 'block' // @ts-ignore - document.getElementById('output-image').src = imageUrl; + d.getElementById('output-image').src = imageUrl; return } // @ts-ignore - document.getElementById('output-text').style.display = 'block' + d.getElementById('output-text').style.display = 'block' // @ts-ignore - document.getElementById('output-text').innerText = new TextDecoder().decode(buffer) + d.getElementById('output-text').innerText = new TextDecoder().decode(buffer) }) }); const reset = () => { // @ts-ignore - document.getElementById('output-image').style.display = 'none' + d.getElementById('output-image').style.display = 'none' // @ts-ignore - document.getElementById('output-text').style.display = 'none' + d.getElementById('output-text').style.display = 'none' } \ No newline at end of file From 0ac60702238aa740f1f204b5e9d96501e4ec0d5c Mon Sep 17 00:00:00 2001 From: Shandar Denys Date: Mon, 13 Nov 2023 23:14:08 +0200 Subject: [PATCH 7/7] version 0.3.0 --- .github/workflows/ci.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd8150a..8944c90 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: branches: [ "main" ] env: - VERSION: 0.2.1 + VERSION: 0.3.0 jobs: node: diff --git a/package.json b/package.json index 4125cdc..299f782 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockset-js", - "version": "0.2.1", + "version": "0.3.0", "description": "BLOCKSET on JavaScript", "keywords": ["blockset", "content-addressable", "storage", "cdt", "content-dependent-tree", "hash"], "main": "index.mjs",