OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-deploy / examples / cli.js

115 lines · javascript ref:
#!/usr/bin/env node
/**
 * Mini CLI example for hyper-deploy
 *
 * Usage:
 *   node examples/cli.js serve <dir> [--topic <hex>]
 *   node examples/cli.js pull <topic> [dest]
 *   node examples/cli.js info <topic>
 */

import { DeployServer, DeployClient } from '../index.js'

function fmt (b) {
  if (b < 1024) return b + ' B'
  if (b < 1048576) return (b / 1024).toFixed(1) + ' KB'
  if (b < 1073741824) return (b / 1048576).toFixed(1) + ' MB'
  return (b / 1073741824).toFixed(2) + ' GB'
}

const args = process.argv.slice(2)
const cmd = args[0]

if (cmd === 'serve') {
  const dir = args[1]
  if (!dir) { console.error('Usage: cli.js serve <dir>'); process.exit(1) }

  let topic
  const ti = args.indexOf('--topic')
  if (ti !== -1 && args[ti + 1]) topic = Buffer.from(args[ti + 1], 'hex')

  const server = new DeployServer(dir, { topic })

  server.on('indexed', (count, size) => {
    console.log('Indexed: %d files, %s', count, fmt(size))
  })

  server.on('ready', () => {
    console.log('Topic: %s', server.topicHex)
    console.log('Pull:  node examples/cli.js pull %s ./dest', server.topicHex)
    console.log('Waiting for peers...')
  })

  server.on('peer', ({ key, state }) => console.log('Peer %s: %s', key, state))

  server.on('progress', (p) => {
    if (p.file) console.log('  sent %s (%d files, %s)', p.file, p.filesServed, fmt(p.bytesServed))
  })

  server.ready().catch((err) => { console.error(err.message); process.exit(1) })
} else if (cmd === 'pull') {
  const topicHex = args[1]
  const dest = args[2] || './deploy-output'
  if (!topicHex || topicHex.length !== 64) {
    console.error('Usage: cli.js pull <64-char-hex> [dest]')
    process.exit(1)
  }

  const client = new DeployClient(topicHex, dest)
  const t0 = Date.now()

  client.on('connected', (key) => console.log('Connected: %s (%dms)', key, Date.now() - t0))
  client.on('manifest', (n) => console.log('Manifest: %d files', n))
  client.on('diff', (needed, skipped) => console.log('Need: %d, skip: %d', needed, skipped))
  client.on('up-to-date', () => console.log('Up to date'))

  client.on('progress', (p) => {
    const total = p.filesTransferred + p.filesSkipped
    if (p.filesTransferred % 100 === 0 || total === p.totalFiles) {
      console.log('  %d/%d transferred, %s', p.filesTransferred, p.totalFiles, fmt(p.bytesReceived))
    }
  })

  client.ready()
    .then(() => client.pull())
    .then((stats) => {
      const speed = stats.bytesReceived > 0 ? (stats.bytesReceived / stats.elapsed * 1000 / 1024 / 1024).toFixed(1) : '0'
      console.log('Done: %d files, %s, %ss (%s MB/s)',
        stats.filesTransferred, fmt(stats.bytesReceived),
        (stats.elapsed / 1000).toFixed(1), speed)
      if (stats.errors.length) console.log('Errors:', stats.errors)
      return client.close()
    })
    .then(() => process.exit(0))
    .catch((err) => { console.error(err.message); process.exit(1) })
} else if (cmd === 'info') {
  const topicHex = args[1]
  if (!topicHex || topicHex.length !== 64) {
    console.error('Usage: cli.js info <64-char-hex>')
    process.exit(1)
  }

  const client = new DeployClient(topicHex, '/tmp/hyper-deploy-info', { timeout: 15000 })

  client.on('connected', (key) => console.log('Connected: %s', key))
  client.on('manifest', (n) => console.log('Files: %d', n))
  client.on('diff', (needed, skipped) => {
    console.log('Would transfer: %d, already local: %d', needed, skipped)
    client.close().then(() => process.exit(0))
  })

  client.ready()
    .then(() => client.pull())
    .catch((err) => {
      if (!err.message.includes('closed during pull')) {
        console.error(err.message)
        process.exit(1)
      }
    })
} else {
  console.log('hyper-deploy example CLI')
  console.log('  serve <dir> [--topic <hex>]  Serve a directory')
  console.log('  pull <topic> [dest]          Pull files from server')
  console.log('  info <topic>                 Show remote manifest')
}