├── .gitignore ├── LICENSE ├── README.md ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.db 3 | -------------------------------------------------------------------------------- /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 | # hyperirc 2 | 3 | Read IRC through hypercore. 4 | 5 | ## What is it? 6 | 7 | [Hypercore](https://github.com/mafintosh/hypercore) is the underlying p2p network that powers [Dat](https://dat-data.com) 8 | 9 | Hyperirc is a bot that mirrors irc channels to a hypercore append-only log. 10 | This allows you to read an IRC channel using the hypercore p2p network. Anyone who is reading the irc logs is also helping hosting them. 11 | 12 | ## Usage 13 | 14 | ``` 15 | npm install -g hyperirc 16 | ``` 17 | 18 | ## Usage 19 | 20 | First, somewhere, start a mirror. 21 | 22 | ``` sh 23 | hyperirc --mirror=an-irc-channel 24 | ``` 25 | 26 | This will mirror `an-irc-channel` on freenode into a hyperdrive feed. 27 | The feed key is printed out. 28 | 29 | Then on a couple of other computers run this to tail the channel 30 | 31 | ``` sh 32 | hyperirc --tail=the-key-printed-out-above 33 | ``` 34 | 35 | Thats it! Every peer tailing (and the peer mirroring) will join the p2p network and help eachother host the irc logs. 36 | 37 | By default, hyperirc will save its database under `~/.hyperirc`. You may choose your own location. 38 | 39 | ```sh 40 | hyperirc --mirror=an-irc-channel --database=/path/to/db 41 | ``` 42 | 43 | For more options run `hyperirc --help`. 44 | 45 | ## Browser support 46 | 47 | You can also seed the irc logs to the browser by adding the `--webrtc` option. This will make hyperirc join a p2p webrtc swarm 48 | as well. 49 | 50 | ``` sh 51 | hyperirc --tail=the-key-printed-out-above --webrtc 52 | ``` 53 | 54 | To view the logs in the browser visit the static website hosted here, https://github.com/mafintosh/hyperirc-www 55 | 56 | ## Mirrored IRC channels 57 | 58 | * #dat on freenode, `hyperirc --tail=227d9212ee85c0f14416885c5390f2d270ba372252e781bf45a6b7056bb0a1b5` 59 | * #sciencefair on freenode, `hyperirc --tail=d5ec4f72d2dfde000510b1d84912242a2c10400bbd9721311a548a1e3a7913b5` 60 | * #beakerbrowser on freenode, `hyperirc --tail=18bab41fd4cfd47425226bebf6030ef270091481b39a1959768c2ccc90db02a3` 61 | 62 | If you mirror a channel open a PR and add your key. 63 | 64 | ## License 65 | 66 | MIT 67 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var irc = require('irc') 4 | var hypercore = require('hypercore') 5 | var swarm = require('discovery-swarm') 6 | var defaults = require('dat-swarm-defaults') 7 | var minimist = require('minimist') 8 | var home = require('os-homedir') 9 | var path = require('path') 10 | 11 | var argv = minimist(process.argv.slice(2), { 12 | alias: { 13 | mirror: 'channel', 14 | tail: 'feed', 15 | channel: 'c', 16 | database: 'd', 17 | feed: 'f', 18 | server: 's', 19 | name: 'n' 20 | }, 21 | default: { 22 | server: 'irc.freenode.net', 23 | signalhub: 'https://signalhub.mafintosh.com' 24 | } 25 | }) 26 | 27 | if (!argv.channel && !argv.feed || argv.help) { 28 | console.error('Usage: hyperirc [options]') 29 | console.error() 30 | console.error(' --mirror=[channel-name] IRC channel to mirror') 31 | console.error(' --server=[irc-server] Optional IRC server. Defaults to freenode') 32 | console.error(' --tail=[feed-key] A mirrored channel to tail') 33 | console.error(' --database=[db-path] Path for database. Defaults to ~/.hyperirc') 34 | console.error(' --webrtc Share over webrtc as well.') 35 | console.error(' --all Print the entire channel log.') 36 | console.error() 37 | console.error('You must specify either --tail or --mirror') 38 | console.error() 39 | process.exit(1) 40 | } 41 | 42 | if (argv.channel) argv.channel = argv.channel.replace(/^#/, '') 43 | 44 | var db = argv.database || path.join(home(), '.hyperirc', argv.channel || argv.feed) 45 | var feed = hypercore(db, argv.feed, {valueEncoding: 'json'}) 46 | var peerCnt = 0 47 | 48 | feed.ready(function () { 49 | var sw = swarm(defaults({ 50 | hash: false, 51 | stream: function () { 52 | return feed.replicate({ 53 | live: true 54 | }) 55 | } 56 | })) 57 | 58 | if (argv.channel) { 59 | var channel = '#' + argv.channel 60 | var name = argv.name || 'hyperirc-' + feed.key.toString('hex').slice(0, 12) 61 | var client = new irc.Client(argv.server, name, { 62 | channels: [channel] 63 | }) 64 | 65 | if (!feed.length) feed.append({channel: channel}) 66 | 67 | client.on('message', function (from, to, message) { 68 | feed.append({ from: from, message: message, timestamp: Date.now() }) 69 | }) 70 | 71 | console.log('Mirroring ' + channel + ' to ' + feed.key.toString('hex')) 72 | } 73 | 74 | feed.get(0, function (err, data) { 75 | if (err) throw err 76 | 77 | if (!argv.channel) { 78 | console.log('Tailing ' + data.channel + ' over hypercore') 79 | } 80 | 81 | var end = feed.length 82 | 83 | if (!argv.all) { 84 | feed.once('sync', function () { 85 | if (feed.length - end > 10) { 86 | stream.destroy() 87 | console.log('(skipping to latest messages)') 88 | tail() 89 | } 90 | }) 91 | } 92 | 93 | var stream = tail() 94 | 95 | function tail () { 96 | var stream = feed.createReadStream({live: true, start: argv.all ? 1 : Math.max(feed.length - 10, 1)}) 97 | .on('data', function (data) { 98 | console.log(`${Date(data.timestamp).toLocaleString()} ${data.from} > ${data.message}`) 99 | }) 100 | 101 | return stream 102 | } 103 | }) 104 | 105 | sw.join(feed.discoveryKey) 106 | sw.on('connection', function (peer) { 107 | console.log('(peer joined, %d total)', ++peerCnt) 108 | peer.on('close', function () { 109 | console.log('(peer left, %d total)', --peerCnt) 110 | }) 111 | }) 112 | 113 | if (argv.webrtc) { 114 | var signalhub = require('signalhub') 115 | var webrtcSwarm = require('webrtc-swarm') 116 | var pump = require('pump') 117 | var wsw = webrtcSwarm(signalhub('hyperirc-' + feed.discoveryKey.toString('hex'), argv.signalhub), { 118 | wrtc: require('electron-webrtc')({headless: true}) 119 | }) 120 | 121 | wsw.on('peer', function (connection) { 122 | console.log('(webrtc peer joined, %d total', ++peerCnt) 123 | var peer = feed.replicate() 124 | pump(peer, connection, peer, function () { 125 | console.log('(webrtc peer left, %d total', --peerCnt) 126 | }) 127 | }) 128 | } 129 | }) 130 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hyperirc", 3 | "version": "3.0.0", 4 | "description": "Read IRC through hypercore", 5 | "main": "index.js", 6 | "bin": { 7 | "hyperirc": "./index.js" 8 | }, 9 | "dependencies": { 10 | "dat-swarm-defaults": "^1.0.0", 11 | "discovery-swarm": "^4.4.0", 12 | "hypercore": "^6.6.3", 13 | "irc": "^0.5.2", 14 | "minimist": "^1.2.0", 15 | "os-homedir": "^1.0.1" 16 | }, 17 | "devDependencies": { 18 | "standard": "^7.1.2" 19 | }, 20 | "scripts": { 21 | "test": "standard" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/mafintosh/hyperirc.git" 26 | }, 27 | "author": "Mathias Buus (@mafintosh)", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/mafintosh/hyperirc/issues" 31 | }, 32 | "homepage": "https://github.com/mafintosh/hyperirc", 33 | "optionalDependencies": { 34 | "electron-webrtc": "^0.2.12", 35 | "pump": "^1.0.1", 36 | "signalhub": "^4.5.1", 37 | "webrtc-swarm": "^2.4.0" 38 | } 39 | } 40 | --------------------------------------------------------------------------------