From db88b09ba500315a316d52c5838f469721c34213 Mon Sep 17 00:00:00 2001 From: Raven Scott Date: Fri, 14 Jun 2024 15:09:54 -0400 Subject: [PATCH] handling user icons via HyperDrive --- app.js | 20 ++++-- chatBot/assets/icon.png | Bin 0 -> 26538 bytes chatBot/bot.js | 9 ++- chatBot/includes/Client.js | 85 ++++++++++++++++++++---- chatBot/includes/message/IconMessage.js | 4 +- chatBot/includes/message/Message.js | 2 +- chatBot/includes/message/TextMessage.js | 26 ++++---- 7 files changed, 110 insertions(+), 36 deletions(-) create mode 100644 chatBot/assets/icon.png diff --git a/app.js b/app.js index 74a6207..4a4c7a0 100644 --- a/app.js +++ b/app.js @@ -166,16 +166,23 @@ function setupEventListeners() { setupTalkButton(); } } - function handleIncomingMessage(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'); - drive.put(`/icons/${username}.png`, avatarBuffer); - updateIcon(username, avatarBuffer); + try { + const avatarBuffer = b4a.from(messageObj.avatar, 'base64'); + drive.put(`/icons/${username}.png`, avatarBuffer).then(() => { + console.log(`Icon stored for user: ${username}`); // Debugging log + updateIcon(username, avatarBuffer); + }).catch(error => { + console.error(`Failed to store icon for user ${username}:`, error); + }); + } catch (error) { + console.error('Error processing avatar data:', error); + } } else { console.error('Received icon message with missing avatar data:', messageObj); } @@ -185,6 +192,8 @@ function handleIncomingMessage(messageObj) { drive.put(`/files/${messageObj.fileName}`, fileBuffer).then(() => { const fileUrl = `http://localhost:${servePort}/files/${messageObj.fileName}`; addFileMessage(messageObj.name, messageObj.fileName, updatePortInUrl(fileUrl), messageObj.fileType, updatePortInUrl(messageObj.avatar), messageObj.topic); + }).catch(error => { + console.error(`Failed to store file ${messageObj.fileName}:`, error); }); } else { console.error('Received file message with missing file data or fileName:', messageObj); @@ -197,12 +206,13 @@ function handleIncomingMessage(messageObj) { drive.put(filePath, audioBuffer).then(() => { const audioUrl = `http://localhost:${servePort}${filePath}`; addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic); + }).catch(error => { + console.error(`Failed to store audio message:`, error); }); } else { console.error('Received unknown message type:', messageObj); } } - async function handleConnection(connection, info) { console.log('New connection', info); diff --git a/chatBot/assets/icon.png b/chatBot/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..51285556e6da5f6977a710fa677a6c138180024e GIT binary patch literal 26538 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 literal 0 HcmV?d00001 diff --git a/chatBot/bot.js b/chatBot/bot.js index d5eabd7..24ca968 100644 --- a/chatBot/bot.js +++ b/chatBot/bot.js @@ -52,7 +52,10 @@ loadCommands().then(commands => { // If the command exists, execute its handler if (commandHandler && typeof commandHandler.handler === 'function') { + console.log(`Executing command: ${command} with arguments: ${args}`); commandHandler.handler(bot, args, message); + } else { + console.warn(`Command not found: ${command}`); } } }); @@ -64,7 +67,9 @@ loadCommands().then(commands => { bot.joinChatRoom(process.env.LINKUP_ROOM_ID); - bot.fetchAvatar(`https://avatar.iran.liara.run/username?username=${bot.botName}&background=f4d9b2&color=FF9800&size=40`); // Debugging avatar + const iconPath = path.join(new URL('./assets/icon.png', import.meta.url).pathname); + bot.fetchAvatar(iconPath); // Fetch the avatar from local file + }).catch(error => { console.error('Error loading commands:', error); -}); \ No newline at end of file +}); diff --git a/chatBot/includes/Client.js b/chatBot/includes/Client.js index c1da18e..1311d37 100644 --- a/chatBot/includes/Client.js +++ b/chatBot/includes/Client.js @@ -6,16 +6,29 @@ import FileMessage from "./message/FileMessage.js"; import AudioMessage from "./message/AudioMessage.js"; import Message from "./message/Message.js"; import IconMessage from "./message/IconMessage.js"; +import Corestore from 'corestore'; +import Hyperdrive from 'hyperdrive'; +import fs from 'fs'; +import ServeDrive from 'serve-drive'; class Client extends EventEmitter { constructor(botName) { super(); if (!botName) return console.error("Bot Name is not defined!"); this.botName = botName; - this.botAvatar = ""; this.swarm = new Hyperswarm(); this.joinedRooms = new Set(); // Track the rooms the bot has joined this.currentTopic = null; // Track the current topic + + // Initialize Corestore and Hyperdrive + this.storagePath = './storage/'; + this.store = new Corestore(this.storagePath); + this.drive = new Hyperdrive(this.store); + + // Initialize ServeDrive + this.servePort = null; + this.initializeServeDrive(); + this.setupSwarm(); process.on('exit', () => { @@ -25,35 +38,65 @@ class Client extends EventEmitter { process.on('SIGTERM', async () => { console.log('SIGTERM signal received. Shutting down HyperSwarm...'); - await this.destroy() + await this.destroy(); console.log('HyperSwarm was shut down. Exiting the process with exit code 0.'); process.exit(0); }); process.on('SIGINT', async () => { console.log('SIGINT signal received. Shutting down HyperSwarm...'); - await this.destroy() + await this.destroy(); console.log('HyperSwarm was shut down. Exiting the process with exit code 0.'); process.exit(0); }); } - async fetchAvatar(url) { - this.botAvatar = url; - const web = await fetch(url); - const img = await web.body.getReader().read(); - this.sendMessage(IconMessage.new(this, img.value)); + async initializeServeDrive() { + try { + this.servePort = this.getRandomPort(); + const serve = new ServeDrive({ + port: this.servePort, + get: ({ key, filename, version }) => this.drive + }); + await serve.ready(); + console.log('ServeDrive listening on port:', this.servePort); + } catch (error) { + console.error('Error initializing ServeDrive:', error); + } + } + + getRandomPort() { + return Math.floor(Math.random() * (65535 - 49152 + 1)) + 49152; + } + + async fetchAvatar(filePath) { + try { + await this.drive.ready(); + const iconBuffer = fs.readFileSync(filePath); + await this.drive.put(`/icons/${this.botName}.png`, iconBuffer); + this.botAvatar = `http://localhost:${this.servePort}/icons/${this.botName}.png`; + + // Cache the icon message + this.iconMessage = IconMessage.new(this, iconBuffer); + } catch (error) { + console.error('Error fetching avatar:', error); + } } setupSwarm() { this.swarm.on('connection', (peer) => { + // Send the cached icon message to the new peer + if (this.iconMessage) { + peer.write(this.iconMessage.toJsonString()); + } + peer.on('data', message => { const messageObj = JSON.parse(message.toString()); if (this.joinedRooms.has(messageObj.topic)) { // Process message only if it is from a joined room this.currentTopic = messageObj.topic; // Set the current topic from the incoming message const msgType = messageObj.type; - const peerName = messageObj.name; + const peerName = messageObj.userName; // Changed from name to userName const peerAvatar = messageObj.avatar; const timestamp = messageObj.timestamp; @@ -73,7 +116,7 @@ class Client extends EventEmitter { peer.on('error', e => { this.emit('onError', e); - console.error(`Connection error: ${e}`) + console.error(`Connection error: ${e}`); }); }); @@ -97,17 +140,33 @@ class Client extends EventEmitter { } sendTextMessage(message) { + console.log(`Preparing to send text message: ${message}`); this.sendMessage(TextMessage.new(this, message)); } sendMessage(message) { - if(!(message instanceof Message)) return console.log(`message does not extend Message class (TextMessage, FileMessage, AudioMessage).`, message); + if (!(message instanceof Message)) { + console.error(`message does not extend Message class (TextMessage, FileMessage, AudioMessage).`, message); + return; + } - // console.log('Bot name:', this.botName); console.log("Sending message:", message); const data = message.toJsonString(); const peers = [...this.swarm.connections]; - for (const peer of peers) peer.write(data); + if (peers.length === 0) { + console.warn("No active peer connections found."); + return; + } + + console.log(`Sending message to ${peers.length} peers.`); + for (const peer of peers) { + try { + peer.write(data); + console.log(`Message sent to peer: ${peer.remoteAddress}`); + } catch (error) { + console.error(`Failed to send message to peer: ${peer.remoteAddress}`, error); + } + } } async destroy() { diff --git a/chatBot/includes/message/IconMessage.js b/chatBot/includes/message/IconMessage.js index bb4afc4..f3e9bd5 100644 --- a/chatBot/includes/message/IconMessage.js +++ b/chatBot/includes/message/IconMessage.js @@ -2,8 +2,8 @@ import Message from "./Message.js"; import b4a from "b4a"; class IconMessage extends Message { - constructor(peerName, peerAvatar, topic, timestamp) { - super("icon", peerName, peerAvatar, topic, timestamp); + constructor(peerName, peerAvatar, timestamp) { + super("icon", peerName, peerAvatar, null, timestamp); } toJsonString() { diff --git a/chatBot/includes/message/Message.js b/chatBot/includes/message/Message.js index fbb2fff..3a2c9c0 100644 --- a/chatBot/includes/message/Message.js +++ b/chatBot/includes/message/Message.js @@ -10,7 +10,7 @@ class Message { toJson() { return { type: this.type, - name: this.peerName, + username: this.peerName, avatar: this.peerAvatar, topic: this.topic, timestamp: this.timestamp diff --git a/chatBot/includes/message/TextMessage.js b/chatBot/includes/message/TextMessage.js index 716cde1..f4a68c0 100644 --- a/chatBot/includes/message/TextMessage.js +++ b/chatBot/includes/message/TextMessage.js @@ -1,21 +1,21 @@ import Message from "./Message.js"; class TextMessage extends Message { - constructor(peerName, peerAvatar, topic, timestamp, message) { - super("message", peerName, peerAvatar, topic, timestamp); - this.message = message; - } + constructor(peerName, peerAvatar, topic, timestamp, message) { + super("message", peerName, peerAvatar, topic, timestamp); + this.message = message; + } - toJsonString() { - return JSON.stringify({ - ...this.toJson(), - message: this.message, - }); - } + toJsonString() { + return JSON.stringify({ + ...this.toJson(), + message: this.message, + }); + } - static new(bot, message) { - return new TextMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), message); - } + static new(bot, message) { + return new TextMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), message); + } } export default TextMessage;