From 9e6c803347f0a61925653eb51df3edaa10cb5388 Mon Sep 17 00:00:00 2001 From: Raven Scott Date: Sat, 8 Jun 2024 15:06:24 -0400 Subject: [PATCH] testing EventEmitter --- app.js | 521 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 267 insertions(+), 254 deletions(-) diff --git a/app.js b/app.js index ead03a2..1e0fb79 100644 --- a/app.js +++ b/app.js @@ -1,3 +1,4 @@ +import { EventEmitter } from 'events'; import Hyperswarm from 'hyperswarm'; import crypto from 'hypercore-crypto'; import b4a from 'b4a'; @@ -12,283 +13,295 @@ const drive = new Hyperdrive(store); await drive.ready(); -let swarm; -let userName = 'Anonymous'; -let userAvatar = ''; -let registeredUsers = JSON.parse(localStorage.getItem('registeredUsers')) || {}; -let peerCount = 0; -let currentRoom = null; +class ChatHandler extends EventEmitter { + constructor() { + super(); + this.userName = 'Anonymous'; + this.userAvatar = ''; + this.registeredUsers = JSON.parse(localStorage.getItem('registeredUsers')) || {}; + this.peerCount = 0; + this.currentRoom = null; + this.swarm = new Hyperswarm(); -async function initialize() { - swarm = new Hyperswarm(); - - const servePort = 1337; - const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => drive }); - await serve.ready(); - console.log('Listening on http://localhost:' + serve.address().port); - - const registerForm = document.querySelector('#register-form'); - const selectAvatarButton = document.querySelector('#select-avatar'); - const createChatRoomButton = document.querySelector('#create-chat-room'); - const joinChatRoomButton = document.querySelector('#join-chat-room'); - const messageForm = document.querySelector('#message-form'); - const toggleSetupBtn = document.querySelector('#toggle-setup-btn'); - const removeRoomBtn = document.querySelector('#remove-room-btn'); - - if (registerForm) { - 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', leaveRoom); + this.initialize(); } - const registerDiv = document.querySelector('#register'); - if (registerDiv) { - registerDiv.classList.remove('hidden'); - } + async initialize() { + const servePort = 1337; + const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => drive }); + await serve.ready(); + console.log('Listening on http://localhost:' + serve.address().port); - swarm.on('connection', async (connection, info) => { - peerCount++; - updatePeerCount(); + const registerForm = document.querySelector('#register-form'); + const selectAvatarButton = document.querySelector('#select-avatar'); + const createChatRoomButton = document.querySelector('#create-chat-room'); + const joinChatRoomButton = document.querySelector('#join-chat-room'); + const messageForm = document.querySelector('#message-form'); + const toggleSetupBtn = document.querySelector('#toggle-setup-btn'); + const removeRoomBtn = document.querySelector('#remove-room-btn'); - const iconBuffer = await drive.get(`/icons/${userName}.png`); - if (iconBuffer) { - const iconMessage = JSON.stringify({ - type: 'icon', - username: userName, - avatar: iconBuffer.toString('base64'), + if (registerForm) { + registerForm.addEventListener('submit', (e) => this.registerUser(e)); + } + if (selectAvatarButton) { + selectAvatarButton.addEventListener('click', () => { + document.querySelector('#avatar-file').click(); }); - connection.write(iconMessage); + } + if (createChatRoomButton) { + createChatRoomButton.addEventListener('click', () => this.createChatRoom()); + } + if (joinChatRoomButton) { + joinChatRoomButton.addEventListener('click', (e) => this.joinChatRoom(e)); + } + if (messageForm) { + messageForm.addEventListener('submit', (e) => this.sendMessage(e)); + } + if (toggleSetupBtn) { + toggleSetupBtn.addEventListener('click', () => this.toggleSetupView()); + } + if (removeRoomBtn) { + removeRoomBtn.addEventListener('click', () => this.leaveRoom()); } - connection.on('data', async (data) => { - const messageObj = JSON.parse(data.toString()); - if (messageObj.type === 'icon') { - const username = messageObj.username; - const avatarBuffer = Buffer.from(messageObj.avatar, 'base64'); - await drive.put(`/icons/${username}.png`, avatarBuffer); - updateIcon(username, avatarBuffer); - } else { - onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar); + const registerDiv = document.querySelector('#register'); + if (registerDiv) { + registerDiv.classList.remove('hidden'); + } + + this.swarm.on('connection', async (connection, info) => { + this.peerCount++; + this.updatePeerCount(); + + const iconBuffer = await drive.get(`/icons/${this.userName}.png`); + if (iconBuffer) { + const iconMessage = JSON.stringify({ + type: 'icon', + username: this.userName, + avatar: iconBuffer.toString('base64'), + }); + connection.write(iconMessage); } + + connection.on('data', (data) => this.emit('onMessage', data, connection)); + connection.on('close', () => { + this.peerCount--; + this.updatePeerCount(); + }); }); - connection.on('close', () => { - peerCount--; - updatePeerCount(); + this.swarm.on('error', (err) => { + console.error('Swarm error:', err); }); - }); - swarm.on('error', (err) => { - console.error('Swarm error:', err); - }); + this.swarm.on('close', () => { + console.log('Swarm closed'); + }); - swarm.on('close', () => { - console.log('Swarm closed'); - }); -} - -function registerUser(e) { - e.preventDefault(); - const regUsername = document.querySelector('#reg-username').value; - - if (registeredUsers[regUsername]) { - alert('Username already taken. Please choose another.'); - return; + this.on('onMessage', async (data, connection) => this.handleMessage(data, connection)); } - const avatarFile = document.querySelector('#avatar-file').files[0]; - if (avatarFile) { - const reader = new FileReader(); - reader.onload = (event) => { - const buffer = new Uint8Array(event.target.result); - drive.put(`/icons/${regUsername}.png`, buffer); - userAvatar = URL.createObjectURL(new Blob([buffer])); - registeredUsers[regUsername] = userAvatar; - localStorage.setItem('registeredUsers', JSON.stringify(registeredUsers)); - continueRegistration(regUsername); - }; - reader.readAsArrayBuffer(avatarFile); - } else { - continueRegistration(regUsername); - } -} + async registerUser(e) { + e.preventDefault(); + const regUsername = document.querySelector('#reg-username').value; -async function continueRegistration(regUsername) { - const loadingDiv = document.querySelector('#loading'); - const setupDiv = document.querySelector('#setup'); - - if (!regUsername) { - alert('Please enter a username.'); - return; - } - - userName = regUsername; - setupDiv.classList.remove('hidden'); - document.querySelector('#register').classList.add('hidden'); - loadingDiv.classList.add('hidden'); - - const randomTopic = crypto.randomBytes(32); - document.querySelector('#chat-room-topic').innerText = truncateHash(b4a.toString(randomTopic, 'hex')); -} - -async function createChatRoom() { - const topicBuffer = crypto.randomBytes(32); - const topic = b4a.toString(topicBuffer, 'hex'); - addRoomToList(topic); - joinSwarm(topicBuffer); -} - -async function joinChatRoom(e) { - e.preventDefault(); - const topicStr = document.querySelector('#join-chat-room-topic').value; - const topicBuffer = b4a.from(topicStr, 'hex'); - addRoomToList(topicStr); - joinSwarm(topicBuffer); -} - -async function joinSwarm(topicBuffer) { - if (currentRoom) { - currentRoom.destroy(); - } - - document.querySelector('#setup').classList.add('hidden'); - document.querySelector('#loading').classList.remove('hidden'); - - const discovery = swarm.join(topicBuffer, { client: true, server: true }); - await discovery.flushed(); - - const topic = b4a.toString(topicBuffer, 'hex'); - document.querySelector('#chat-room-topic').innerText = topic; // Set full topic here - document.querySelector('#loading').classList.add('hidden'); - document.querySelector('#chat').classList.remove('hidden'); - - currentRoom = discovery; - clearMessages(); -} - -function addRoomToList(topic) { - const roomList = document.querySelector('#room-list'); - const roomItem = document.createElement('li'); - roomItem.textContent = truncateHash(topic); - roomItem.dataset.topic = topic; - roomItem.addEventListener('click', () => switchRoom(topic)); - roomList.appendChild(roomItem); -} - -function switchRoom(topic) { - const topicBuffer = b4a.from(topic, 'hex'); - joinSwarm(topicBuffer); -} - -function leaveRoom() { - if (currentRoom) { - const topic = b4a.toString(currentRoom.topic, 'hex'); - const roomItem = document.querySelector(`li[data-topic="${topic}"]`); - if (roomItem) { - roomItem.remove(); + if (this.registeredUsers[regUsername]) { + alert('Username already taken. Please choose another.'); + return; + } + + const avatarFile = document.querySelector('#avatar-file').files[0]; + if (avatarFile) { + const reader = new FileReader(); + reader.onload = (event) => { + const buffer = new Uint8Array(event.target.result); + drive.put(`/icons/${regUsername}.png`, buffer); + this.userAvatar = URL.createObjectURL(new Blob([buffer])); + this.registeredUsers[regUsername] = this.userAvatar; + localStorage.setItem('registeredUsers', JSON.stringify(this.registeredUsers)); + this.continueRegistration(regUsername); + }; + reader.readAsArrayBuffer(avatarFile); + } else { + this.continueRegistration(regUsername); } - currentRoom.destroy(); - currentRoom = null; } - document.querySelector('#chat').classList.add('hidden'); - document.querySelector('#setup').classList.remove('hidden'); -} -function sendMessage(e) { - e.preventDefault(); - const message = document.querySelector('#message').value; - document.querySelector('#message').value = ''; + async continueRegistration(regUsername) { + const loadingDiv = document.querySelector('#loading'); + const setupDiv = document.querySelector('#setup'); - onMessageAdded(userName, message, userAvatar); + if (!regUsername) { + alert('Please enter a username.'); + return; + } - const messageObj = JSON.stringify({ - type: 'message', - name: userName, - message, - avatar: userAvatar, - timestamp: Date.now(), - }); + this.userName = regUsername; + setupDiv.classList.remove('hidden'); + document.querySelector('#register').classList.add('hidden'); + loadingDiv.classList.add('hidden'); - const peers = [...swarm.connections]; - for (const peer of peers) { - peer.write(messageObj); + const randomTopic = crypto.randomBytes(32); + document.querySelector('#chat-room-topic').innerText = this.truncateHash(b4a.toString(randomTopic, 'hex')); + } + + async createChatRoom() { + const topicBuffer = crypto.randomBytes(32); + const topic = b4a.toString(topicBuffer, 'hex'); + this.addRoomToList(topic); + this.joinSwarm(topicBuffer); + } + + async joinChatRoom(e) { + e.preventDefault(); + const topicStr = document.querySelector('#join-chat-room-topic').value; + const topicBuffer = b4a.from(topicStr, 'hex'); + this.addRoomToList(topicStr); + this.joinSwarm(topicBuffer); + } + + async joinSwarm(topicBuffer) { + if (this.currentRoom) { + this.currentRoom.destroy(); + } + + document.querySelector('#setup').classList.add('hidden'); + document.querySelector('#loading').classList.remove('hidden'); + + const discovery = this.swarm.join(topicBuffer, { client: true, server: true }); + await discovery.flushed(); + + const topic = b4a.toString(topicBuffer, 'hex'); + document.querySelector('#chat-room-topic').innerText = topic; // Set full topic here + document.querySelector('#loading').classList.add('hidden'); + document.querySelector('#chat').classList.remove('hidden'); + + this.currentRoom = discovery; + this.clearMessages(); + } + + addRoomToList(topic) { + const roomList = document.querySelector('#room-list'); + const roomItem = document.createElement('li'); + roomItem.textContent = this.truncateHash(topic); + roomItem.dataset.topic = topic; + roomItem.addEventListener('click', () => this.switchRoom(topic)); + roomList.appendChild(roomItem); + } + + switchRoom(topic) { + const topicBuffer = b4a.from(topic, 'hex'); + this.joinSwarm(topicBuffer); + } + + leaveRoom() { + if (this.currentRoom) { + const topic = b4a.toString(this.currentRoom.topic, 'hex'); + const roomItem = document.querySelector(`li[data-topic="${topic}"]`); + if (roomItem) { + roomItem.remove(); + } + this.currentRoom.destroy(); + this.currentRoom = null; + } + document.querySelector('#chat').classList.add('hidden'); + document.querySelector('#setup').classList.remove('hidden'); + } + + sendMessage(e) { + e.preventDefault(); + const message = document.querySelector('#message').value; + document.querySelector('#message').value = ''; + + this.onMessageAdded(this.userName, message, this.userAvatar); + + const messageObj = JSON.stringify({ + type: 'message', + name: this.userName, + message, + avatar: this.userAvatar, + timestamp: Date.now(), + }); + + const peers = [...this.swarm.connections]; + for (const peer of peers) { + peer.write(messageObj); + } + } + + async handleMessage(data, connection) { + const messageObj = JSON.parse(data.toString()); + if (messageObj.type === 'icon') { + const username = messageObj.username; + const avatarBuffer = Buffer.from(messageObj.avatar, 'base64'); + await drive.put(`/icons/${username}.png`, avatarBuffer); + this.updateIcon(username, avatarBuffer); + } else { + this.onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar); + } + } + + scrollToBottom() { + var container = document.getElementById("messages-container"); + container.scrollTop = container.scrollHeight; + } + + onMessageAdded(from, message, avatar) { + const $div = document.createElement('div'); + $div.classList.add('message'); + + const $img = document.createElement('img'); + $img.src = avatar || 'https://via.placeholder.com/40'; + $div.appendChild($img); + + const $content = document.createElement('div'); + $content.classList.add('message-content'); + + const $header = document.createElement('div'); + $header.classList.add('message-header'); + $header.textContent = from; + + const $text = document.createElement('div'); + $text.classList.add('message-text'); + + const md = window.markdownit(); + const markdownContent = md.render(message); + $text.innerHTML = markdownContent; + + $content.appendChild($header); + $content.appendChild($text); + $div.appendChild($content); + + document.querySelector('#messages').appendChild($div); + this.scrollToBottom(); + } + + truncateHash(hash) { + return `${hash.slice(0, 6)}...${hash.slice(-6)}`; + } + + async updateIcon(username, avatarBuffer) { + const userIcon = document.querySelector(`img[src*="${username}.png"]`); + if (userIcon) { + userIcon.src = URL.createObjectURL(new Blob([avatarBuffer])); + } + } + + clearMessages() { + const messagesContainer = document.querySelector('#messages'); + while (messagesContainer.firstChild) { + messagesContainer.removeChild(messagesContainer.firstChild); + } + } + + toggleSetupView() { + const setupDiv = document.querySelector('#setup'); + setupDiv.classList.toggle('hidden'); + } + + updatePeerCount() { + // Implement this method based on your needs to update the peer count in the UI } } -function scrollToBottom() { - var container = document.getElementById("messages-container"); - container.scrollTop = container.scrollHeight; -} - -function onMessageAdded(from, message, avatar) { - const $div = document.createElement('div'); - $div.classList.add('message'); - - const $img = document.createElement('img'); - $img.src = avatar || 'https://via.placeholder.com/40'; - $div.appendChild($img); - - const $content = document.createElement('div'); - $content.classList.add('message-content'); - - const $header = document.createElement('div'); - $header.classList.add('message-header'); - $header.textContent = from; - - const $text = document.createElement('div'); - $text.classList.add('message-text'); - - const md = window.markdownit(); - const markdownContent = md.render(message); - $text.innerHTML = markdownContent; - - $content.appendChild($header); - $content.appendChild($text); - $div.appendChild($content); - - document.querySelector('#messages').appendChild($div); - scrollToBottom(); -} - -function truncateHash(hash) { - return `${hash.slice(0, 6)}...${hash.slice(-6)}`; -} - -async function updateIcon(username, avatarBuffer) { - const userIcon = document.querySelector(`img[src*="${username}.png"]`); - if (userIcon) { - userIcon.src = URL.createObjectURL(new Blob([avatarBuffer])); - } -} - -function clearMessages() { - const messagesContainer = document.querySelector('#messages'); - while (messagesContainer.firstChild) { - messagesContainer.removeChild(messagesContainer.firstChild); - } -} - -function toggleSetupView() { - const setupDiv = document.querySelector('#setup'); - setupDiv.classList.toggle('hidden'); -} - -initialize(); \ No newline at end of file +new ChatHandler();