diff --git a/.gitignore b/.gitignore index 5a088d9..1e5348d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules npm-debug.log package-lock.json +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ca983e9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +- 1.2.0 + - "sync" and "info" now default to non-live output. +- 1.1.0 + - Add "beam" command. + - Drives created by "sync" are now automatically seeded. +- 1.0.0 + - Initial release. \ No newline at end of file diff --git a/README.md b/README.md index a2dcf62..e2f025a 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,24 @@ -![./logo.png](./logo.png) +# NOTE +The CLI is currently mostly out of date, tracking the previous major version of the Hypercore stack. + +Check out the individual repos instead, like [Hypercore](https://github.com/hypercore-protocol/hypercore), [Hyperbee](https://github.com/hypercore-protocol/hyperbee), [Hyperbeam](https://github.com/mafintosh/hyperbeam), [Hyperswarm](https://github.com/hyperswarm) + +
Click to see the CLI README still + # Hyp +

[ + Demo Video | + Installation | + Usage | + Overview | + Website +]

+ A CLI for peer-to-peer file sharing (and more) using the [Hypercore Protocol](https://hypercore-protocol.org). -- [Installation](#installation) -- [Usage](#usage) -- [Overview](#overview) -- Guides - - [Sharing a folder](./docs/guides/sharing-a-folder.md) - - [Downloading a folder](./docs/guides/downloading-a-folder.md) - - [Keeping hypers online (seeding)](./docs/guides/seeding.md) - - [List your current seeds](./docs/guide/list-seeds.md) - - [Creating a hyperdrive](./docs/guides/creating-a-hyperdrive.md) - - [Reading a file from a hyperdrive](./docs/guides/reading-a-file.md) - - [Writing a file to a hyperdrive](./docs/guides/writing-a-file.md) - - [Diffing hyperdrives and local folders](./docs/guides/diffing-a-hyperdrive.md) -- [Glossary of terms](./docs/glossary.md) -- [API Docs](https://github.com/hypercore-protocol/hyperspace-client) +📺 Watch The Demo Video ## Installation @@ -27,6 +28,18 @@ Requires nodejs 14+ npm install -g @hyperspace/cli ``` +To start using the network, run: + +``` +hyp daemon start +``` + +This will run in the background, sync data for you, until you run: + +``` +hyp daemon stop +``` + ## Usage Command overview: @@ -41,6 +54,8 @@ General Commands: hyp unseed {urls...} - Stop making hyper data available to the network. hyp create {drive|bee} - Create a new hyperdrive or hyperbee. + hyp beam {pass_phrase} - Send a stream of data over the network. + Hyperdrive Commands: hyp drive ls {url} - List the entries of the given hyperdrive URL. @@ -66,6 +81,7 @@ Hyperbee Commands: Daemon Commands: hyp daemon status - Check the status of the hyperspace daemon. + hyp daemon start - Start the hyperspace daemon. hyp daemon stop - Stop the hyperspace and mirroring daemons if active. Aliases: @@ -118,12 +134,12 @@ To see what hypers you are currently seeding, run `info`: hyp info ``` -Further guides: +## Documentation + +The [website documentation](https://hypercore-protocol.org/guides/hyp/) have a lot of useful guides: -- [Sharing a folder](./docs/guides/sharing-a-folder.md) -- [Downloading a folder](./docs/guides/downloading-a-folder.md) -- [Keeping hypers online (seeding)](./docs/guides/seeding.md) -- [List your current seeds](./docs/guide/list-seeds.md) -- [Reading a file from a hyperdrive](./docs/guides/reading-a-file.md) -- [Writing a file to a hyperdrive](./docs/guides/writing-a-file.md) -- [Diffing hyperdrives and local folders](./docs/guides/diffing-a-hyperdrive.md) \ No newline at end of file +- [Full Commands Reference](https://hypercore-protocol.org/guides/hyp/commands/) +- [Guide: Sharing Folders](https://hypercore-protocol.org/guides/hyp/sharing-folders/) +- [Guide: Seeding Data](https://hypercore-protocol.org/guides/hyp/seeding-data/) +- [Guide: Beaming Files](https://hypercore-protocol.org/guides/hyp/beaming-files/) +
diff --git a/bin/hyp.js b/bin/hyp.js index 60e5bbf..043bdf4 100755 --- a/bin/hyp.js +++ b/bin/hyp.js @@ -1,7 +1,12 @@ #!/usr/bin/env node + +process.title = "hyp" + import subcommand from 'subcommand' import fs from 'fs' +import path from 'path' +import { fileURLToPath } from 'url' import * as hyper from '../lib/hyper/index.js' @@ -9,6 +14,7 @@ import info from '../lib/commands/info.js' import create from '../lib/commands/create.js' import seed from '../lib/commands/seed.js' import unseed from '../lib/commands/unseed.js' +import beam from '../lib/commands/beam.js' import driveLs from '../lib/commands/drive/ls.js' import driveCat from '../lib/commands/drive/cat.js' @@ -26,6 +32,7 @@ import beePut from '../lib/commands/bee/put.js' import beeDel from '../lib/commands/bee/del.js' import daemonStatus from '../lib/commands/daemon/status.js' +import daemonStart from '../lib/commands/daemon/start.js' import daemonStop from '../lib/commands/daemon/stop.js' import usage from '../lib/usage.js' @@ -38,6 +45,7 @@ const commands = { seed, unseed, create, + beam, driveLs, driveCat, @@ -55,6 +63,7 @@ const commands = { beeDel, daemonStatus, + daemonStart, daemonStop } @@ -72,7 +81,7 @@ match(argv) // error output when no/invalid command is given function none (args) { if (args.version) { - const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8')) + const packageJson = JSON.parse(fs.readFileSync(path.join(fileURLToPath(import.meta.url), '../../package.json'), 'utf8')) console.log(packageJson.version) process.exit(0) } @@ -93,9 +102,18 @@ function wrapCommand (obj) { } try { - if (!obj.name.startsWith('daemon')) { + if (!obj.name.startsWith('daemon') && obj.name !== 'beam') { await hyper.setup() } + } catch (err) { + console.error('The daemon is not active. Please run:') + console.error('') + console.error(' hyp daemon start') + console.error('') + process.exit(2) + } + + try { await innerCommand(...args) } catch (err) { console.error('Error:', err.message) diff --git a/docs/guides/beaming-data.md b/docs/guides/beaming-data.md new file mode 100644 index 0000000..40a9d82 --- /dev/null +++ b/docs/guides/beaming-data.md @@ -0,0 +1,5 @@ +# Beaming data + +This doc was moved to the website: + +https://hypercore-protocol.org/guides/hyp/beaming-files/ \ No newline at end of file diff --git a/docs/guides/creating-a-hyperdrive.md b/docs/guides/creating-a-hyperdrive.md index fe4e3ec..17e065f 100644 --- a/docs/guides/creating-a-hyperdrive.md +++ b/docs/guides/creating-a-hyperdrive.md @@ -1,9 +1,5 @@ # Creating a hyperdrive -``` -hyp create drive -``` +This doc was moved to the website: -This will output the URL of your new hyperdrive and you'll be ready to go. - -> If you're just looking to share a folder, you can [use the sync command](./sharing-a-folder.md). \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/commands/create/ \ No newline at end of file diff --git a/docs/guides/diffing-a-hyperdrive.md b/docs/guides/diffing-a-hyperdrive.md index 75cec0d..b41ed05 100644 --- a/docs/guides/diffing-a-hyperdrive.md +++ b/docs/guides/diffing-a-hyperdrive.md @@ -1,18 +1,5 @@ # Diffing hyperdrives and local folders -``` -hyp diff {source} {target} -``` +This doc was moved to the website: - - **source** A local folder path or hyperdrive URL. - - **target** A local folder path or hyperdrive URL. - -The command will output a list of all files that differ and explain how they differ. - -You can sync the target so that it matches the source by adding the `--commit` switch: - -``` -hyp diff {source} {target} --commit -``` - -This will give you a chance to review the changes about to occur, then y/n the sync. \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/commands/drive-diff/ \ No newline at end of file diff --git a/docs/guides/downloading-a-folder.md b/docs/guides/downloading-a-folder.md index 648eda2..8cbe5dc 100644 --- a/docs/guides/downloading-a-folder.md +++ b/docs/guides/downloading-a-folder.md @@ -1,18 +1,5 @@ # Downloading a folder from a hyperdrive -``` -hyp sync {source} [target] -``` +This doc was moved to the website: -- **source** The hyperdrive you want to download. -- **target** The path of the local folder you want to download to. - -Example: - -``` -hyp sync hyper://1234..af ./target-folder --no-live -``` - -You can re-run the command to update the target folder. It will cause the target folder to match the hyperdrive *exactly* so watch out for data loss. - -> If you don't include `--no-live` the sync command will continuously sync the source to the target. \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/sharing-folders/ \ No newline at end of file diff --git a/docs/guides/list-seeds.md b/docs/guides/list-seeds.md index 2904ce9..4c0e29c 100644 --- a/docs/guides/list-seeds.md +++ b/docs/guides/list-seeds.md @@ -1,17 +1,5 @@ # List your current seeds -``` -hyp info [urls..] -``` +This doc was moved to the website: -The info command will tell you what you are currently seeding if given no arguments: - -``` -hyp info -``` - -If one (or more) URLs are supplied, it will give the current seeding state of that hyper: - -``` -hyp info hyper://1234..af -``` \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/seeding-data/ \ No newline at end of file diff --git a/docs/guides/reading-a-file.md b/docs/guides/reading-a-file.md index 0e916d1..09686df 100644 --- a/docs/guides/reading-a-file.md +++ b/docs/guides/reading-a-file.md @@ -1,17 +1,5 @@ # Reading a file from a hyperdrive -``` -hyp cat {url} -``` +This doc was moved to the website: -To read the file, simply run `cat` on the file's URL: - -``` -hyp cat hyper://1234..af/hello.txt -``` - -You can save the file using pipes: - -``` -hyp cat hyper://1234..af/hello.txt > ./hello.txt -``` \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/commands/drive-cat/ \ No newline at end of file diff --git a/docs/guides/seeding.md b/docs/guides/seeding.md index 16b452c..4717c42 100644 --- a/docs/guides/seeding.md +++ b/docs/guides/seeding.md @@ -1,23 +1,5 @@ # Keeping hypers online (seeding) -``` -hyp seed {url} -``` +This doc was moved to the website: -To sync the current data of a hyper and host its data for others to access, run the seed command on its URL: - -``` -hyp seed hyper://1234..af -``` - -You can stop seeding with the unseed command: - -``` -hyp unseed hyper://1234..af -``` - -You can list all currently-seeded hypers with the info command: - -``` -hyp info -``` \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/seeding-data/ \ No newline at end of file diff --git a/docs/guides/sharing-a-folder.md b/docs/guides/sharing-a-folder.md index cb9ac2d..a3ddbcb 100644 --- a/docs/guides/sharing-a-folder.md +++ b/docs/guides/sharing-a-folder.md @@ -1,26 +1,5 @@ # Sharing a folder in a hyperdrive -``` -hyp sync {source} [target] -``` +This doc was moved to the website: -- **source** The path of the folder to share. -- **target** Optional- the hyperdrive to sync the folder to. - -If no target is supplied, `hyp` will create a new hyperdrive for you. - -``` -hyp sync ./target-folder --no-live -``` - -The sync command will output the URL of your new hyperdrive, and it will now contain your folder's files. - -To update the hyperdrive again, run: - -``` -hyp sync ./target-folder hyper://1234..af --no-live -``` - -Where `hyper://1234..af` is your hyperdrive's URL. - -> If you don't include `--no-live` the sync command will continuously sync the source to the target. \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/sharing-folders/ \ No newline at end of file diff --git a/docs/guides/writing-a-file.md b/docs/guides/writing-a-file.md index 32873e5..49026d8 100644 --- a/docs/guides/writing-a-file.md +++ b/docs/guides/writing-a-file.md @@ -1,19 +1,5 @@ # Writing an individual file to hyperdrive -``` -hyp put {url} [value] -``` +This doc was moved to the website: -You'll first need to [create a hyperdrive](./creating-a-hyperdrive.md). - -To write a file, run the `put` command on the URL and provide the content of the file: - -``` -hyp put hyper://1234..af/hello.txt "Hello, world!" -``` - -If you want to copy an existing file into the hyperdrive, use pipes instead of supplying the value in the arguments: - -``` -cat hello.txt | hyp put hyper://1234..af/hello.txt -``` \ No newline at end of file +https://hypercore-protocol.org/guides/hyp/commands/drive-put/ \ No newline at end of file diff --git a/lib/commands/beam.js b/lib/commands/beam.js new file mode 100644 index 0000000..c38efef --- /dev/null +++ b/lib/commands/beam.js @@ -0,0 +1,80 @@ +import Hyperbeam from 'hyperbeam' +import randomWords from 'random-words' +import chalk from 'chalk' + +const FULL_USAGE = ` + The beam command is a general-purpose tool for sending data over the network + according to a secret passphrase. You choose a phrase (try to make it hard-ish + to guess!) and then share the phrase with your recipient. The phrase is only + good for 30-60 minutes. + +On the sending device: + + cat hello.txt | hyp beam "for bob roberts" + +On the receiving device: + + hyp beam "for bob roberts" > ./hello.txt + +This can be really useful for sharing hyper keys between devices. For instance: + + > hyp sync ./my-folder + Creating new hyperdrive... + Source: my-folder/ + Target: hyper://f7145e1bbc0d17705861e996b47422e0ca50a80db9441249bd721ff426b79f2a/ + Begin sync? [y/N] y + Syncing... + Synced + > echo "hyper://f7145e1bbc0d17705861e996b47422e0ca50a80db9441249bd721ff426b79f2a/" \\ + | hyp beam "nobody can guess" +` + +export default { + name: 'beam', + description: 'Send a stream of data over the network.', + usage: { + simple: '[passphrase]', + full: FULL_USAGE + }, + command: async function (args) { + var phrase = args._[0] ? args._.join(' ') : randomWords(3).join(' ') + const beam = new Hyperbeam(phrase) + + if (!args._[0]) { + console.error('[hyperbeam] Generated passphrase:') + console.error('') + console.error(' ', chalk.bold(phrase)) + console.error('') + } + + beam.on('remote-address', function ({ host, port }) { + if (!host) console.error('[hyperbeam] Could not detect remote address') + else console.error('[hyperbeam] Joined the DHT - remote address is ' + host + ':' + port) + if (port) console.error('[hyperbeam] Network is holepunchable \\o/') + }) + + beam.on('connected', function () { + console.error('[hyperbeam] Success! Encrypted tunnel established to remote peer') + }) + + beam.on('end', () => beam.end()) + + process.stdin.pipe(beam).pipe(process.stdout) + process.stdin.unref() + + process.once('SIGINT', () => { + if (!beam.connected) closeASAP() + else beam.end() + }) + + function closeASAP () { + console.error('[hyperbeam] Shutting down beam...') + + const timeout = setTimeout(() => process.exit(1), 2000) + beam.destroy() + beam.on('close', function () { + clearTimeout(timeout) + }) + } + } +} diff --git a/lib/commands/create.js b/lib/commands/create.js index 260535a..0e5b988 100644 --- a/lib/commands/create.js +++ b/lib/commands/create.js @@ -22,7 +22,7 @@ export default { process.exit(1) } - await getMirroringClient().mirror(struct.api.key, struct.type) + await getMirroringClient().mirror(struct.key, struct.type) console.log('Seeding', struct.type) process.exit(0) } diff --git a/lib/commands/daemon/start.js b/lib/commands/daemon/start.js new file mode 100644 index 0000000..d33c5a7 --- /dev/null +++ b/lib/commands/daemon/start.js @@ -0,0 +1,31 @@ +import hyperspace from 'hyperspace' +const HyperspaceClient = hyperspace.Client + +import { setup } from '../../hyper/index.js' + +const FULL_USAGE = ` +Examples: + + hyp daemon start +` +export default { + name: 'daemon start', + description: 'Start the hyperspace daemon.', + usage: { + full: FULL_USAGE + }, + command: async function (args) { + await setup({canStartDaemon: true}) + try { + const client = new HyperspaceClient() + await client.ready() + await client.status() + } catch (err) { + console.error('Could not start the daemon:') + console.error(err) + process.exit(1) + } + console.log('Daemon is running.') + process.exit(0) + } +} diff --git a/lib/commands/drive/sync.js b/lib/commands/drive/sync.js index eb1814c..c5e974b 100644 --- a/lib/commands/drive/sync.js +++ b/lib/commands/drive/sync.js @@ -18,7 +18,8 @@ Options: --no-add - Don't include additions to the target location. --no-overwrite - Don't include overwrites to the target location. --no-delete - Don't include deletions to the target location. - --no-live - Don't continuously sync changes. + -w/--watch/--live - Continuously sync changes. + -y/--yes - Do not ask for confirmation Examples: @@ -40,24 +41,32 @@ export default { {name: 'add', default: true, boolean: true}, {name: 'overwrite', default: true, boolean: true}, {name: 'delete', default: true, boolean: true}, - {name: 'live', default: true, boolean: true} + {name: 'live', default: false, boolean: true}, + {name: 'watch', abbr: 'w', default: false, boolean: true}, + {name: 'yes', abbr: 'y', default: false, boolean: true} ], command: async function (args) { if (!args._[0]) throw new Error('A source path or URL is required') + var live = args.watch || args.live var leftArgs = await parseArgs(args._[0]) var rightArgs = args._[1] ? await parseArgs(args._[1]) : await createTarget(leftArgs) if (!args._[1]) console.error('Creating new hyperdrive...') console.error(chalk.bold(`Source: ${leftArgs.raw}`)) console.error(chalk.bold(`Target: ${rightArgs.raw}`)) - var ok = await yesno({ - question: `Begin sync? [y/N]`, - defaultValue: false - }) + var ok = true + + if(!args.yes){ + ok = await yesno({ + question: `Begin sync? [y/N]`, + defaultValue: false + }) + } + if (!rightArgs.isHyper) mkdirp.sync(rightArgs.path) if (!ok) process.exit(0) - console.error(args.live ? 'Live syncing (Ctrl+c to exit)...' : 'Syncing...') + console.error(live ? 'Live syncing (Ctrl+c to exit)...' : 'Syncing...') var statusLines = [''] var statusLog = statusLogger(statusLines) @@ -69,7 +78,7 @@ export default { var right = toDftParam(rightArgs) await sync(left, right, args, {statusLines, statusLog}) - if (!args.live) return process.exit(0) + if (!live) return process.exit(0) const watcher = watch(left, debounce(() => sync(left, right, args, {statusLines, statusLog}), SYNC_INTERVAL)) let exiting = false @@ -169,7 +178,7 @@ async function createTarget (source) { } // If the source is a local directory, create a new drive to copy into. let drive = await HyperStruct.create('hyperdrive') - await getMirroringClient().mirror(drive.api.key, drive.type) + await getMirroringClient().mirror(drive.key, drive.type) return {fs: drive.api, path: '/', raw: drive.url + '/'} } @@ -201,4 +210,4 @@ async function setupTracker (key, statusLines, statusLog) { setTimeout(updateState, 1e3).unref() } await updateState() -} \ No newline at end of file +} diff --git a/lib/commands/info.js b/lib/commands/info.js index ecb5867..595685a 100644 --- a/lib/commands/info.js +++ b/lib/commands/info.js @@ -9,11 +9,13 @@ const FULL_USAGE = ` Options: + --live - Continuously output the current state. -l/--long - List the full keys of the hypers. Examples: hyp info + hyp info --live hyp info hyper://1234..af/ hyp info hyper://1234..af/ hyper://fedc..21/ ` @@ -31,12 +33,23 @@ export default { default: false, abbr: 'l', boolean: true + }, + { + name: 'live', + default: false, + boolean: true } ], command: async function (args) { + var useLiveOutput = process.stdout.isTTY var hyperClient = getClient() var mirroringClient = getMirroringClient() + if (!useLiveOutput && args.live) { + console.error('Cannot pipe output of "hyp info" with --live set, disabling live-mode.') + args.live = false + } + var keys if (!args._.length) { keys = await getAllKeys(mirroringClient) @@ -49,15 +62,30 @@ export default { } if (!keys.length) { - console.error(`No hypers active.`) + console.log(`No hypers active.`) process.exit(0) } - var statusLines = keys.map(k => `${chalk.bold(short(k))}: Loading...`) - var statusLog = statusLogger(statusLines) - statusLog.print() + if (useLiveOutput) { + var statusLines = keys.map(k => `${chalk.bold(short(k))}: Loading...`) + var statusLog = statusLogger(statusLines) + statusLog.print() + } + + await Promise.all(keys.map(async (key, i) => { + const log = (str) => { + if (useLiveOutput) { + statusLines[i] = str + statusLog.print() + } else { + console.log(str) + } + } + const weaklog = (str) => { + // only log if live output + if (useLiveOutput) log(str) + } - keys.forEach(async (key, i) => { var tracker = new HyperStructInfoTracker(key) await tracker.attemptLoadStruct() var mirror = null @@ -66,29 +94,31 @@ export default { // periodically update stdout with the status-line const updateStatusLine = () => { if (!network && !mirror) { - statusLines[i] = `${tracker.genStatusIdent(args.long)}...` + weaklog(`${tracker.genStatusIdent(args.long)}...`) } else { const networkStatusLine = network && network.announce ? 'but online (announcing)' : 'and not online' const seedingStatusLine = mirror && mirror.mirroring ? 'Seeding' : `Not seeding ${networkStatusLine}` - statusLines[i] = ` + log(` ${tracker.genStatusIdent(args.long)}: - ${tracker.genStatusPeerCount()} | - ${tracker.genStatusNetStats()} + ${tracker.genStatusPeerCount()} + ${args.live ? `| ${tracker.genStatusNetStats()}` : ''} - ${seedingStatusLine} - `.split('\n').map(s => s.trim()).join(' ') + `.split('\n').map(s => s.trim()).filter(Boolean).join(' ')) } - statusLog.print() } updateStatusLine() - setInterval(updateStatusLine, 1e3).unref() // periodically calculate the size of the hyper structure const updateState = async () => { try { + await tracker.fetchState() + if (!args.live && tracker.loadStructPromise) { + // if not live, we should wait until the struct finishes loading + await tracker.loadStructPromise + } if (tracker.struct) { - ;({ mirror, network } = await getStatus(key, tracker.struct.type, tracker.struct.api.discoveryKey)) + ;({ mirror, network } = await getStatus(key, tracker.struct.type, tracker.struct.discoveryKey)) } - await tracker.fetchState() } catch (e) { if (e.toString().includes('RPC stream destroyed')) { // ignore @@ -96,10 +126,19 @@ export default { console.error(e) } } - setTimeout(updateState, 1e3).unref() + updateStatusLine() + + if (args.live) { + // continuous update + setTimeout(updateState, 1e3).unref() + } } - updateState() - }) + await updateState() + })) + + if (!args.live) { + process.exit(0) + } async function getAllStatuses () { // TODO - --all switch diff --git a/lib/commands/seed.js b/lib/commands/seed.js index f01357e..ab330e1 100644 --- a/lib/commands/seed.js +++ b/lib/commands/seed.js @@ -27,10 +27,9 @@ export default { keys.push(urlp.hostname) } - let i = 0 for (const key of keys) { var struct = await HyperStruct.get(key) - await mirroringClient.mirror(struct.api.key, struct.type) + await mirroringClient.mirror(struct.key, struct.type) console.log(`Seeding ${chalk.bold(short(key))}`) } process.exit(0) diff --git a/lib/commands/unseed.js b/lib/commands/unseed.js index 0c34172..006eac1 100644 --- a/lib/commands/unseed.js +++ b/lib/commands/unseed.js @@ -27,10 +27,9 @@ export default { keys.push(urlp.hostname) } - let i = 0 for (const key of keys) { var struct = await HyperStruct.get(key) - await mirroringClient.unmirror(struct.api.key, struct.type) + await mirroringClient.unmirror(struct.key, struct.type) console.log(`No longer seeding ${chalk.bold(short(key))}`) } process.exit(0) diff --git a/lib/hyper/index.js b/lib/hyper/index.js index 5cd4d20..cfacbe5 100644 --- a/lib/hyper/index.js +++ b/lib/hyper/index.js @@ -6,18 +6,18 @@ import mirroring from 'hyperspace-mirroring-service' const HyperspaceClient = hyperspace.Client const MirroringClient = mirroring.Client -const NUM_RETRIES = 5 +const NUM_RETRIES = 50 const RETRY_DELAY = 100 var clients = new Map() var running = new Set() -export async function setup () { - await setupClient('hyperspace', 'Hyperspace', () => new HyperspaceClient()) - await setupClient('hyperspace-mirroring-service', 'Mirroring', () => new MirroringClient()) +export async function setup ({canStartDaemon} = {canStartDaemon: false}) { + await setupClient('hyperspace', 'Hyperspace', () => new HyperspaceClient(), canStartDaemon) + await setupClient('hyperspace-mirroring-service', 'Mirroring', () => new MirroringClient(), canStartDaemon) } -async function setupClient (name, readable, clientFunc) { +async function setupClient (name, readable, clientFunc, canStartDaemon = false) { let retries = 0 while (!clients.get(name) && retries++ < NUM_RETRIES) { try { @@ -25,6 +25,7 @@ async function setupClient (name, readable, clientFunc) { await client.ready() clients.set(name, client) } catch { + if (!canStartDaemon) break if (!running.has(name)) { await startDaemon(name, readable) running.add(name) @@ -32,7 +33,9 @@ async function setupClient (name, readable, clientFunc) { await wait(RETRY_DELAY * retries) } } - if (!clients.has(name)) throw new Error(`Could not connect to the ${readable} daemon.`) + if (!clients.has(name)) { + throw new Error(`Could not connect to the ${readable} daemon.`) + } const cleanup = async () => { const client = clients.get(name) @@ -47,7 +50,7 @@ async function startDaemon (name, readable) { const daemonRoot = p.dirname(require.resolve(name)) const binPath = p.join(daemonRoot, 'bin', 'index.js') console.error(`${readable} daemon started`) - return spawn(binPath, { + return spawn('node', [binPath], { detached: true }) } diff --git a/lib/hyper/info-tracker.js b/lib/hyper/info-tracker.js index 51dc0b1..e568e9c 100644 --- a/lib/hyper/info-tracker.js +++ b/lib/hyper/info-tracker.js @@ -75,14 +75,14 @@ export class HyperStructInfoTracker { } async fetchState () { - this.netCfg = await hyper.getClient().network.status(this.discoveryKey) + this.netCfg = await hyper.getClient().network.status(this.discoveryKey).catch(e => undefined) if (!this.struct) { /* dont await */ this.attemptLoadStruct() return } - await this.calcBlockState() + await this.calcBlockState().catch(e => undefined) } async attemptLoadStruct () { diff --git a/lib/hyper/struct.js b/lib/hyper/struct.js index c7d0ff7..2481848 100644 --- a/lib/hyper/struct.js +++ b/lib/hyper/struct.js @@ -24,8 +24,16 @@ class HyperStructure extends EventEmitter { this.api = undefined } + get key () { + return this.core?.key + } + + get discoveryKey () { + return this.core?.discoveryKey + } + get url () { - return `hyper://${this.keyStr}` + return `hyper://${this.keyStr}/` } get core () { @@ -99,7 +107,7 @@ class HyperStructure extends EventEmitter { if (this.type === 'hyperdrive') { this.api = hyperdrive(getClient().corestore(), null, {extension: false}) await this.api.promises.ready() - this.keyStr = this.api.key.toString('hex') + this.keyStr = this.key.toString('hex') } else if (this.type === 'hyperbee') { let core = getClient().corestore().get(null) this.api = new Hyperbee(core, { @@ -107,7 +115,7 @@ class HyperStructure extends EventEmitter { valueEncoding: 'json' }) await this.api.ready() - this.keyStr = this.api.feed.key.toString('hex') + this.keyStr = this.key.toString('hex') } if (!noNetConfig) getClient().network.configure(this.core, {lookup: true, announce: true}) diff --git a/lib/usage.js b/lib/usage.js index fc7a4c3..1a8b581 100644 --- a/lib/usage.js +++ b/lib/usage.js @@ -23,6 +23,8 @@ ${chalk.bold(`General Commands:`)} ${simple(commands.unseed)} ${simple(commands.create)} + ${simple(commands.beam)} + ${chalk.bold(`Hyperdrive Commands:`)} ${simple(commands.driveLs)} @@ -48,6 +50,7 @@ ${chalk.bold(`Hyperbee Commands:`)} ${chalk.bold(`Daemon Commands:`)} ${simple(commands.daemonStatus)} + ${simple(commands.daemonStart)} ${simple(commands.daemonStop)} ${chalk.bold(`Aliases:`)} @@ -58,7 +61,7 @@ ${chalk.bold(`Aliases:`)} ${chalk.bold('hyp cat')} -> hyp drive cat ${chalk.bold('hyp put')} -> hyp drive put - ${chalk.green(`Learn more at https://github.com/hypecore-protocol/cli`)} + ${chalk.green(`Learn more at https://github.com/hypercore-protocol/cli`)} `) process.exit(err ? 1 : 0) } diff --git a/package.json b/package.json index 96d083d..e7465b6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@hyperspace/cli", "type": "module", - "version": "1.0.1", + "version": "2.0.0", "description": "A CLI for the hyper:// space network.", "bin": { "hyp": "./bin/hyp.js" @@ -23,6 +23,9 @@ "bugs": { "url": "https://github.com/hypercore-protocol/hypercore-cli/issues" }, + "engines": { + "node": ">=14.0.0" + }, "homepage": "https://github.com/hypercore-protocol/hypercore-cli#readme", "dependencies": { "ansi-diff-stream": "^1.2.1", @@ -33,9 +36,10 @@ "chokidar": "^3.4.3", "concat-stream": "^2.0.0", "diff-file-tree": "^2.5.1", - "hyperbee": "^1.0.0", + "hyperbeam": "^1.1.1", + "hyperbee": "^1.0.1", "hyperdrive": "^10.18.0", - "hyperspace": "^3.16.0", + "hyperspace": "^3.17.0", "hyperspace-mirroring-service": "^1.0.0", "identify-filetype": "^1.0.0", "mime": "^1.4.0", @@ -46,6 +50,7 @@ "pretty-hash": "^1.0.1", "progress-string": "^1.2.1", "pump": "^3.0.0", + "random-words": "^1.1.1", "range-parser": "^1.2.1", "speedometer": "^1.1.0", "subcommand": "^2.1.1",