Skip to content

Instantly share code, notes, and snippets.

@avinashtare
Created July 11, 2025 13:22
Show Gist options
  • Save avinashtare/561c134d7f233c61e7e77100e372bf07 to your computer and use it in GitHub Desktop.
Save avinashtare/561c134d7f233c61e7e77100e372bf07 to your computer and use it in GitHub Desktop.
True Peer To Peer Connection Chat APP Using Node.JS.
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