├── .gitignore ├── .travis.yml ├── LICENSE ├── app.js ├── cli.js ├── index.js ├── package.json ├── readme.md └── usage.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "4" 5 | - "5" 6 | - "6" 7 | 8 | sudo: false 9 | 10 | script: 11 | - npm test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) Copyright (c) 2016 Joe Hand 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var appa = require('appa') 2 | 3 | module.exports = function (api) { 4 | var app = appa({log: {level: 'silent'}}) 5 | 6 | app.on('/add', function (req, res, ctx) { 7 | api.add(req, res, ctx, function (err, code, data) { 8 | if (err) return app.error(res, code, err.message) 9 | app.send(code, data).pipe(res) 10 | }) 11 | }) 12 | 13 | app.on('/remove', function (req, res, ctx) { 14 | api.remove(req, res, ctx, function (err, code, data) { 15 | if (err) return app.error(res, code, err.message) 16 | app.send(code, data).pipe(res) 17 | }) 18 | }) 19 | 20 | app.on('/status', function (req, res, ctx) { 21 | api.status(req, res, ctx, function (err, code, data) { 22 | if (err) return app.error(res, code, err.message) 23 | app.send(code, data).pipe(res) 24 | }) 25 | }) 26 | 27 | return app 28 | } 29 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var argv = require('minimist')(process.argv.slice(2), { 4 | alias: { 5 | dir: 'd', 6 | help: 'h' 7 | }, 8 | default: { 9 | httpPort: process.env.PORT || 8080, 10 | datPort: 3282, 11 | dir: require('path').join(process.cwd(), 'archives'), 12 | swarm: true, 13 | archiveHttp: true, 14 | debug: true 15 | }, 16 | boolean: ['swarm', 'archiveHttp', 'debug', 'help'] 17 | }) 18 | 19 | if (argv.h) { 20 | require('./usage')() 21 | } 22 | 23 | if (!argv.swarm) { 24 | console.error('Alternative Dat server not implemented yet.\nPlease use swarm or PR =).') 25 | process.exit(1) 26 | } 27 | 28 | if (argv.debug) { 29 | if (typeof argv.debug === 'boolean') { 30 | process.env.DEBUG = 'archiver-server, archiver-api, hyperarchiver' 31 | } else { 32 | process.env.DEBUG = argv.debug 33 | } 34 | } 35 | var debug = require('debug')('hyperarchiver') 36 | 37 | var http = require('http') 38 | var hyperarchiver = require('./index')(argv) 39 | var api = require('./app')(hyperarchiver.api) 40 | var swarm = hyperarchiver.dat.swarm 41 | 42 | var httpServer = http.createServer(function (req, res) { 43 | if (['/add', '/remove', '/status'].indexOf(req.url) > -1) { 44 | return api(req, res) 45 | } else if (opts.archiveHttp) { 46 | // TODO: errors for hyperdrive-http? 47 | return hyperarchiver.dat.httpRequest(req, res) 48 | } 49 | console.error('No request handler found ' + req.url) 50 | res.writeHead(404, {'Content-Type': 'text/plain'}) 51 | res.write('404 Not found') 52 | res.end() 53 | return 54 | }) 55 | 56 | if (argv.swarm) { 57 | swarm.once('listening', function () { 58 | if (argv.debug) debug('Connected to the Dat Network') 59 | else console.log('Connected to the Dat Network') 60 | }) 61 | } 62 | 63 | httpServer.once('listening', function () { 64 | if (argv.debug) debug('Server started at http://127.0.0.1:' + argv.httpPort) 65 | else console.log('Server started at http://127.0.0.1:' + argv.httpPort) 66 | }) 67 | httpServer.listen(argv.httpPort) 68 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var fs = require('fs') 3 | var Archiver = require('hypercore-archiver') 4 | var ArchiverServer = require('archiver-server') 5 | var ArchiverApi = require('archiver-api') 6 | 7 | module.exports = function (opts) { 8 | opts = opts || {} 9 | assert.ok(opts.dir, 'hyperarchiver requires a directory option') 10 | 11 | try { 12 | fs.accessSync(opts.dir, fs.F_OK) 13 | } catch (e) { fs.mkdirSync(opts.dir) } 14 | 15 | var archiver = Archiver(opts.dir) 16 | var archiverApi = ArchiverApi(archiver) 17 | var datServer = ArchiverServer(archiver, { 18 | swarm: opts.swarm, 19 | http: opts.archiveHttp, 20 | datPort: opts.datPort 21 | }) 22 | 23 | return { 24 | archiver: archiver, 25 | dat: datServer, 26 | api: archiverApi 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperarchiver", 3 | "version": "1.1.0", 4 | "description": "Host, backup, and share hyperdrive archives", 5 | "main": "index.js", 6 | "bin": { 7 | "hyperarchiver": "cli.js" 8 | }, 9 | "scripts": { 10 | "test": "standard" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/joehand/hyperarchiver.git" 15 | }, 16 | "author": "Joe Hand (https://joeahand.com/)", 17 | "license": "MIT", 18 | "bugs": { 19 | "url": "https://github.com/joehand/hyperarchiver/issues" 20 | }, 21 | "homepage": "https://github.com/joehand/hyperarchiver#readme", 22 | "dependencies": { 23 | "appa": "^6.0.0", 24 | "archiver-api": "^1.0.0", 25 | "archiver-server": "^2.0.2", 26 | "debug": "^2.3.3", 27 | "hypercore-archiver": "^2.3.0", 28 | "minimist": "^1.2.0" 29 | }, 30 | "devDependencies": { 31 | "standard": "^8.6.0", 32 | "tap-spec": "^4.1.1", 33 | "tape": "^4.6.3" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Hyperarchiver [![Travis](https://travis-ci.org/joehand/hyperarchiver.svg)](https://travis-ci.org/joehand/hyperarchiver) [![npm](https://img.shields.io/npm/v/hyperarchiver.svg)](https://npmjs.org/package/hyperarchiver) 2 | 3 | Zero config server and API for hypercore-archiver. 4 | 5 | ### Features 6 | 7 | * **Rest API**: Add & remove archives to host & backup 8 | * **Dat Network**: Connect automatically to archives over the Dat network. Acts as a public peer for all archives added. 9 | * **Access Archives via HTTP**: View metadata and archive files over HTTP. 10 | 11 | Built with: 12 | 13 | * [hypercore-archiver](https://github.com/mafintosh/hypercore-archiver): Storage, archive management and replication 14 | * [archiver-server](https://github.com/joehand/archiver-server): Serve archives via [discovery-swarm](https://github.com/mafintosh/discovery-swarm) and [hyperdrive-http](https://github.com/joehand/hyperdrive-http) 15 | * [archiver-api](https://github.com/joehand/archiver-api): Rest API for hypercore-archiver 16 | 17 | ## Usage 18 | 19 | ### Install from NPM: 20 | 21 | ``` 22 | npm install -g hyperarchiver 23 | ``` 24 | 25 | ### Run the servers! 26 | 27 | ``` 28 | hyperarchiver --dir archives 29 | ``` 30 | 31 | This starts two servers, one for HTTP access and one for Dat Network access. 32 | 33 | * Archives will be stored in directory specified by `--dir`. 34 | * Add new archives by sending a POST request to `/add`. 35 | * Added archives will be available over the Dat network 36 | * Access archives over http via `/` 37 | 38 | ### Add Archives 39 | 40 | Once the server is running, you can add archives (make sure you are hosting them over Dat). Send a POST request with `YOUR_DAT_KEY`: 41 | 42 | ``` 43 | curl -X POST -H "Content-Type: application/json" -d '{"key":"YOUR_DAT_KEY"}' http://127.0.0.1:8080/add 44 | ``` 45 | 46 | ### Usage Details 47 | 48 | See all the options by running with the `--help` option: 49 | 50 | ``` 51 | hyperarchiver --help 52 | ``` 53 | 54 | ### Http Routes 55 | 56 | #### `/add`: add a new archive 57 | 58 | Send a POST request to `/add` with a JSON object, `{"key": "YOUR_DAT_KEY"}`, to add a new archive. 59 | 60 | hyperarchiver will connect to the archive over Dat, copy it, and serve it over Dat and HTTP. 61 | 62 | #### `/remove`: remove an archive 63 | 64 | Send a POST request to `/remove` with a JSON object, `{"key": "YOUR_DAT_KEY"}`, to remove a new archive. 65 | 66 | hyperarchiver stop serving the archive and remove it from the database. 67 | 68 | #### `/status`: hyperarchiver status 69 | 70 | Send a GET request to `/status` to view the hyperarchiver status. 71 | 72 | #### `/` 73 | 74 | View metadata for an archive that has been added. 75 | 76 | #### `//` 77 | 78 | View a file in an archive. 79 | 80 | ## API 81 | 82 | ### `var hyperarchiver = Hyperarchiver(opts)` 83 | 84 | Create a `hypercore-archiver` and attach the `archiver-server` and `archiver-api`. Hyperarchiver doesn't do much besides glue those three modules together. 85 | 86 | ```js 87 | opts = { 88 | dir: 'archives', // required 89 | swarm: true, // join dat swarm. 90 | archiveHttp: true, // serve archives over http 91 | datPort: 3282, // port for dat swarm 92 | } 93 | ``` 94 | 95 | * `hyperarchiver.api` is `archiver-api` 96 | * `hyperarchiver.dat` is `archiver-server` 97 | * `hyperarchiver.archiver` is `hypercore-archiver` 98 | 99 | See `cli.js` for example usage. 100 | 101 | ## License 102 | 103 | MIT 104 | -------------------------------------------------------------------------------- /usage.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | console.error('Usage: hyperarchiver [options]') 3 | console.error('') 4 | console.error(' hyperarchiver start the api and dat servers') 5 | console.error('') 6 | console.error(' --dir= directory to store archives') 7 | console.error(' --httpPort=8080 http port for API and hyperdrive-http') 8 | console.error(' --datPort=3282 port for Dat discovery swarm') 9 | console.error(' --archiveHttp serve archives over http') 10 | console.error(' --debug show debugging output') 11 | console.error(' --help, -h show usage guide') 12 | console.error('') 13 | process.exit(1) 14 | } 15 | --------------------------------------------------------------------------------