diff --git a/examples/http.js b/examples/http.js index ceacfd1b..96adc959 100644 --- a/examples/http.js +++ b/examples/http.js @@ -1,21 +1,21 @@ -;(function(){ - var cluster = require('cluster'); - if(cluster.isMaster){ - return cluster.fork() && cluster.on('exit', function(){ cluster.fork() }); - } - - var fs = require('fs'); - var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 }; - var Gun = require('../'); // require('gun') - - if(process.env.HTTPS_KEY){ - config.key = fs.readFileSync(process.env.HTTPS_KEY); - config.cert = fs.readFileSync(process.env.HTTPS_CERT); - config.server = require('https').createServer(config, Gun.serve(__dirname)); - } else { - config.server = require('http').createServer(Gun.serve(__dirname)); - } - - var gun = Gun({web: config.server.listen(config.port) }); - console.log('Relay peer started on port ' + config.port + ' with /gun'); -}()); \ No newline at end of file +;(function(){ + var cluster = require('cluster'); + if(cluster.isMaster){ + return cluster.fork() && cluster.on('exit', function(){ cluster.fork() }); + } + + var fs = require('fs'); + var config = { port: process.env.OPENSHIFT_NODEJS_PORT || process.env.VCAP_APP_PORT || process.env.PORT || process.argv[2] || 8765 }; + var Gun = require('../'); // require('gun') + + if(process.env.HTTPS_KEY){ + config.key = fs.readFileSync(process.env.HTTPS_KEY); + config.cert = fs.readFileSync(process.env.HTTPS_CERT); + config.server = require('https').createServer(config, Gun.serve(__dirname)); + } else { + config.server = require('http').createServer(Gun.serve(__dirname)); + } + + var gun = Gun({web: config.server.listen(config.port)}); + console.log('Relay peer started on port ' + config.port + ' with /gun'); +}()); diff --git a/gun.js b/gun.js index 6cb9957e..c825123f 100644 --- a/gun.js +++ b/gun.js @@ -1976,9 +1976,8 @@ if(!raw){ return } var dup = ctx.dup, id, hash, msg, tmp = raw[0]; if(opt.pack <= raw.length){ return mesh.say({dam: '!', err: "Message too big!"}, peer) } - try{msg = JSON.parse(raw); - }catch(e){opt.log('DAM JSON parse error', e)} if('{' === tmp){ + try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } if(dup.check(id = msg['#'])){ return } dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. @@ -2004,6 +2003,7 @@ return; } else if('[' === tmp){ + try{msg = JSON.parse(raw);}catch(e){opt.log('DAM JSON parse error', e)} if(!msg){ return } var i = 0, m; while(m = msg[i++]){ @@ -2063,11 +2063,12 @@ function send(raw, peer){ var wire = peer.wire; try{ - if(wire.send){ - wire.send(raw); - } else if(peer.say){ peer.say(raw); + } else + if(wire.send){ + if(wire.readyState && 1 != wire.readyState){ return } + wire.send(raw); } }catch(e){ (peer.queue = peer.queue || []).push(raw); diff --git a/lib/ipfs.js b/lib/ipfs.js new file mode 100644 index 00000000..789fdbb0 --- /dev/null +++ b/lib/ipfs.js @@ -0,0 +1,45 @@ +var opt = gun._.opt, u; +if (u === opt.ipfs.directory) { + opt.ipfs.directory = '/gun'; +} +opt.store = {}; +opt.store.put = function(file, data, cb){ + var uri = opt.ipfs.directory + '/' + file; + opt.ipfs.instance.files.write(uri, Buffer.from(JSON.stringify(data)), {create:true}) + .then(res => { + console.log('File written to IPFS directory', uri, res); + return opt.ipfs.instance.files.stat(opt.ipfs.directory, {hash:true}); + }).then(res => { + console.log('Directory hash:', res.hash); + return opt.ipfs.instance.name.publish(res.hash); + // currently throws "This command must be run in online mode. Try running 'ipfs daemon' first." for some reason, maybe js-ipfs IPNS not ready yet + }).then(res => { + console.log('IPFS put request successful:', res); + cb(undefined, 1); + }).catch(error => { + console.error('IPFS put request failed', error); + }); +} +opt.store.get = function(file, cb){ + var uri = opt.ipfs.directory + '/' + file; + opt.ipfs.instance.files.read(uri, {}) + .then(res => { + var data = JSON.parse(res.toString()); + console.log(uri + ' was loaded from ipfs:', data); + cb(data); + }); +} +opt.store.list = function(cb){ + var stream = opt.ipfs.files.lsReadableStream(opt.ipfs.directory); + + stream.on('data', (file) => { + console.log('ls', file.name); + if (cb(file.name)) { + stream.destroy(); + } + }); + + stream.on('finish', () => { + cb(); + }); +} diff --git a/lib/multicast.js b/lib/multicast.js new file mode 100644 index 00000000..a49ca9dc --- /dev/null +++ b/lib/multicast.js @@ -0,0 +1,63 @@ +var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); + +Gun.on('create', function(root){ + this.to.next(root); + var opt = root.opt; + if(false === opt.multicast){ return } + + var udp = opt.multicast = opt.multicast || {}; + udp.address = udp.address || '233.255.255.255'; + udp.pack = udp.pack || 50000; // UDP messages limited to 65KB. + udp.port = udp.port || 23456; + + var noop = function(){}, port; + + var dgram = require("dgram"); + var socket = dgram.createSocket({type: "udp4", reuseAddr: true}); + socket.bind(udp.port); + + socket.on("listening", function() { + socket.addMembership(udp.address); + udp.peer = {url: udp.address + ':' + udp.port, wire: socket}; + + udp.peer.say = function(raw){ + var buf = Buffer.from(raw, 'utf8'); + if(udp.pack <= buf.length){ // message too big!!! + return; + } + socket.send(buf, 0, buf.length, udp.port, udp.address, noop); + } + opt.mesh.hi(udp.peer); + + console.log('multicasting on', udp.peer.url); + return; // below code only needed for when WebSocket connections desired! + setInterval(function broadcast(){ + port = port || (opt.web && opt.web.address()||{}).port; + if(!port){ return } + udp.peer.say(JSON.stringify({id: opt.pid || (opt.pid = Math.random().toString(36).slice(2)), port: port})); + }, 1000); + }); + + socket.on("message", function(raw, info) { try { + if(!raw){ return } + raw = raw.toString('utf8'); + opt.mesh.hear(raw, udp.peer); + + return; // below code only needed for when WebSocket connections desired! + var message; + message = JSON.parse(raw.toString('utf8')); + + if(opt.pid === message.id){ return } // ignore self + + var url = 'http://' + info.address + ':' + (port || (opt.web && opt.web.address()||{}).port) + '/gun'; + if(root.opt.peers[url]){ return } + + console.log('discovered', url, message, info); + root.$.opt(url); + + } catch(e){ + console.log('multicast error', e, raw); + return; + } }); + +}); diff --git a/lib/server.js b/lib/server.js index 7870006c..509af9e5 100644 --- a/lib/server.js +++ b/lib/server.js @@ -16,6 +16,7 @@ //try{require('../axe');}catch(e){} require('./file'); require('./evict'); + require('./multicast'); if('debug' === process.env.GUN_ENV){ require('./debug') } module.exports = Gun; -}()); \ No newline at end of file +}()); diff --git a/lib/wire.js b/lib/wire.js index 5e74b6b3..c8b63505 100644 --- a/lib/wire.js +++ b/lib/wire.js @@ -74,7 +74,7 @@ Gun.on('opt', function(root){ wire.on('message', function(msg){ opt.mesh.hear(msg.data || msg, peer); }); - wire.on('close', function(){ + wire.on('close', function(a,b,c){ opt.mesh.bye(peer); }); wire.on('error', function(e){}); diff --git a/package-lock.json b/package-lock.json index 7fa8f7c3..c46e5dda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gun", - "version": "0.9.999999", + "version": "0.2019.413", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1246,9 +1246,9 @@ "dev": true }, "ws": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.0.tgz", - "integrity": "sha512-c18dMeW+PEQdDFzkhDsnBAlS4Z8KGStBQQUcQ5mf7Nf689jyGk0594L+i9RaQuf4gog6SvWLJorz2NfSaqxZ7w==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", "requires": { "async-limiter": "~1.0.0" } diff --git a/package.json b/package.json index 658a6ac7..badb8ab8 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "node": ">=0.8.4" }, "dependencies": { - "ws": "~>5.2.0" + "ws": "~>6.2.1" }, "optionalDependencies": { "text-encoding": "^0.7.0",