Compare commits

...

21 Commits

Author SHA1 Message Date
1c6cc9a82e Merge pull request 'Reworked message format, added support for audio messages, made Message class' (#10) from MiTask/LinkUp-P2P-Chat:main into main
Reviewed-on: #10
2024-06-14 18:15:43 +00:00
MrMasrozYTLIVE
f706e7d621 Made Client.js->setupSwarm() parsing messages more readable 2024-06-14 20:06:05 +03:00
MrMasrozYTLIVE
42dccf9547 Actually just returning the url if its host is not 'localhost' 2024-06-14 19:58:40 +03:00
MrMasrozYTLIVE
d4dc1b299d Ignoring 'updatePortInUrl' if port is 443 (SSL connection) 2024-06-14 19:53:51 +03:00
MrMasrozYTLIVE
3e9a2101d5 I did this.botName and not bot.botName lol 2024-06-14 19:51:34 +03:00
MrMasrozYTLIVE
2d0f97bc8f Oops i made async constructor 2024-06-14 19:50:10 +03:00
MrMasrozYTLIVE
6cbfe34966 Testing bot avatars thingy 2024-06-14 19:49:26 +03:00
MrMasrozYTLIVE
9b4357dd00 i hate js. it ignores all of my code and just sends 'messagetype' instead of 'type' 2024-06-14 19:25:17 +03:00
MrMasrozYTLIVE
14aa129f6d Trying some changes to make bot messages and client mmessages have same format 2024-06-14 17:44:05 +03:00
MrMasrozYTLIVE
d449249f41 Revert reverting 2024-06-14 17:39:16 +03:00
MrMasrozYTLIVE
bb26b5c2a8 Revert all changes i did to app.js 2024-06-14 17:37:58 +03:00
MrMasrozYTLIVE
52a319a1c0 Fixed my bots messages 2024-06-14 17:36:16 +03:00
MrMasrozYTLIVE
70655ce901 So messages actually broke somehow lol 2024-06-14 17:34:06 +03:00
MrMasrozYTLIVE
75be3a5b33 Reworked commands, added some funny stuff 2024-06-14 17:20:37 +03:00
MrMasrozYTLIVE
d5650a9d7b I think i did it yay 2024-06-14 17:09:30 +03:00
MrMasrozYTLIVE
2ff9c73585 It doesnt want to work 😭 2024-06-14 17:07:21 +03:00
MrMasrozYTLIVE
d50e0df6a1 Time to do lots of debugging 😭 2024-06-14 17:05:00 +03:00
MrMasrozYTLIVE
8262bd4eb7 Hm. Its pretty strange. Thats why i dont really like JavaScript 2024-06-14 17:04:08 +03:00
MrMasrozYTLIVE
457bf01bc3 Trying out isPrototypeOf() function 2024-06-14 17:02:26 +03:00
MrMasrozYTLIVE
feff30fecc Testing if sendMessage argument extends Message class 2024-06-14 17:00:35 +03:00
MrMasrozYTLIVE
b3ccda32ea did lots of work on bot package 2024-06-14 16:43:17 +03:00
10 changed files with 157 additions and 71 deletions

20
app.js
View File

@ -213,6 +213,7 @@ async function handleConnection(connection, info) {
type: 'icon', type: 'icon',
username: config.userName, username: config.userName,
avatar: b4a.toString(iconBuffer, 'base64'), avatar: b4a.toString(iconBuffer, 'base64'),
timestamp: Date.now()
}); });
console.log('Sending icon to new peer:', iconMessage); console.log('Sending icon to new peer:', iconMessage);
connection.write(iconMessage); connection.write(iconMessage);
@ -289,10 +290,11 @@ function setupTalkButton() {
const audioMessage = { const audioMessage = {
type: 'audio', type: 'audio',
name: config.userName, name: config.userName,
audio: b4a.toString(buffer, 'base64'),
audioType: audioBlob.type,
avatar: updatePortInUrl(config.userAvatar), avatar: updatePortInUrl(config.userAvatar),
topic: topic topic: topic,
timestamp: Date.now(),
audio: b4a.toString(buffer, 'base64'),
audioType: audioBlob.type
}; };
console.log('Sending audio message:', audioMessage); // Debugging log console.log('Sending audio message:', audioMessage); // Debugging log
@ -563,10 +565,10 @@ async function sendMessage(e) {
const messageObj = JSON.stringify({ const messageObj = JSON.stringify({
type: 'message', type: 'message',
name: config.userName, name: config.userName,
message,
avatar: config.userAvatar, avatar: config.userAvatar,
topic: topic, topic: topic,
timestamp: timestamp timestamp: timestamp,
message
}); });
const peers = [...activeRooms.find(room => room.topic === topic).swarm.connections]; const peers = [...activeRooms.find(room => room.topic === topic).swarm.connections];
@ -590,11 +592,12 @@ async function handleFileInput(event) {
const fileMessage = { const fileMessage = {
type: 'file', type: 'file',
name: config.userName, name: config.userName,
avatar: updatePortInUrl(config.userAvatar),
topic: topic,
timestamp: Date.now(),
fileName: file.name, fileName: file.name,
file: b4a.toString(buffer, 'base64'), file: b4a.toString(buffer, 'base64'),
fileType: file.type, fileType: file.type
avatar: updatePortInUrl(config.userAvatar),
topic: topic
}; };
console.log('Sending file message:', fileMessage); // Debugging log console.log('Sending file message:', fileMessage); // Debugging log
@ -847,6 +850,7 @@ function writeConfigToFile(filePath) {
function updatePortInUrl(url) { function updatePortInUrl(url) {
if (!url) return url; if (!url) return url;
const urlObject = new URL(url); const urlObject = new URL(url);
if(!urlObject.host.startsWith("localhost")) return urlObject.toString();
urlObject.port = servePort; urlObject.port = servePort;
return urlObject.toString(); return urlObject.toString();
} }

View File

@ -39,10 +39,9 @@ loadCommands().then(commands => {
// We use Event Emitter here to handle new messages // We use Event Emitter here to handle new messages
bot.on('onMessage', (peer, message) => { bot.on('onMessage', (peer, message) => {
console.log(`Message received from ${message.peerName} at ${new Date(message.timestamp).toLocaleTimeString()}: ${message.message}`);
console.log(message); console.log(message);
console.log(`Message received from ${message.peerName}@${message.topic} at ${new Date(message.timestamp).toLocaleTimeString()}: ${message.message}`);
// Check if the message starts with a command prefix // Check if the message starts with a command prefix
if (message.message.startsWith('!')) { if (message.message.startsWith('!')) {
// Extract the command and arguments // Extract the command and arguments
@ -64,6 +63,8 @@ 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
}).catch(error => { }).catch(error => {
console.error('Error loading commands:', error); console.error('Error loading commands:', error);
}); });

View File

@ -1,14 +1,18 @@
import Hyperswarm from 'hyperswarm'; import Hyperswarm from 'hyperswarm';
import EventEmitter from 'node:events'; import EventEmitter from 'node:events';
import b4a from "b4a"; import b4a from "b4a";
import TextMessage from "./TextMessage.js"; import TextMessage from "./message/TextMessage.js";
import FileMessage from "./FileMessage.js"; import FileMessage from "./message/FileMessage.js";
import AudioMessage from "./message/AudioMessage.js";
import Message from "./message/Message.js";
import IconMessage from "./message/IconMessage.js";
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
@ -34,20 +38,36 @@ class Client extends EventEmitter {
}); });
} }
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));
}
setupSwarm() { setupSwarm() {
this.swarm.on('connection', (peer) => { this.swarm.on('connection', (peer) => {
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
if (messageObj.type === "message")
this.emit('onMessage', peer, new TextMessage(messageObj.name, messageObj.avatar, messageObj.topic, messageObj.message, messageObj.timestamp));
if (messageObj.type === "file") const msgType = messageObj.type;
this.emit('onFile', peer, new FileMessage(messageObj.name, messageObj.fileName, messageObj.fileUrl, messageObj.fileType, messageObj.avatar, messageObj.topic, messageObj.timestamp)); const peerName = messageObj.name;
const peerAvatar = messageObj.avatar;
const timestamp = messageObj.timestamp;
if (messageObj.type === "icon") if (msgType === "message")
this.emit('onIcon', peer, messageObj); this.emit('onMessage', peer, new TextMessage(peerName, peerAvatar, this.currentTopic, timestamp, messageObj.message));
if (msgType === "file")
this.emit('onFile', peer, new FileMessage(peerName, peerAvatar, this.currentTopic, timestamp, messageObj.fileName, messageObj.fileUrl, messageObj.fileType));
if (msgType === "icon")
this.emit('onIcon', peer, new IconMessage(peerName, peerAvatar, timestamp));
if (msgType === "audio")
this.emit('onAudio', peer, new AudioMessage(peerName, peerAvatar, this.currentTopic, timestamp, messageObj.audio, messageObj.audioType));
} }
}); });
@ -81,7 +101,10 @@ class Client extends EventEmitter {
} }
sendMessage(message) { sendMessage(message) {
console.log('Bot name:', this.botName); if(!(message instanceof Message)) return console.log(`message does not extend Message class (TextMessage, FileMessage, AudioMessage).`, message);
// console.log('Bot name:', this.botName);
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); for (const peer of peers) peer.write(data);

View File

@ -1,26 +0,0 @@
class FileMessage {
constructor(peerName, fileName, fileUrl, fileType, peerAvatar, topic, timestamp) {
this.peerName = peerName;
this.fileName = fileName;
this.fileUrl = fileUrl;
this.fileType = fileType;
this.peerAvatar = peerAvatar;
this.topic = topic;
this.timestamp = timestamp;
}
toJsonString() {
return JSON.stringify({
type: 'file',
name: this.peerName,
fileName: this.fileName,
fileUrl: this.fileUrl,
fileType: this.fileType,
avatar: this.peerAvatar,
topic: this.topic,
timestamp: this.timestamp,
});
}
}
export default FileMessage;

View File

@ -1,26 +0,0 @@
class TextMessage {
constructor(peerName, peerAvatar, topic, message, timestamp) {
this.peerName = peerName;
this.peerAvatar = peerAvatar;
this.topic = topic;
this.message = message;
this.timestamp = timestamp;
}
toJsonString() {
return JSON.stringify({
type: 'message',
name: this.peerName,
message: this.message,
avatar: this.peerAvatar,
topic: this.topic,
timestamp: this.timestamp
});
}
static new(bot, message) {
return new TextMessage(bot.botName, "", bot.currentTopic, message, Date.now());
}
}
export default TextMessage;

View File

@ -0,0 +1,23 @@
import Message from "./Message.js";
class AudioMessage extends Message {
constructor(peerName, peerAvatar, topic, timestamp, audio, audioType) {
super("audio", peerName, peerAvatar, topic, timestamp);
this.audio = audio;
this.audioType = audioType;
}
toJsonString() {
return JSON.stringify({
...this.toJson(),
audio: this.audio,
audioType: this.audioType
});
}
static new(bot, audio, audioType) {
return new AudioMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), audio, audioType);
}
}
export default AudioMessage;

View File

@ -0,0 +1,25 @@
import Message from "./Message.js";
class FileMessage extends Message {
constructor(peerName, peerAvatar, topic, timestamp, fileName, fileUrl, fileType) {
super("file", peerName, peerAvatar, topic, timestamp);
this.fileName = fileName;
this.fileUrl = fileUrl;
this.fileType = fileType;
}
toJsonString() {
return JSON.stringify({
...this.toJson(),
fileName: this.fileName,
fileUrl: this.fileUrl,
fileType: this.fileType
});
}
static new(bot, fileName, fileUrl, fileType) {
return new FileMessage(bot.botName, bot.botAvatar, bot.currentTopic, Date.now(), fileName, fileUrl, fileType);
}
}
export default FileMessage;

View File

@ -0,0 +1,20 @@
import Message from "./Message.js";
import b4a from "b4a";
class IconMessage extends Message {
constructor(peerName, peerAvatar, topic, timestamp) {
super("icon", peerName, peerAvatar, topic, timestamp);
}
toJsonString() {
return JSON.stringify({
...this.toJson()
});
}
static new(bot, avatarBuffer) {
return new IconMessage(bot.botName, b4a.toString(avatarBuffer, 'base64'), Date.now());
}
}
export default IconMessage;

View File

@ -0,0 +1,21 @@
class Message {
constructor(messageType, peerName, peerAvatar, topic, timestamp) {
this.type = messageType;
this.peerName = peerName;
this.peerAvatar = peerAvatar;
this.topic = topic;
this.timestamp = timestamp;
}
toJson() {
return {
type: this.type,
name: this.peerName,
avatar: this.peerAvatar,
topic: this.topic,
timestamp: this.timestamp
};
}
}
export default Message;

View File

@ -0,0 +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;
}
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);
}
}
export default TextMessage;