├── .gitignore ├── LICENSE ├── README.md ├── bin.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | sandbox.js 3 | hyperbrowse/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Mathias Buus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hyperbrowse 2 | 3 | Browse Hyperdrive 10 archives over a localhost http server: 4 | 5 | ``` sh 6 | npm install -g hyperbrowse 7 | ``` 8 | 9 | First time you spin it up pass the Hyperdrive key you want to explore: 10 | 11 | This is wikipedia for example: 12 | 13 | ``` sh 14 | hyperbrowse -d wiki -k 907c949c372f7281c13330b7bd3feb922a936c4f5ae04e61e34e3c90fc6eba9b 15 | ``` 16 | 17 | Then simply navigate your browser to the address printed (usually http://localhost:8080) 18 | to start browsing. 19 | 20 | ## Options 21 | 22 | - `-d {dir}`: the directory where hyperbrowse will store the Hyperdrive 23 | - `-k {key}`: the Hypercore archive you want to browse 24 | - `-ram`: run completely in memory 25 | 26 | 27 | For more info run `hyperbrowse --help` 28 | 29 | ## License 30 | 31 | MIT 32 | -------------------------------------------------------------------------------- /bin.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const hyperdrive = require('hyperdrive') 4 | const onrequest = require('hyperdrive-http') 5 | const replicator = require('@hyperswarm/replicator') 6 | const prettier = require('prettier-bytes') 7 | 8 | const minimist = require('minimist') 9 | 10 | const argv = minimist(process.argv, { 11 | alias: { 12 | key: 'k', 13 | dir: 'd', 14 | directory: 'd', 15 | port: 'p', 16 | help: 'h' 17 | }, 18 | default: { 19 | directory: 'hyperbrowse', 20 | port: 8080 21 | }, 22 | boolean: ['ram', 'help'] 23 | }) 24 | 25 | if (argv.help) { 26 | console.error(`Usage: hyperbrowse [options] 27 | -k, --key The hyperdrive 10 key 28 | -d, --dir Where to store the data 29 | -p, --port Which HTTP port to use. 30 | --ram Only use RAM for storage 31 | `) 32 | process.exit(0) 33 | } 34 | 35 | const key = argv.key ? Buffer.from(argv.key, 'hex') : null 36 | const storage = argv.ram ? require('random-access-memory') : argv.directory 37 | const drive = hyperdrive(storage, key) 38 | 39 | const cs = drive._corestore || drive.corestore 40 | 41 | const metadatas = new Set() 42 | const contents = new Set() 43 | let first = true // hackish, get feedback from @andrewosh on how to better do this 44 | cs.on('feed', function (feed) { 45 | const metadata = first 46 | first = false 47 | 48 | if (metadata) { 49 | metadatas.add(feed) 50 | feed.on('download', function (seq, data) { 51 | metadataBytes += data.length 52 | metadataBlocks++ 53 | }) 54 | } else { 55 | contents.add(feed) 56 | feed.on('download', function (seq, data) { 57 | contentBytes += data.length 58 | contentBlocks++ 59 | }) 60 | } 61 | }) 62 | 63 | let metadataBlocks = 0 64 | let metadataBytes = 0 65 | let contentBlocks = 0 66 | let contentBytes = 0 67 | 68 | drive.ready(function (err) { 69 | if (err) throw err 70 | 71 | console.log('Browsing ' + drive.key.toString('hex')) 72 | if (drive.metadata.sparse) { 73 | console.log('Note: running in sparse mode so data is only downloaded when needed') 74 | } 75 | 76 | let connections = 0 77 | const set = new Set() 78 | const swarm = replicator(drive, { 79 | discoveryKey: drive.discoveryKey, 80 | live: true, 81 | encrypt: false 82 | }) 83 | 84 | swarm.on('peer', function (peer) { 85 | set.add(peer.host + ':' + peer.port) 86 | }) 87 | 88 | swarm.on('connection', function (connection) { 89 | connections++ 90 | connection.on('close', function () { 91 | connections-- 92 | }) 93 | }) 94 | 95 | process.once('SIGINT', function () { 96 | console.log('Caught SIGINT, shutting down the swarm ...') 97 | server.close() 98 | swarm.destroy(function () { 99 | // something else is keeping the process alive so just exit for now 100 | // todo: investigate what it is 101 | process.exit(0) 102 | }) 103 | }) 104 | 105 | const server = require('http').createServer(onrequest(drive)) 106 | 107 | server.once('error', () => server.listen(0)) 108 | server.listen(argv.port) 109 | 110 | server.on('listening', function () { 111 | console.log(`Server is listening on port http://localhost:${server.address().port}/`) 112 | }) 113 | 114 | setInterval(function () { 115 | console.log(`Found ${set.size} different peers, connected to ${connections} of them`) 116 | console.log(`Downloaded ${metadataBlocks} / ${blocks(metadatas)} blocks and ${prettier(metadataBytes)} / ${prettier(bytes(metadatas))} of metadata`) 117 | console.log(`Downloaded ${contentBlocks} / ${blocks(contents)} blocks and ${prettier(contentBytes)} / ${prettier(bytes(contents))} of content`) 118 | console.log() 119 | }, 2000).unref() 120 | }) 121 | 122 | function bytes (set) { 123 | let total = 0 124 | for (const feed of set) total += feed.byteLength 125 | return total 126 | } 127 | 128 | function blocks (set) { 129 | let total = 0 130 | for (const feed of set) total += feed.length 131 | return total 132 | } 133 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperbrowse", 3 | "version": "1.0.1", 4 | "description": "Browse Hyperdrive 10 archives over a localhost http server", 5 | "bin": { 6 | "hyperbrowse": "./bin.js" 7 | }, 8 | "dependencies": { 9 | "@hyperswarm/replicator": "^1.0.0", 10 | "hyperdrive": "^10.0.0", 11 | "hyperdrive-http": "^4.4.0", 12 | "minimist": "^1.2.0", 13 | "prettier-bytes": "^1.0.4", 14 | "random-access-memory": "^3.1.1" 15 | }, 16 | "devDependencies": {}, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mafintosh/hyperbrowse.git" 20 | }, 21 | "author": "Mathias Buus (@mafintosh)", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/mafintosh/hyperbrowse/issues" 25 | }, 26 | "homepage": "https://github.com/mafintosh/hyperbrowse" 27 | } 28 | --------------------------------------------------------------------------------