forked from snxraven/LinkUp-P2P-Chat
handling user icons via HyperDrive
This commit is contained in:
parent
1c6cc9a82e
commit
db88b09ba5
20
app.js
20
app.js
@ -166,16 +166,23 @@ function setupEventListeners() {
|
|||||||
setupTalkButton();
|
setupTalkButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleIncomingMessage(messageObj) {
|
function handleIncomingMessage(messageObj) {
|
||||||
console.log('Received message:', messageObj); // Debugging log
|
console.log('Received message:', messageObj); // Debugging log
|
||||||
|
|
||||||
if (messageObj.type === 'icon') {
|
if (messageObj.type === 'icon') {
|
||||||
const username = messageObj.username;
|
const username = messageObj.username;
|
||||||
if (messageObj.avatar) {
|
if (messageObj.avatar) {
|
||||||
const avatarBuffer = b4a.from(messageObj.avatar, 'base64');
|
try {
|
||||||
drive.put(`/icons/${username}.png`, avatarBuffer);
|
const avatarBuffer = b4a.from(messageObj.avatar, 'base64');
|
||||||
updateIcon(username, avatarBuffer);
|
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 {
|
} else {
|
||||||
console.error('Received icon message with missing avatar data:', messageObj);
|
console.error('Received icon message with missing avatar data:', messageObj);
|
||||||
}
|
}
|
||||||
@ -185,6 +192,8 @@ function handleIncomingMessage(messageObj) {
|
|||||||
drive.put(`/files/${messageObj.fileName}`, fileBuffer).then(() => {
|
drive.put(`/files/${messageObj.fileName}`, fileBuffer).then(() => {
|
||||||
const fileUrl = `http://localhost:${servePort}/files/${messageObj.fileName}`;
|
const fileUrl = `http://localhost:${servePort}/files/${messageObj.fileName}`;
|
||||||
addFileMessage(messageObj.name, messageObj.fileName, updatePortInUrl(fileUrl), messageObj.fileType, updatePortInUrl(messageObj.avatar), messageObj.topic);
|
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 {
|
} else {
|
||||||
console.error('Received file message with missing file data or fileName:', messageObj);
|
console.error('Received file message with missing file data or fileName:', messageObj);
|
||||||
@ -197,12 +206,13 @@ function handleIncomingMessage(messageObj) {
|
|||||||
drive.put(filePath, audioBuffer).then(() => {
|
drive.put(filePath, audioBuffer).then(() => {
|
||||||
const audioUrl = `http://localhost:${servePort}${filePath}`;
|
const audioUrl = `http://localhost:${servePort}${filePath}`;
|
||||||
addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic);
|
addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic);
|
||||||
|
}).catch(error => {
|
||||||
|
console.error(`Failed to store audio message:`, error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error('Received unknown message type:', messageObj);
|
console.error('Received unknown message type:', messageObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleConnection(connection, info) {
|
async function handleConnection(connection, info) {
|
||||||
console.log('New connection', info);
|
console.log('New connection', info);
|
||||||
|
|
||||||
|
BIN
chatBot/assets/icon.png
Normal file
BIN
chatBot/assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -52,7 +52,10 @@ loadCommands().then(commands => {
|
|||||||
|
|
||||||
// If the command exists, execute its handler
|
// If the command exists, execute its handler
|
||||||
if (commandHandler && typeof commandHandler.handler === 'function') {
|
if (commandHandler && typeof commandHandler.handler === 'function') {
|
||||||
|
console.log(`Executing command: ${command} with arguments: ${args}`);
|
||||||
commandHandler.handler(bot, args, message);
|
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.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 => {
|
}).catch(error => {
|
||||||
console.error('Error loading commands:', error);
|
console.error('Error loading commands:', error);
|
||||||
});
|
});
|
@ -6,16 +6,29 @@ import FileMessage from "./message/FileMessage.js";
|
|||||||
import AudioMessage from "./message/AudioMessage.js";
|
import AudioMessage from "./message/AudioMessage.js";
|
||||||
import Message from "./message/Message.js";
|
import Message from "./message/Message.js";
|
||||||
import IconMessage from "./message/IconMessage.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 {
|
class Client extends EventEmitter {
|
||||||
constructor(botName) {
|
constructor(botName) {
|
||||||
super();
|
super();
|
||||||
if (!botName) return console.error("Bot Name is not defined!");
|
if (!botName) return console.error("Bot Name is not defined!");
|
||||||
this.botName = botName;
|
this.botName = botName;
|
||||||
this.botAvatar = "";
|
|
||||||
this.swarm = new Hyperswarm();
|
this.swarm = new Hyperswarm();
|
||||||
this.joinedRooms = new Set(); // Track the rooms the bot has joined
|
this.joinedRooms = new Set(); // Track the rooms the bot has joined
|
||||||
this.currentTopic = null; // Track the current topic
|
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();
|
this.setupSwarm();
|
||||||
|
|
||||||
process.on('exit', () => {
|
process.on('exit', () => {
|
||||||
@ -25,35 +38,65 @@ class Client extends EventEmitter {
|
|||||||
|
|
||||||
process.on('SIGTERM', async () => {
|
process.on('SIGTERM', async () => {
|
||||||
console.log('SIGTERM signal received. Shutting down HyperSwarm...');
|
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.');
|
console.log('HyperSwarm was shut down. Exiting the process with exit code 0.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('SIGINT', async () => {
|
process.on('SIGINT', async () => {
|
||||||
console.log('SIGINT signal received. Shutting down HyperSwarm...');
|
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.');
|
console.log('HyperSwarm was shut down. Exiting the process with exit code 0.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchAvatar(url) {
|
async initializeServeDrive() {
|
||||||
this.botAvatar = url;
|
try {
|
||||||
const web = await fetch(url);
|
this.servePort = this.getRandomPort();
|
||||||
const img = await web.body.getReader().read();
|
const serve = new ServeDrive({
|
||||||
this.sendMessage(IconMessage.new(this, img.value));
|
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() {
|
setupSwarm() {
|
||||||
this.swarm.on('connection', (peer) => {
|
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 => {
|
peer.on('data', message => {
|
||||||
const messageObj = JSON.parse(message.toString());
|
const messageObj = JSON.parse(message.toString());
|
||||||
if (this.joinedRooms.has(messageObj.topic)) { // Process message only if it is from a joined room
|
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
|
this.currentTopic = messageObj.topic; // Set the current topic from the incoming message
|
||||||
|
|
||||||
const msgType = messageObj.type;
|
const msgType = messageObj.type;
|
||||||
const peerName = messageObj.name;
|
const peerName = messageObj.userName; // Changed from name to userName
|
||||||
const peerAvatar = messageObj.avatar;
|
const peerAvatar = messageObj.avatar;
|
||||||
const timestamp = messageObj.timestamp;
|
const timestamp = messageObj.timestamp;
|
||||||
|
|
||||||
@ -73,7 +116,7 @@ class Client extends EventEmitter {
|
|||||||
|
|
||||||
peer.on('error', e => {
|
peer.on('error', e => {
|
||||||
this.emit('onError', 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) {
|
sendTextMessage(message) {
|
||||||
|
console.log(`Preparing to send text message: ${message}`);
|
||||||
this.sendMessage(TextMessage.new(this, message));
|
this.sendMessage(TextMessage.new(this, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(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);
|
console.log("Sending message:", message);
|
||||||
const data = message.toJsonString();
|
const data = message.toJsonString();
|
||||||
const peers = [...this.swarm.connections];
|
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() {
|
async destroy() {
|
||||||
|
@ -2,8 +2,8 @@ import Message from "./Message.js";
|
|||||||
import b4a from "b4a";
|
import b4a from "b4a";
|
||||||
|
|
||||||
class IconMessage extends Message {
|
class IconMessage extends Message {
|
||||||
constructor(peerName, peerAvatar, topic, timestamp) {
|
constructor(peerName, peerAvatar, timestamp) {
|
||||||
super("icon", peerName, peerAvatar, topic, timestamp);
|
super("icon", peerName, peerAvatar, null, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJsonString() {
|
toJsonString() {
|
||||||
|
@ -10,7 +10,7 @@ class Message {
|
|||||||
toJson() {
|
toJson() {
|
||||||
return {
|
return {
|
||||||
type: this.type,
|
type: this.type,
|
||||||
name: this.peerName,
|
username: this.peerName,
|
||||||
avatar: this.peerAvatar,
|
avatar: this.peerAvatar,
|
||||||
topic: this.topic,
|
topic: this.topic,
|
||||||
timestamp: this.timestamp
|
timestamp: this.timestamp
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import Message from "./Message.js";
|
import Message from "./Message.js";
|
||||||
|
|
||||||
class TextMessage extends Message {
|
class TextMessage extends Message {
|
||||||
constructor(peerName, peerAvatar, topic, timestamp, message) {
|
constructor(peerName, peerAvatar, topic, timestamp, message) {
|
||||||
super("message", peerName, peerAvatar, topic, timestamp);
|
super("message", peerName, peerAvatar, topic, timestamp);
|
||||||
this.message = message;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
toJsonString() {
|
toJsonString() {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
...this.toJson(),
|
...this.toJson(),
|
||||||
message: this.message,
|
message: this.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static new(bot, message) {
|
static new(bot, message) {
|
||||||
return new TextMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), message);
|
return new TextMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TextMessage;
|
export default TextMessage;
|
||||||
|
Loading…
Reference in New Issue
Block a user