UNPKG

friends-irc

Version:

Connects IRC and Friends channels by sending messages back and forth.

166 lines (130 loc) 4.13 kB
var events = require('events') var subleveldown = require('subleveldown') var swarm = require('webrtc-swarm') var signalhub = require('signalhub') var hyperlog = require('hyperlog') var ghsign = require('ghsign') var through = require('through2') var protobuf = require('protocol-buffers') var fs = require('fs') var request = require('request') var wrtc = require('wrtc') var messages = protobuf(fs.readFileSync(__dirname + '/../schema.proto')) module.exports = createSwarm ghsign = ghsign(function (username, cb) { fs.readFile('./public-keys/' + username + '.keys', 'utf-8', function (_, keys) { if (keys) return cb(null, keys) request('https://github.com/' + username + '.keys', function (_, response) { var keys = response.statusCode === 200 && response.body if (!keys) return cb(new Error('Could not find public keys for ' + username)) fs.mkdir('./public-keys', function () { fs.writeFile('./public-keys/' + username + '.keys', keys, function () { cb(null, keys) }) }) }) }) }) var verifiers = {} function createSwarm (db) { var emitter = new events.EventEmitter() var logs = {} emitter.logs = logs var sign var processor emitter.changes = function (name) { return logs[name] ? logs[name].changes : 0 } emitter.process = function (fn) { processor = fn Object.keys(logs).forEach(function (name) { startProcessor(logs[name]) }) } emitter.removeChannel = function (name) { var log = logs[name] if (!log) return delete logs[name] if (log.processing) log.processing.destroy() log.peers.forEach(function (p) { p.destroy() }) } emitter.addChannel = function (name) { if (logs[name]) return var log = logs[name] = hyperlog(subleveldown(db, name)) var id = 'friends-' + name var hub = signalhub('http://dev.mathiasbuus.eu:8080', id) var sw = swarm(hub, { wrtc: wrtc }) log.peers = [] sw.on('peer', function (p, id) { var stream = log.replicate({live: true}) log.peers.push(p) p.on('close', function () { var i = log.peers.indexOf(p) if (i > -1) log.peers.splice(i, 1) }) emitter.emit('peer', p, name, id, stream) stream.on('push', function () { emitter.emit('push', name) }) stream.on('pull', function () { emitter.emit('pull', name) }) p.pipe(stream).pipe(p) }) if (processor) startProcessor(log) } emitter.send = function (message, cb) { if (!sign && emitter.username) { sign = ghsign.signer(emitter.username) } var addMessage = function (m, sig) { var ch = message.channel || 'friends' emitter.addChannel(ch) var log = logs[ch] log.heads(function (err, heads) { if (err) return cb(err) log.add(heads, messages.SignedMessage.encode({signature: sig, message: m}), cb) }) } console.log(JSON.stringify(message, null, 4)) var m = messages.Message.encode(message) if (sign) { sign(m, function (err, sig) { if (err) return cb(err) addMessage(m, sig) }) return } addMessage(m, null) } function startProcessor (log) { log.ready(function () { if (log.processing) return var rs = log.processing = log.createReadStream({ live: true, since: Math.max(log.changes - 500, 0) }) rs.pipe(through.obj(function (data, enc, cb) { if (data.value.toString()[0] === '{') return cb() // old stuff var val = messages.SignedMessage.decode(data.value) var m = messages.Message.decode(val.message) var u = m.username var verify = verifiers[u] if (u && !verifiers[u]) verifiers[u] = verify = ghsign.verifier(u) m.change = data.change if (verify && val.signature) { verify(val.message, val.signature, function (_, valid) { m.valid = !!valid processor(m, cb) }) return } m.valid = false processor(m, cb) })) }) } return emitter }