├── .gitignore ├── README.md ├── example.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hypercore-stats-server 2 | 3 | Server for sending hypercore/hyperdrive stats over server-side events. 4 | 5 | ``` 6 | npm install hypercore-stats-server 7 | ``` 8 | 9 | ### Example 10 | 11 | ```` 12 | var hyperdiscovery = require('hyperdiscovery') 13 | var hyperdrive = require('hyperdrive') 14 | var http = require('http') 15 | var ram = require('random-access-memory') 16 | var stats = require('hypercore-stats-server') 17 | 18 | // create a server 19 | http.createServer(function (req, res) { 20 | 21 | // set up a drive 22 | var drive = hyperdrive(ram, '72671c5004d3b956791b6ffca7f05025d62309feaf99cde04c6f434189694291') 23 | hyperdiscovery(archive) 24 | 25 | // stats for the given drive will be sent to /events 26 | if (req.url === '/events') stats(archive, res) 27 | else res.end('hi. hit /events for stat events') 28 | }).listen(10000) 29 | ``` 30 | 31 | ### API 32 | 33 | ##### `stats(archive, response)` 34 | 35 | Takes a hyperdrive archive and an `http` response object. Will return server side events to the response object that represent stats as they are downloaded through the swarm. 36 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var swarm = require('hyperdrive-archive-swarm') 2 | var hyperdrive = require('hyperdrive') 3 | var http = require('http') 4 | var memdb = require('memdb') 5 | var stats = require('./') 6 | 7 | http.createServer(function (req, res) { 8 | // set up a drive 9 | var drive = hyperdrive(memdb()) 10 | var archive = drive.createArchive('2d8186c581cd9c1b4f45e42eb765cebcba983feb8a0525d7bffee1ce3b7a9471') 11 | 12 | // attach the swarm 13 | swarm(archive) 14 | 15 | // stats for the given drive will be sent to /events 16 | if (req.url === '/events') stats(archive, res) 17 | else res.end('hi. hit /events for stat events') 18 | }).listen(10000) 19 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (feed, res) { 2 | res.setHeader('Content-Type', 'text/event-stream; charset=utf-8') 3 | 4 | var archive = feed.metadata ? feed : null 5 | 6 | if (archive) { 7 | feed = archive.metadata 8 | } 9 | 10 | var key = feed.key.toString('hex') 11 | 12 | send(res, {type: 'key', key: key}) 13 | 14 | feed.ready(function () { 15 | if (archive) track(feed, 'metadata') 16 | else track(feed, null) 17 | }) 18 | 19 | send(res, {type: 'peer-update', peers: feed.peers.length}) 20 | 21 | feed.on('peer-add', onpeeradd) 22 | feed.on('peer-remove', onpeerremove) 23 | 24 | if (archive) { 25 | if (archive.content) { 26 | track(archive.content, 'content') 27 | } else { 28 | archive.on('content', function () { 29 | track(archive.content, 'content') 30 | }) 31 | } 32 | } 33 | 34 | res.on('close', function () { 35 | feed.removeListener('peer-add', onpeeradd) 36 | feed.removeListener('peer-remove', onpeerremove) 37 | }) 38 | 39 | function track (feed, name) { 40 | send(res, {type: 'feed', name: name, key: key, blocks: bitfield(feed), bytes: feed.byteLength}) 41 | 42 | feed.on('update', onupdate) 43 | feed.on('append', onupdate) 44 | feed.on('download', ondownload) 45 | feed.on('upload', onupload) 46 | 47 | res.on('close', function () { 48 | feed.removeListener('update', onupdate) 49 | feed.removeListener('download', ondownload) 50 | feed.removeListener('upload', onupload) 51 | }) 52 | 53 | function onupdate () { 54 | send(res, {type: 'update', name: name, key: key, blocks: bitfield(feed), bytes: feed.byteLength}) 55 | } 56 | 57 | function ondownload (index, data) { 58 | send(res, {type: 'download', name: name, index: index, bytes: data.length}) 59 | } 60 | 61 | function onupload (index, data) { 62 | send(res, {type: 'upload', name: name, index: index, bytes: data.length}) 63 | } 64 | } 65 | 66 | function onpeeradd () { 67 | send(res, {type: 'peer-update', peers: feed.peers.length}) 68 | } 69 | 70 | function onpeerremove () { 71 | send(res, {type: 'peer-update', peers: feed.peers.length}) 72 | } 73 | 74 | function bitfield (feed) { 75 | var list = [] 76 | for (var i = 0; i < feed.length; i++) { 77 | list.push(feed.has(i)) 78 | } 79 | return list 80 | } 81 | 82 | function send (res, message) { 83 | res.write('data: ' + JSON.stringify(message) + '\n\n') 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hypercore-stats-server", 3 | "version": "2.0.1", 4 | "description": "server for sending hypercore/hyperdrive stats over sse", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "devDependencies": { 10 | "hypercore-stats-ui": "^1.1.0" 11 | }, 12 | "scripts": { 13 | "start": "node example.js" 14 | }, 15 | "author": "Karissa McKelvey ", 16 | "license": "BSD-2-Clause" 17 | } 18 | --------------------------------------------------------------------------------