Created
July 11, 2025 13:22
-
-
Save avinashtare/561c134d7f233c61e7e77100e372bf07 to your computer and use it in GitHub Desktop.
True Peer To Peer Connection Chat APP Using Node.JS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const dgram = require('dgram'); | |
const readline = require('readline'); | |
const rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout | |
}); | |
function ask(question) { | |
return new Promise(resolve => rl.question(question, resolve)); | |
} | |
async function findMyIP() { | |
let req = await fetch("https://api64.ipify.org?format=json"); | |
req = await req.json(); | |
return req.ip; | |
} | |
findMyIP(); | |
(async () => { | |
// first find you ip | |
let myIP = await findMyIP(); | |
console.log("Your IP:", myIP); | |
const myPort = parseInt(await ask("Your port (e.g. 12345): ")); | |
const peerIP = (await ask("Peer's PUBLIC IP: ")).trim(); | |
const peerPort = parseInt(await ask("Peer's port: ")); | |
// start udp server | |
const socket = dgram.createSocket('udp4'); | |
let connectionEstablished = false; | |
// === Receive handler === | |
socket.on('message', (msg, rinfo) => { | |
const data = msg.toString(); | |
if (data === 'punch') { | |
socket.send('punch_ack', rinfo.port, rinfo.address); | |
} else if (data === 'punch_ack') { | |
if (!connectionEstablished) { | |
console.log(`\n✅ Hole punch successful with ${rinfo.address}:${rinfo.port}`); | |
connectionEstablished = true; | |
} | |
} else if (data === 'KEEP_ALIVE') { | |
// ignore | |
} else { | |
console.log(`\n[From ${rinfo.address}:${rinfo.port}]: ${data}`); | |
rl.prompt(true); | |
} | |
}); | |
socket.on('listening', () => { | |
const address = socket.address(); | |
console.log(`\n🔌 Listening on ${address.address}:${address.port}`); | |
}); | |
socket.bind(myPort); | |
// === Punch hole === | |
function punchLoop() { | |
let count = 0; | |
const interval = setInterval(() => { | |
if (connectionEstablished || count >= 20) { | |
clearInterval(interval); | |
if (!connectionEstablished) { | |
console.log("⚠️ Hole punching finished, but no ACK received."); | |
socket.close(); | |
process.exit() | |
} | |
return; | |
} | |
socket.send('punch', peerPort, peerIP); | |
count += 1; | |
}, 500); | |
} | |
// === Keep alive === | |
function keepAlive() { | |
setInterval(() => { | |
socket.send('KEEP_ALIVE', peerPort, peerIP); | |
}, 15000); | |
} | |
// === Chat loop === | |
function chatLoop() { | |
console.log("💬 You can now chat! Type messages below:"); | |
rl.on('line', line => { | |
socket.send(Buffer.from(line), peerPort, peerIP); | |
}); | |
} | |
// === Start everything === | |
punchLoop(); | |
keepAlive(); | |
const waitForConnection = setInterval(() => { | |
if (connectionEstablished) { | |
clearInterval(waitForConnection); | |
chatLoop(); | |
} | |
}, 1000); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment