handling user icons via HyperDrive

This commit is contained in:
Raven Scott 2024-06-14 15:09:54 -04:00
parent 1c6cc9a82e
commit db88b09ba5
7 changed files with 110 additions and 36 deletions

20
app.js
View File

@ -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);

BIN
chatBot/assets/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -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);
});
});

View File

@ -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() {

View File

@ -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() {

View File

@ -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

View File

@ -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;