diff --git a/app.js b/app.js index 1272852..9c5cfaa 100644 --- a/app.js +++ b/app.js @@ -3,21 +3,20 @@ import crypto from 'hypercore-crypto'; import b4a from 'b4a'; import ServeDrive from 'serve-drive'; import Localdrive from 'localdrive'; -import fs from 'fs'; -const drive = new Localdrive('./storage'); +const sharedDrive = new Localdrive('./shared-storage'); let swarm; let userName = 'Anonymous'; let userAvatar = ''; -let registeredUsers = JSON.parse(localStorage.getItem('registeredUsers')) || {}; let peerCount = 0; async function initialize() { swarm = new Hyperswarm(); - await drive.ready(); + await sharedDrive.ready(); + const servePort = 1337; - const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => drive }); + const serve = new ServeDrive({ port: servePort, get: ({ key, filename, version }) => sharedDrive }); await serve.ready(); console.log('Listening on http://localhost:' + serve.address().port); @@ -45,6 +44,38 @@ async function initialize() { messageForm.addEventListener('submit', sendMessage); } + swarm.on('connection', (connection, info) => { + peerCount++; + updatePeerCount(); + + connection.on('data', async (data) => { + const messageObj = JSON.parse(data.toString()); + if (messageObj.type === 'avatarRequest') { + const avatarBuffer = await getAvatar(messageObj.username); + if (avatarBuffer) { + connection.write(avatarBuffer); + } + } else if (messageObj.type === 'fileUpdate') { + await processFileUpdate(messageObj); + } else { + onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar); + } + }); + + connection.on('close', () => { + peerCount--; + updatePeerCount(); + }); + }); + + swarm.on('error', (err) => { + console.error('Swarm error:', err); + }); + + swarm.on('close', () => { + console.log('Swarm closed.'); + }); + const savedUser = localStorage.getItem('currentUser'); if (savedUser) { const user = JSON.parse(savedUser); @@ -61,33 +92,8 @@ async function initialize() { } } - swarm.on('connection', (connection, info) => { - peerCount++; - updatePeerCount(); - connection.on('data', async (data) => { - const messageObj = JSON.parse(data.toString()); - if (messageObj.type === 'icon') { - // Save icon to local directory - const username = messageObj.username; - const avatarBuffer = Buffer.from(messageObj.avatar, 'base64'); - await drive.put(`/icons/${username}.png`, avatarBuffer); - } else { - onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar); - } - }); - connection.on('close', () => { - peerCount--; - updatePeerCount(); - }); - }); - - swarm.on('error', (err) => { - console.error('Swarm error:', err); - }); - - swarm.on('close', () => { - console.log('Swarm closed.'); - }); + const randomTopic = crypto.randomBytes(32); + document.querySelector('#chat-room-topic').innerText = b4a.toString(randomTopic, 'hex'); } function updatePeerCount() { @@ -97,6 +103,17 @@ function updatePeerCount() { } } +async function getAvatar(username) { + try { + const avatarPath = `./shared-storage/icons/${username}.png`; + const avatarBuffer = await sharedDrive.get(avatarPath); + return avatarBuffer; + } catch (error) { + console.error('Error getting avatar:', error); + return null; + } +} + async function registerUser(e) { e.preventDefault(); @@ -125,9 +142,8 @@ async function registerUser(e) { const reader = new FileReader(); reader.onload = async () => { const fileBuffer = Buffer.from(reader.result); - await drive.put(`/icons/${regUsername}.png`, fileBuffer); - userAvatar = `http://localhost:1337/icons/${regUsername}.png`; - // Save avatar URL to localStorage + await sharedDrive.put(`/icons/${regUsername}-${file.name}`, fileBuffer); + userAvatar = `http://localhost:1337/icons/${regUsername}-${file.name}`; localStorage.setItem('avatarURL', userAvatar); }; reader.readAsArrayBuffer(file); @@ -157,7 +173,6 @@ async function continueRegistration(regUsername) { } async function createChatRoom() { - // Generate a new random topic (32 byte string) const topicBuffer = crypto.randomBytes(32); joinSwarm(topicBuffer); } @@ -173,7 +188,6 @@ async function joinSwarm(topicBuffer) { document.querySelector('#setup').classList.add('hidden'); document.querySelector('#loading').classList.remove('hidden'); - // Join the swarm with the topic. Setting both client/server to true means that this app can act as both. const discovery = swarm.join(topicBuffer, { client: true, server: true }); await discovery.flushed(); @@ -190,7 +204,8 @@ function sendMessage(e) { onMessageAdded(userName, message, userAvatar); - // Send the message to all peers (that you are connected to) + onMessageAdded(userName, message, userAvatar); + const messageObj = JSON.stringify({ type: 'message', name: userName, @@ -205,7 +220,23 @@ function sendMessage(e) { } } -// appends element to #messages element with content set to sender and message +async function processFileUpdate(messageObj) { + try { + const filePath = messageObj.filePath; + const fileBuffer = await downloadFileFromPeer(messageObj.peerId, filePath); + + await sharedDrive.put(filePath, fileBuffer); + + console.log(`File ${filePath} updated successfully.`); + } catch (error) { + console.error('Error processing file update:', error); + } +} + +async function downloadFileFromPeer(peerId, filePath) { + // Implement logic to download file from peer using Hyperswarm or other P2P mechanisms +} + function onMessageAdded(from, message, avatar) { const $div = document.createElement('div'); $div.classList.add('message'); @@ -231,4 +262,4 @@ function onMessageAdded(from, message, avatar) { document.querySelector('#messages').appendChild($div); } -initialize(); \ No newline at end of file +initialize(); diff --git a/shared-storage/icons/Raven-ava.webp b/shared-storage/icons/Raven-ava.webp new file mode 100644 index 0000000..dc307e6 Binary files /dev/null and b/shared-storage/icons/Raven-ava.webp differ