forked from snxraven/LinkUp-P2P-Chat
Up to date fork #1
301
app.js
301
app.js
@ -38,161 +38,165 @@ function getRandomPort() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initialize() {
|
async function initialize() {
|
||||||
swarm = new Hyperswarm();
|
try {
|
||||||
|
swarm = new Hyperswarm();
|
||||||
|
|
||||||
servePort = getRandomPort();
|
servePort = getRandomPort();
|
||||||
const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => drive });
|
const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => drive });
|
||||||
await serve.ready();
|
await serve.ready();
|
||||||
console.log('Listening on http://localhost:' + serve.address().port);
|
console.log('Listening on http://localhost:' + serve.address().port);
|
||||||
|
|
||||||
const registerForm = document.querySelector('#register-form');
|
const registerForm = document.querySelector('#register-form');
|
||||||
const selectAvatarButton = document.querySelector('#select-avatar');
|
const selectAvatarButton = document.querySelector('#select-avatar');
|
||||||
const createChatRoomButton = document.querySelector('#create-chat-room');
|
const createChatRoomButton = document.querySelector('#create-chat-room');
|
||||||
const joinChatRoomButton = document.querySelector('#join-chat-room');
|
const joinChatRoomButton = document.querySelector('#join-chat-room');
|
||||||
const messageForm = document.querySelector('#message-form');
|
const messageForm = document.querySelector('#message-form');
|
||||||
const toggleSetupBtn = document.querySelector('#toggle-setup-btn');
|
const toggleSetupBtn = document.querySelector('#toggle-setup-btn');
|
||||||
const removeRoomBtn = document.querySelector('#remove-room-btn');
|
const removeRoomBtn = document.querySelector('#remove-room-btn');
|
||||||
const attachFileButton = document.getElementById('attach-file');
|
const attachFileButton = document.getElementById('attach-file');
|
||||||
const fileInput = document.getElementById('file-input');
|
const fileInput = document.getElementById('file-input');
|
||||||
const talkButton = document.getElementById('talk-btn');
|
const talkButton = document.getElementById('talk-btn');
|
||||||
|
|
||||||
if (registerForm) {
|
if (registerForm) {
|
||||||
registerForm.addEventListener('submit', registerUser);
|
registerForm.addEventListener('submit', registerUser);
|
||||||
}
|
|
||||||
if (selectAvatarButton) {
|
|
||||||
selectAvatarButton.addEventListener('click', () => {
|
|
||||||
document.querySelector('#avatar-file').click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (createChatRoomButton) {
|
|
||||||
createChatRoomButton.addEventListener('click', createChatRoom);
|
|
||||||
}
|
|
||||||
if (joinChatRoomButton) {
|
|
||||||
joinChatRoomButton.addEventListener('click', joinChatRoom);
|
|
||||||
}
|
|
||||||
if (messageForm) {
|
|
||||||
messageForm.addEventListener('submit', sendMessage);
|
|
||||||
}
|
|
||||||
if (toggleSetupBtn) {
|
|
||||||
toggleSetupBtn.addEventListener('click', toggleSetupView);
|
|
||||||
}
|
|
||||||
if (removeRoomBtn) {
|
|
||||||
removeRoomBtn.addEventListener('click', () => {
|
|
||||||
const topic = document.querySelector('#chat-room-topic').innerText;
|
|
||||||
leaveRoom(topic);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (attachFileButton) {
|
|
||||||
attachFileButton.addEventListener('click', () => fileInput.click());
|
|
||||||
}
|
|
||||||
if (fileInput) {
|
|
||||||
fileInput.addEventListener('change', handleFileInput);
|
|
||||||
}
|
|
||||||
if (talkButton) {
|
|
||||||
setupTalkButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
const configExists = fs.existsSync("./config.json");
|
|
||||||
if (configExists) {
|
|
||||||
config = JSON.parse(fs.readFileSync("./config.json", 'utf8'));
|
|
||||||
console.log("Read config from file:", config);
|
|
||||||
// Update port in URLs
|
|
||||||
config.userAvatar = updatePortInUrl(config.userAvatar);
|
|
||||||
config.rooms.forEach(room => {
|
|
||||||
room.alias = room.alias || truncateHash(room.topic);
|
|
||||||
});
|
|
||||||
for (let user in config.registeredUsers) {
|
|
||||||
config.registeredUsers[user] = updatePortInUrl(config.registeredUsers[user]);
|
|
||||||
}
|
}
|
||||||
|
if (selectAvatarButton) {
|
||||||
renderRoomList(); // Render the room list with aliases
|
selectAvatarButton.addEventListener('click', () => {
|
||||||
|
document.querySelector('#avatar-file').click();
|
||||||
// Connect to all rooms on startup
|
|
||||||
for (const room of config.rooms) {
|
|
||||||
const topicBuffer = b4a.from(room.topic, 'hex');
|
|
||||||
await joinSwarm(topicBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const registerDiv = document.querySelector('#register');
|
|
||||||
if (registerDiv && !configExists) {
|
|
||||||
registerDiv.classList.remove('hidden');
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter.on('onMessage', async (messageObj) => {
|
|
||||||
console.log('Received message:', messageObj); // Debugging log
|
|
||||||
|
|
||||||
if (messageObj.type === 'icon') {
|
|
||||||
const username = messageObj.username;
|
|
||||||
if (messageObj.avatar) {
|
|
||||||
const avatarBuffer = b4a.from(messageObj.avatar, 'base64');
|
|
||||||
await drive.put(`/icons/${username}.png`, avatarBuffer);
|
|
||||||
updateIcon(username, avatarBuffer);
|
|
||||||
} else {
|
|
||||||
console.error('Received icon message with missing avatar data:', messageObj);
|
|
||||||
}
|
|
||||||
} else if (messageObj.type === 'file') {
|
|
||||||
if (messageObj.file && messageObj.fileName) {
|
|
||||||
const fileBuffer = b4a.from(messageObj.file, 'base64');
|
|
||||||
await drive.put(`/files/${messageObj.fileName}`, fileBuffer);
|
|
||||||
const fileUrl = `http://localhost:${servePort}/files/${messageObj.fileName}`;
|
|
||||||
addFileMessage(messageObj.name, messageObj.fileName, updatePortInUrl(fileUrl), messageObj.fileType, updatePortInUrl(messageObj.avatar), messageObj.topic);
|
|
||||||
} else {
|
|
||||||
console.error('Received file message with missing file data or fileName:', messageObj);
|
|
||||||
}
|
|
||||||
} else if (messageObj.type === 'message') {
|
|
||||||
onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar, messageObj.topic);
|
|
||||||
} else if (messageObj.type === 'audio') {
|
|
||||||
const audioBuffer = b4a.from(messageObj.audio, 'base64');
|
|
||||||
const filePath = `/audio/${Date.now()}.webm`;
|
|
||||||
await drive.put(filePath, audioBuffer);
|
|
||||||
const audioUrl = `http://localhost:${servePort}${filePath}`;
|
|
||||||
addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic);
|
|
||||||
} else {
|
|
||||||
console.error('Received unknown message type:', messageObj);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
swarm.on('connection', async (connection, info) => {
|
|
||||||
peerCount++;
|
|
||||||
updatePeerCount();
|
|
||||||
console.log('Peer connected, current peer count:', peerCount);
|
|
||||||
|
|
||||||
// Send the current user's icon to the new peer
|
|
||||||
const iconBuffer = await drive.get(`/icons/${config.userName}.png`);
|
|
||||||
if (iconBuffer) {
|
|
||||||
const iconMessage = JSON.stringify({
|
|
||||||
type: 'icon',
|
|
||||||
username: config.userName,
|
|
||||||
avatar: b4a.toString(iconBuffer, 'base64'),
|
|
||||||
});
|
});
|
||||||
connection.write(iconMessage);
|
}
|
||||||
|
if (createChatRoomButton) {
|
||||||
|
createChatRoomButton.addEventListener('click', createChatRoom);
|
||||||
|
}
|
||||||
|
if (joinChatRoomButton) {
|
||||||
|
joinChatRoomButton.addEventListener('click', joinChatRoom);
|
||||||
|
}
|
||||||
|
if (messageForm) {
|
||||||
|
messageForm.addEventListener('submit', sendMessage);
|
||||||
|
}
|
||||||
|
if (toggleSetupBtn) {
|
||||||
|
toggleSetupBtn.addEventListener('click', toggleSetupView);
|
||||||
|
}
|
||||||
|
if (removeRoomBtn) {
|
||||||
|
removeRoomBtn.addEventListener('click', () => {
|
||||||
|
const topic = document.querySelector('#chat-room-topic').innerText;
|
||||||
|
leaveRoom(topic);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (attachFileButton) {
|
||||||
|
attachFileButton.addEventListener('click', () => fileInput.click());
|
||||||
|
}
|
||||||
|
if (fileInput) {
|
||||||
|
fileInput.addEventListener('change', handleFileInput);
|
||||||
|
}
|
||||||
|
if (talkButton) {
|
||||||
|
setupTalkButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.on('data', (data) => {
|
const configExists = fs.existsSync("./config.json");
|
||||||
const messageObj = JSON.parse(data.toString());
|
if (configExists) {
|
||||||
eventEmitter.emit('onMessage', messageObj);
|
config = JSON.parse(fs.readFileSync("./config.json", 'utf8'));
|
||||||
|
console.log("Read config from file:", config);
|
||||||
|
// Update port in URLs
|
||||||
|
config.userAvatar = updatePortInUrl(config.userAvatar);
|
||||||
|
config.rooms.forEach(room => {
|
||||||
|
room.alias = room.alias || truncateHash(room.topic);
|
||||||
|
});
|
||||||
|
for (let user in config.registeredUsers) {
|
||||||
|
config.registeredUsers[user] = updatePortInUrl(config.registeredUsers[user]);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderRoomList(); // Render the room list with aliases
|
||||||
|
|
||||||
|
// Connect to all rooms on startup
|
||||||
|
for (const room of config.rooms) {
|
||||||
|
const topicBuffer = b4a.from(room.topic, 'hex');
|
||||||
|
await joinSwarm(topicBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const registerDiv = document.querySelector('#register');
|
||||||
|
if (registerDiv && !configExists) {
|
||||||
|
registerDiv.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
eventEmitter.on('onMessage', async (messageObj) => {
|
||||||
|
console.log('Received message:', messageObj); // Debugging log
|
||||||
|
|
||||||
|
if (messageObj.type === 'icon') {
|
||||||
|
const username = messageObj.username;
|
||||||
|
if (messageObj.avatar) {
|
||||||
|
const avatarBuffer = b4a.from(messageObj.avatar, 'base64');
|
||||||
|
await drive.put(`/icons/${username}.png`, avatarBuffer);
|
||||||
|
updateIcon(username, avatarBuffer);
|
||||||
|
} else {
|
||||||
|
console.error('Received icon message with missing avatar data:', messageObj);
|
||||||
|
}
|
||||||
|
} else if (messageObj.type === 'file') {
|
||||||
|
if (messageObj.file && messageObj.fileName) {
|
||||||
|
const fileBuffer = b4a.from(messageObj.file, 'base64');
|
||||||
|
await drive.put(`/files/${messageObj.fileName}`, fileBuffer);
|
||||||
|
const fileUrl = `http://localhost:${servePort}/files/${messageObj.fileName}`;
|
||||||
|
addFileMessage(messageObj.name, messageObj.fileName, updatePortInUrl(fileUrl), messageObj.fileType, updatePortInUrl(messageObj.avatar), messageObj.topic);
|
||||||
|
} else {
|
||||||
|
console.error('Received file message with missing file data or fileName:', messageObj);
|
||||||
|
}
|
||||||
|
} else if (messageObj.type === 'message') {
|
||||||
|
onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar, messageObj.topic);
|
||||||
|
} else if (messageObj.type === 'audio') {
|
||||||
|
const audioBuffer = b4a.from(messageObj.audio, 'base64');
|
||||||
|
const filePath = `/audio/${Date.now()}.webm`;
|
||||||
|
await drive.put(filePath, audioBuffer);
|
||||||
|
const audioUrl = `http://localhost:${servePort}${filePath}`;
|
||||||
|
addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic);
|
||||||
|
} else {
|
||||||
|
console.error('Received unknown message type:', messageObj);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.on('close', () => {
|
swarm.on('connection', async (connection, info) => {
|
||||||
peerCount--;
|
peerCount++;
|
||||||
updatePeerCount();
|
updatePeerCount();
|
||||||
console.log('Peer disconnected, current peer count:', peerCount);
|
console.log('Peer connected, current peer count:', peerCount);
|
||||||
|
|
||||||
|
// Send the current user's icon to the new peer
|
||||||
|
const iconBuffer = await drive.get(`/icons/${config.userName}.png`);
|
||||||
|
if (iconBuffer) {
|
||||||
|
const iconMessage = JSON.stringify({
|
||||||
|
type: 'icon',
|
||||||
|
username: config.userName,
|
||||||
|
avatar: b4a.toString(iconBuffer, 'base64'),
|
||||||
|
});
|
||||||
|
connection.write(iconMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.on('data', (data) => {
|
||||||
|
const messageObj = JSON.parse(data.toString());
|
||||||
|
eventEmitter.emit('onMessage', messageObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
connection.on('close', () => {
|
||||||
|
peerCount--;
|
||||||
|
updatePeerCount();
|
||||||
|
console.log('Peer disconnected, current peer count:', peerCount);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
swarm.on('error', (err) => {
|
swarm.on('error', (err) => {
|
||||||
console.error('Swarm error:', err);
|
console.error('Swarm error:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
swarm.on('close', () => {
|
swarm.on('close', () => {
|
||||||
console.log('Swarm closed');
|
console.log('Swarm closed');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize highlight.js once the DOM is fully loaded
|
// Initialize highlight.js once the DOM is fully loaded
|
||||||
document.addEventListener("DOMContentLoaded", (event) => {
|
document.addEventListener("DOMContentLoaded", (event) => {
|
||||||
hljs.highlightAll();
|
hljs.highlightAll();
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during initialization:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupTalkButton() {
|
function setupTalkButton() {
|
||||||
@ -321,14 +325,18 @@ async function joinChatRoom(e) {
|
|||||||
async function joinSwarm(topicBuffer) {
|
async function joinSwarm(topicBuffer) {
|
||||||
const topic = b4a.toString(topicBuffer, 'hex');
|
const topic = b4a.toString(topicBuffer, 'hex');
|
||||||
if (!activeRooms.some(room => room.topic === topic)) {
|
if (!activeRooms.some(room => room.topic === topic)) {
|
||||||
const discovery = swarm.join(topicBuffer, { client: true, server: true });
|
try {
|
||||||
await discovery.flushed();
|
const discovery = swarm.join(topicBuffer, { client: true, server: true });
|
||||||
|
await discovery.flushed();
|
||||||
|
|
||||||
activeRooms.push({ topic, discovery });
|
activeRooms.push({ topic, discovery });
|
||||||
|
|
||||||
console.log('Joined room:', topic); // Debugging log
|
console.log('Joined room:', topic); // Debugging log
|
||||||
|
|
||||||
renderMessagesForRoom(topic);
|
renderMessagesForRoom(topic);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error joining swarm for topic:', topic, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,6 +675,7 @@ function addAudioMessage(from, audioUrl, avatar, topic) {
|
|||||||
console.log(`Message for topic ${topic} not rendered because current topic is ${currentTopic}`); // Debugging log
|
console.log(`Message for topic ${topic} not rendered because current topic is ${currentTopic}`); // Debugging log
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function truncateHash(hash) {
|
function truncateHash(hash) {
|
||||||
return `${hash.slice(0, 6)}...${hash.slice(-6)}`;
|
return `${hash.slice(0, 6)}...${hash.slice(-6)}`;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user