diff --git a/package.json b/package.json index 36685eb..c715163 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,6 @@ "keywords": [ "pear" ], - "pear": { - "platform": { - "key": "pear://pzcjqmpoo6szkoc4bpkw65ib9ctnrq7b6mneeinbhbheihaq6p6o" - } - }, "author": "Holepunch Inc", "license": "Apache-2.0", "bugs": { @@ -26,13 +21,8 @@ "homepage": "https://docs.pears.com", "dependencies": { "graceful-goodbye": "^1.3.2", - "corestore": "7.9.2", - "hypercore": "11.29.0", - "hypercore-crypto": "^3.6.1", - "hypercore-id-encoding": "^1.2.0", - "pear-updater-bootstrap": "^2.0.0", + "pear-install": "^1.2.0", "rocksdb-native": "^3.5.7", - "speedometer": "^1.1.0", "tiny-byte-size": "^1.1.0", "which-runtime": "^1.2.0" }, diff --git a/pear.js b/pear.js index 095ebc8..2b5cb75 100755 --- a/pear.js +++ b/pear.js @@ -1,50 +1,32 @@ #!/usr/bin/env node const process = require('process') -const HypercoreID = require('hypercore-id-encoding') const os = require('os') const path = require('path') const fs = require('fs') -const { isWindows, isLinux, isMac, platform, arch } = require('which-runtime') +const { isWindows, isLinux } = require('which-runtime') const goodbye = require('graceful-goodbye') -const speedometer = require('speedometer') const byteSize = require('tiny-byte-size') -const { discoveryKey } = require('hypercore-crypto') const isTTY = process.stdout.isTTY -const PROD_KEY = 'pear://pzcjqmpoo6szkoc4bpkw65ib9ctnrq7b6mneeinbhbheihaq6p6o' -const PEAR_KEY = require('./package.json').pear.platform.key -const DKEY = discoveryKey(HypercoreID.decode(PEAR_KEY)).toString('hex') +const PEAR_KEY = 'pear://smw4thqaqed9iq6bae7a9cxd4fesruixgkafe38jny33ahs33igy' +const key = PEAR_KEY -const HOST = platform + '-' + arch - -const PEAR_DIR = isMac - ? path.join(os.homedir(), 'Library', 'Application Support', 'pear') - : isLinux - ? path.join(os.homedir(), '.config', 'pear') - : path.join(os.homedir(), 'AppData', 'Roaming', 'pear') - -const LINK = path.join(PEAR_DIR, 'current') -const BIN = path.join(PEAR_DIR, 'bin') -const CURRENT_BIN = path.join( - LINK, - 'by-arch', - HOST, - 'bin/pear-runtime' + (isWindows ? '.exe' : '') -) - -const forceUpdate = process.argv[2] === 'update' +const HOME = os.homedir() +const BIN_PATH = isWindows + ? path.join( + process.env.LOCALAPPDATA || path.join(HOME, 'AppData', 'Local'), + 'Programs', + 'pear' + ) + : path.join(HOME, '.local', 'bin') +const BIN = path.join(BIN_PATH, `pear${isWindows ? '.exe' : ''}`) -if (isInstalled() && !forceUpdate) { - const warning = `[ WARNING ] To complete Pear installation, prepend the following to the system ${isWindows ? 'Path environment variable' : '$PATH'}: -${BIN} -Until then, this executable spawns the ${'`pear`'} binary. -Fix automatically with: pear run pear://runtime` - console.error(warning) +if (fs.existsSync(BIN)) { let child = null const childProcessExit = new Promise((resolve) => { child = require('child_process') - .spawn(CURRENT_BIN, process.argv.slice(2), { + .spawn(BIN, process.argv.slice(2), { stdio: 'inherit' }) .on('exit', function (code) { @@ -72,124 +54,53 @@ Please install it first using the appropriate package manager for your system. `) process.exit(1) } - const bootstrap = require('pear-updater-bootstrap') + const Install = require('pear-install') - console.log( - 'Installing Pear Runtime (Please stand by, this might take a bit...)\n' - ) - if (PEAR_KEY !== PROD_KEY) console.log('Bootstrapping:', PEAR_KEY) - bootstrap(PEAR_KEY, PEAR_DIR, { - onupdater: startDriveMonitor, - force: forceUpdate - }).then( - function () { - stopDriveMonitor() - console.log('Pear Runtime installed!') - console.log() - console.log('Finish the installation by opening the runtime app') - console.log() - console.log('npx pear run pear://runtime') - if (makeBin()) { - console.log() - console.log('Or by adding the following to your path') - console.log() - if (isWindows) { - console.log(`cmd: set PATH="${BIN};%PATH%"`) - console.log(`PowerShell: $env:PATH="${BIN};$env:PATH"`) - } else { - console.log(`export PATH="${BIN}:$PATH"`) - } - } - }, - function (err) { - if (forceUpdate && err.code === 'ENOENT') { - console.log( - `Update failed: Pear Runtime is not installed at ${err.path}` - ) - } else { - throw err - } - } - ) -} + console.log('Installing Pear (Please stand by, this might take a bit...)') + console.log('Bootstrapping:', key) -function makeBin() { - try { - fs.mkdirSync(BIN, { recursive: true }) + const install = new Install({ link: key }) + + if (isTTY) install.on('stats', printStats) - if (isWindows) { - fs.writeFileSync( - path.join(BIN, 'pear.cmd'), - `@echo off\r\n"${CURRENT_BIN}" %*` - ) - fs.writeFileSync(path.join(BIN, 'pear.ps1'), `& "${CURRENT_BIN}" @args`) + install.on('final', (result) => { + if (isTTY) clear() + + if (result.success) { + console.log('Pear installed!') } else { - fs.symlinkSync(CURRENT_BIN, path.join(BIN, 'pear')) + console.error('Installation failed:', result) + process.exit(1) } - } catch { - return false - } - return true -} + }) -function isInstalled() { - try { - const p = fs.realpathSync(LINK) - return path.basename(path.dirname(p)) === DKEY - } catch { - return false - } -} + install.on('error', (err) => { + if (isTTY) clear() + throw err + }) -let monitorInterval = null + install + .ready() + .catch((err) => { + if (isTTY) clear() + console.error(err.message) + }) + .finally(() => { + install.close() + }) +} function clear() { process.stdout.write('\x1b[2K') // clear line process.stdout.write('\r') // cursor to 0 } -function stopDriveMonitor() { - clearInterval(monitorInterval) - if (isTTY) clear() -} - -function startDriveMonitor(updater) { +function printStats(stats) { if (!isTTY) return - - const downloadSpeedometer = speedometer() - const uploadSpeedometer = speedometer() - let peers = 0 - let downloadedBytes = 0 - let uploadedBytes = 0 - - updater.drive - .getBlobs() - .then((blobs) => { - blobs.core.on('download', (_index, bytes) => { - downloadedBytes += bytes - downloadSpeedometer(bytes) - }) - blobs.core.on('upload', (_index, bytes) => { - uploadedBytes += bytes - uploadSpeedometer(bytes) - }) - blobs.core.on('peer-add', () => { - peers = blobs.core.peers.length - }) - blobs.core.on('peer-remove', () => { - peers = blobs.core.peers.length - }) - }) - .catch(() => { - // ignore - }) - - monitorInterval = setInterval(() => { - clear() - process.stdout.write( - `[⬇ ${byteSize(downloadedBytes)} - ${byteSize(downloadSpeedometer())}/s - ${peers} peers] [⬆ ${byteSize(uploadedBytes)} - ${byteSize(uploadSpeedometer())}/s - ${peers} peers]` - ) - }, 500) + clear() + process.stdout.write( + `[⬇ ${byteSize(stats.download.bytes)} - ${byteSize(stats.download.speed)}/s - ${stats.peers} peers]` + ) } function libatomicCheck() {