├── .gitignore ├── package.json ├── usage.txt ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hypername", 3 | "version": "2.2.0", 4 | "description": "Distributed name server", 5 | "main": "index.js", 6 | "dependencies": { 7 | "hypercore": "^4.11.0", 8 | "hyperdrive-archive-swarm": "^4.1.6", 9 | "level": "^1.5.0", 10 | "minimist": "^1.2.0", 11 | "mkdirp": "^0.5.1" 12 | }, 13 | "devDependencies": {}, 14 | "bin": { 15 | "hypername": "./index.js" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/mafintosh/hypername.git" 20 | }, 21 | "author": "Mathias Buus (@mafintosh)", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/mafintosh/hypername/issues" 25 | }, 26 | "homepage": "https://github.com/mafintosh/hypername" 27 | } 28 | -------------------------------------------------------------------------------- /usage.txt: -------------------------------------------------------------------------------- 1 | Usage: 2 | $ hypername [options] 3 | 4 | Commands: 5 | init Initialize a hypername database. 6 | set Save a value in the store 7 | get Get a value from the store 8 | list List all key value-pairs 9 | sync Connect to the swarm and synchronize data 10 | 11 | Options: 12 | -h, --help Print usage 13 | --no-live Exit after the first download 14 | 15 | Examples: 16 | $ hypername init my-topic # start hypername & print key 17 | $ hypername set my-topic hi cat # save a key-value pair 18 | $ hypername get my-topic hi # get a value at a key 19 | $ hypername list my-topic # list all key-value pairs 20 | $ hypername sync my-topic # sync hypername over the network 21 | 22 | All data is stored in ~/.hypername/ 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 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 | # hypername 2 | 3 | Distributed name server 4 | 5 | ``` 6 | npm install -g hypername 7 | ``` 8 | 9 | ## Usage 10 | 11 | On one computer 12 | 13 | ``` sh 14 | hypername init my-topic 15 | 16 | ``` 17 | 18 | On another 19 | 20 | ``` sh 21 | hypername init my-topic 22 | ``` 23 | 24 | Now the first computer will be able to share name=value pairs with the other one 25 | 26 | On the first computer do 27 | 28 | ``` sh 29 | hypername set my-topic hello world 30 | hypername sync my-topic 31 | ``` 32 | 33 | On the other 34 | 35 | ``` sh 36 | hypername sync my-topic --exit # exit after first change 37 | hypername get my-topic hello # prints world 38 | ``` 39 | 40 | ## API 41 | ```txt 42 | Usage: 43 | $ hypername [options] 44 | 45 | Commands: 46 | init Initialize a hypername database. 47 | set Save a value in the store 48 | get Get a value from the store 49 | list List all key value-pairs 50 | sync Connect to the swarm and synchronize data 51 | 52 | Options: 53 | -h, --help Print usage 54 | --no-live Exit after the first download 55 | 56 | Examples: 57 | $ hypername init my-topic # start hypername & print key 58 | $ hypername set my-topic hi cat # save a key-value pair 59 | $ hypername get my-topic hi # get a value at a key 60 | $ hypername list my-topic # list all key-value pairs 61 | $ hypername sync my-topic # sync hypername over the network 62 | 63 | All data is stored in ~/.hypername/ 64 | ``` 65 | 66 | ## License 67 | 68 | MIT 69 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var hypercore = require('hypercore') 4 | var swarm = require('hyperdrive-archive-swarm') 5 | var level = require('level') 6 | var minimist = require('minimist') 7 | var mkdirp = require('mkdirp') 8 | var path = require('path') 9 | var fs = require('fs') 10 | var home = process.env.HOME || process.env.USERPROFILE 11 | 12 | var usage = fs.readFileSync(path.join(__dirname, 'usage.txt'), 'utf8') 13 | var argv = minimist(process.argv.slice(2), { 14 | boolean: [ 'help', 'live' ], 15 | default: {live: true}, 16 | alias: { help: 'h' } 17 | }) 18 | 19 | var cmd = argv._[0] 20 | var dir = argv._[1] && path.join(home, '.hypername', argv._[1]) 21 | var key = argv._[2] 22 | var value = argv._[3] 23 | 24 | if (argv.help || !dir) { 25 | console.log(usage) 26 | process.exit(argv.help ? 0 : 1) 27 | } 28 | 29 | mkdirp.sync(dir) 30 | var core = hypercore(level(dir)) 31 | 32 | core._db.get('_key', {valueEncoding: 'binary'}, function (_, oldKey) { 33 | var feed = null 34 | 35 | if (cmd === 'init') { 36 | feed = core.createFeed(oldKey || key) 37 | feed.open(function () { 38 | core._db.put('_key', feed.key, function (err) { 39 | if (err) throw err 40 | console.log(feed.key.toString('hex')) 41 | }) 42 | }) 43 | return 44 | } 45 | 46 | if (!oldKey) throw new Error('No key found. Run `hypername init` first') 47 | 48 | feed = core.createFeed(oldKey) 49 | 50 | if (cmd === 'sync') { 51 | feed.open(function () { 52 | var blocks = feed.blocks 53 | swarm(feed) 54 | feed.on('download-finished', function () { 55 | console.log('Pulled ' + (feed.blocks - blocks) + ' change(s)') 56 | blocks = feed.blocks 57 | if (argv.live === false) process.exit(0) 58 | }) 59 | }) 60 | } else if (cmd === 'list' || cmd === 'ls') { 61 | parse(feed, {}, function (err, map) { 62 | if (err) throw err 63 | process.stdout.write('{\n') 64 | Object.keys(map).forEach(function (key, i, keys) { 65 | process.stdout.write(' "' + key + '": "' + map[key] + '"') 66 | if (i !== (keys.length - 1)) process.stdout.write(',\n') 67 | }) 68 | process.stdout.write('\n}\n') 69 | }) 70 | } else if (cmd === 'get') { 71 | parse(feed, {}, function (err, view) { 72 | if (err) throw err 73 | if (view[key]) console.log(view[key]) 74 | else process.exit(1) 75 | }) 76 | } else if (cmd === 'set') { 77 | if (!key) throw new Error('key is required') 78 | feed.append(JSON.stringify({key: key, value: value || ''}), function (err) { 79 | if (err) throw err 80 | }) 81 | } else { 82 | throw new Error('Usage: hypername ') 83 | } 84 | }) 85 | 86 | function parse (feed, opts, cb) { 87 | var view = {} 88 | 89 | feed.createReadStream(opts) 90 | .on('data', function (data) { 91 | data = JSON.parse(data) 92 | if (data.value) view[data.key] = data.value 93 | else delete view[data.key] 94 | }) 95 | .on('end', function () { 96 | cb(null, view) 97 | }) 98 | .on('error', function (err) { 99 | cb(err) 100 | }) 101 | } 102 | --------------------------------------------------------------------------------