commit b4b8bc94b6921be1716a70df67783231546b8e35 Author: William Mantly Date: Wed Aug 19 15:57:40 2020 -0400 beta diff --git a/app.js b/app.js new file mode 100755 index 0000000..dca7a95 --- /dev/null +++ b/app.js @@ -0,0 +1,30 @@ +#!/usr/bin/env nodejs + +const p2p = require('./peers') + +const args = process.argv.slice(1); + +const exec_name = args[0].split('/').pop(); +const server_port = args[1]; +const clients_list = args.slice(2); + +if(server_port){ + console.log('port:', server_port, 'clients:', clients_list) + +}else{ + console.error('Please supply the server port and list of clients to connect too;') + console.error(`${exec_name} ...` ) + console.error(`${exec_name} 7575 10.1.0.1:7575 10.2.0.1:7575 10.3.0.1:7575` ) + process.exit(0) +} + +p2p.listen(server_port); + +for(let client of clients_list){ + p2p.addPeer(client); +} + + +setTimeout(function(){ + p2p.broadcast({type:'topic', body:"yolo"}) +}, 10000); \ No newline at end of file diff --git a/client.js b/client.js new file mode 100644 index 0000000..71875a5 --- /dev/null +++ b/client.js @@ -0,0 +1,38 @@ +const net = require('net'); + +var connect = function(address, port){ + if(!port){ + let parse = address.split(':'); + address = parse[0]; + port = parse[1]; + } + + let socket = new net.Socket().connect(port, address); + + // socket.on('connect', function(){ + // console.log('client EVENT connect:', arguments); + // }); + + // socket.on('close', function(){ + // console.log('client EVENT close:', arguments); + // }); + + // socket.on('ready', function(){ + // console.log('client EVENT ready:', arguments); + // }); + + // socket.on('data', function(data){ + // console.log('client EVENT data:',data.toString(), socket.remoteAddress); + // }); + + + socket.on('error', function(){ + console.log('client EVENT error:', arguments); + }); + + + return socket; + +} + +module.exports = {connect} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5993c48 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "vpn-p2p", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/peers.js b/peers.js new file mode 100644 index 0000000..1e68afb --- /dev/null +++ b/peers.js @@ -0,0 +1,126 @@ +const TcpServer = require('./server'); +const TcpClient = require('./client'); +const crypto = require("crypto"); + +const peerID = crypto.randomBytes(16).toString("hex"); + +console.log('Peer ID:', peerID) + +let connectedPeers = {} +let peers = [] + +let addPeer = function(peer){ + if(peers.includes(peer)) return true; + peers.push(peer) +} + +setInterval(function(){ + let connected = Object.keys(connectedPeers).map(function(i){return connectedPeers[i].peerConnectAddress}) + console.log('interval', connected, Object.keys(connectedPeers)) + for(let peer of peers){ + if(!connected.includes(peer)){ + connectPeer(peer); + } + } +}, 1000); + + +let connectPeer = function(address, port) { + if(!port){ + let parse = address.split(':'); + address = parse[0]; + port = parse[1]; + } + + let peer = TcpClient.connect(address, port); + + peer.on('connect', function(){ + console.info(`Peer ${address} is now connected.`); + peer.peerConnectAddress = `${address}:${port}` + peer.write(JSON.stringify({type:"register", id: peerID})); + }); + + peer.on('close', function(){ + delete connectedPeers[peer.peerID]; + console.info(`Peer ${address} droped.`); + }); + + peer.on('data', function(data){ + read(JSON.parse(data.toString()), peer.remoteAddress, peer); + }); + +} + +let removePeer = function(peer){ + if(peer[peer.address]){ + peer.end(); + delete peer[peer.address] + } +} + +let listen = function(port){ + console.log('p2p listen', port) + let serverSocket = TcpServer(port); + + serverSocket.on('connection', function(clientSocket){ + console.log('server EVENT connection from client:', clientSocket.remoteAddress); + clientSocket.write(JSON.stringify({type:"register", id: peerID})); + + clientSocket.on('data', function(data){ + read(JSON.parse(data.toString()), clientSocket.remoteAddress, clientSocket); + }); + + clientSocket.on('close', function(){ + delete connectedPeers[clientSocket.peerID]; + console.info(`Peer ${clientSocket.remoteAddress} droped.`); + }); + + }); +} + + +let broadcast = function(message, exclude){ + exclude = [...exclude || [], ...[peerID]] + let sentTo = [] + + for(let _peerID in connectedPeers){ + if(exclude.includes(_peerID)) continue; + sentTo.push(_peerID); + } + + message.sentTo = [...new Set([...message.sentTo || [] ,...sentTo, ...[peerID]])] + message.from = message.from || peerID; + + for(let _peerID of sentTo){ + connectedPeers[_peerID].write(JSON.stringify(message)); + } +} + +let read = function(message, from, socket){ + if(message.type === "heartbeat"){ + console.log('heartbeat from', from); + return ; + } + + if(message.type === "register"){ + console.log('registering net peer', message.id, socket.remoteAddress) + if(Object.keys(connectedPeers).includes(message.id)){ + console.log(`Dropping ${message.id}, already connected`) + socket.end(); + }else{ + connectedPeers[message.id] = socket; + connectedPeers[message.id].peerID = message.id + } + } + + if(message.type === 'topic'){ + broadcast(message, message.sentTo); + console.log('p2p read:', message) + + // publish message locally + //publish(message.top, message.body) + } +} + + +module.exports = {broadcast, connectPeer, listen, addPeer} diff --git a/server.js b/server.js new file mode 100644 index 0000000..b0b81d8 --- /dev/null +++ b/server.js @@ -0,0 +1,51 @@ +const net = require('net') + +const server = function(port){ + + let serverSocket = new net.Server(function (clientSocket) { + + console.info(`server ${port}`) + + // clientSocket.on('connection', function(){ + // console.log('server-client EVENT connection:', arguments); + // }); + + // clientSocket.on('listening', function(){ + // console.log('server-client EVENT listening:', arguments); + // }); + + clientSocket.on('error', function(){ + console.log('server-client EVENT error:', arguments); + }); + + // clientSocket.on('data', function (data) { + // console.log('server-client EVENT data', data.toString(), clientSocket.remoteAddress); + // }); + + }) + serverSocket.listen(Number(port)); + + // serverSocket.on('connection', function(clientSocket){ + // console.log('server EVENT connection:', clientSocket.remoteAddress); + // }); + + // serverSocket.on('listening', function(){ + // console.log('server EVENT listening:', arguments); + // }); + + serverSocket.on('error', function(){ + console.log('server EVENT error:', arguments); + }); + + // serverSocket.on('data', function (data) { + // console.info('here...') + // // console.log(arguments, serverSocket); + // }); + + + return serverSocket; + +} + + +module.exports = server; \ No newline at end of file