From cbd2130c3dbf5ba7eb8a23648e0ce94538a2381c Mon Sep 17 00:00:00 2001 From: Adam Robins Date: Thu, 30 Jan 2025 00:32:05 +0100 Subject: [PATCH 1/3] Websocket plumbing added for DM's --- main.ts | 3 +- middleware/auth.ts | 1 - public/index.html | 4 +-- public/main.js | 69 ++++++++++++++++++++++++++++------------------ services/socket.ts | 15 ++++++++++ 5 files changed, 61 insertions(+), 31 deletions(-) diff --git a/main.ts b/main.ts index 7ffc952..81210f3 100644 --- a/main.ts +++ b/main.ts @@ -64,6 +64,7 @@ app.post("/channel/join", isLoggedIn, async (req, res) => { }; var channelMessages = await MongooseDal.getMessagesForChannel(req.body.channel); + await MongooseDal.createChannel(channelMongo); @@ -73,7 +74,7 @@ app.post("/channel/join", isLoggedIn, async (req, res) => { socket.socket.emit("channel:joined", { channel: req.body.channel, users: users, - messages: channelMessages.messages + messages: channelMessages?.messages || [], }); }); res.send({ users: users, channel: req.body.channel }); diff --git a/middleware/auth.ts b/middleware/auth.ts index 139c0f2..7a0d499 100644 --- a/middleware/auth.ts +++ b/middleware/auth.ts @@ -55,7 +55,6 @@ const getUser = async (req, res) => { if (!token) res.status(401).json({ error: "malformed auth header" }); const payload = await jwt.verify(token, SECRET_KEY); - logger.log.magenta("Payload", payload); return payload; }; diff --git a/public/index.html b/public/index.html index 376ec66..6ded339 100644 --- a/public/index.html +++ b/public/index.html @@ -21,8 +21,8 @@

Join a channel

- - + +
diff --git a/public/main.js b/public/main.js index 23309e0..fbd57f0 100644 --- a/public/main.js +++ b/public/main.js @@ -15,35 +15,44 @@ var currentNick = ''; var channels = []; var dmUsers = [{user: 'ChanServe', messages: []}]; -$(document).ready(function () { - $("#message").keypress(function (e) { - if (e.which == 13) { - var message = $('#message').val(); - $('#message').val(''); - addMessage({ - user: currentNick, - message: message - }); - // Socket sent - socket.emit('client:message', { - message: message, - channel: selectedChannel - }); - return false; - } - }); - $('#message_send').click(function () { - var message = $('#message').val(); - $('#message').val(''); - // Socket sent - socket.emit('client:message', { - message: message, - channel: selectedChannel - }); +function sendMessage() { + var message = $('#message').val(); + + if(channels.find(channel => channel.name == selectedChannel) == undefined){ + const receiver = selectedChannel; + const message = $('#message').val(); + addMessage({ + user: currentNick, + message: message + }); + + socket.emit('client:direct', { + from: currentNick, + to: receiver, + message: message + }); + } else { addMessage({ user: currentNick, message: message }); + socket.emit('client:message', { + message: message, + channel: selectedChannel + }); + } + + $('#messages').animate({ scrollTop: $('#messages').prop("scrollHeight")}, 10); + $('#message').val(''); + return false; +} + +$(document).ready(function () { + $("#message").keypress(function (e) { + if (e.which == 13) sendMessage(); + }); + $('#message_send').click(function () { + sendMessage(); }); $('#connect').click(()=>{ @@ -91,11 +100,13 @@ $(document).ready(function () { $('#join_channel').click(()=>{ const channel = $('#channel').val(); const key = $('#channel-key').val(); - const isDm = $('#isDm').val(); + const isDm = $('#isDm').is(':checked') $('#channel').val(''); $('#channel-key').val(''); + joinChannel(channel, key, isDm); + toggleOpenChannel(); }); }); @@ -254,7 +265,11 @@ function cleanChannelCss(channel){ }; function joinChannel(channel, key, isDm) { - console.log(isDm); + if(isDm){ + openDirectMessage(channel); + return; + } + axios.post('http://127.0.0.1:3000/channel/join', { channel: channel, key: key diff --git a/services/socket.ts b/services/socket.ts index 4a0a5ba..d00744a 100644 --- a/services/socket.ts +++ b/services/socket.ts @@ -32,6 +32,7 @@ export class SocketService { socket: socket, user: "", }); + // Channel Message socket.on("client:message", async (message) => { var channel = "Global"; if (message.channel) channel = message.channel; @@ -48,6 +49,20 @@ export class SocketService { await MongooseDal.addMessage(message.channel, messageStore); }); + + // Direct Message + socket.on("client:direct", async (message) => { + const directMessage: IDirectMessage = { + sender: message.from, + owner: message.to, + message: message.message, + created_at: new Date(), + }; + + await MongooseDal.addDirectMessage(directMessage); + this.ircClient.say(message.to, message.message); + }); + }); return this.io; } From f49e65725fc53f91d7b4a34dee5faba99b76cbe9 Mon Sep 17 00:00:00 2001 From: Adam Robins Date: Thu, 30 Jan 2025 21:17:00 +0100 Subject: [PATCH 2/3] optimised direct messages and better modeling --- main.ts | 3 ++- models/channel.ts | 16 ++++++++-------- public/login/login.html | 2 +- public/main.js | 15 +++++++++++++-- services/mongo.ts | 18 +++++++++++------- services/socket.ts | 34 ++++++++++++++++------------------ 6 files changed, 51 insertions(+), 37 deletions(-) diff --git a/main.ts b/main.ts index 81210f3..7da1c9c 100644 --- a/main.ts +++ b/main.ts @@ -44,7 +44,8 @@ app.use("/login", Express.static("public/login/login.html")); app.post("/join/dm/:nick", isLoggedIn, async (req, res) => { const nick = req.params.nick; var dms = await MongooseDal.getDirectMessagesForUser(UserSettings.nick, nick); - res.send({ nick: nick, messages: dms }); + console.log(dms); + res.send({ nick: nick, messages: dms?.messages || [] }); }); app.post("/channel/join", isLoggedIn, async (req, res) => { diff --git a/models/channel.ts b/models/channel.ts index 6b1b8b8..e6cc07c 100644 --- a/models/channel.ts +++ b/models/channel.ts @@ -6,10 +6,10 @@ interface IMessage { created_at: Date; } -interface IDirectMessage { - sender: string; +interface IDirectMessages { owner: string; - message: string; + external_user: string; + messages: Array; created_at: Date; } @@ -35,14 +35,14 @@ const channelSchema = new Schema({ active: { type: Boolean, default: true } }); -const directMessageSchema = new Schema({ +const directMessageSchema = new Schema({ owner: { type: String, required: true }, - sender: { type: String, required: true }, - message: { type: String, required: true }, + external_user: { type: String, required: true }, + messages: { type: [new Schema({ sender: String, message: String, created_at: { type: Date, default: Date.now } })], default: [] }, created_at: { type: Date, default: Date.now } }); const Channel = model('Channel', channelSchema); -const DirectMessage = model('DirectMessage', directMessageSchema); +const DirectMessages = model('DirectMessages', directMessageSchema); -export { Channel, DirectMessage, IChannel, IMessage, IDirectMessage }; \ No newline at end of file +export { Channel, DirectMessages, IChannel, IMessage, IDirectMessages }; \ No newline at end of file diff --git a/public/login/login.html b/public/login/login.html index 61015d1..8dc5355 100644 --- a/public/login/login.html +++ b/public/login/login.html @@ -42,7 +42,7 @@

Login

var password = document.getElementById('password').value; // POST with axios to /login - axios.post('/user/login', { + axios.post('http://127.0.0.1:3000/user/login', { username: username, password: password }).then((response) => { diff --git a/public/main.js b/public/main.js index fbd57f0..6d6a3d0 100644 --- a/public/main.js +++ b/public/main.js @@ -143,8 +143,12 @@ socket.on('channel:list', function (data) { socket.on('channel:parted', function (data) { $('#users').empty(); $('#messages').empty(); + // Sort the users by their modes + data.users.sort((a, b) => (a.modes > b.modes ? 1 : -1)); $.each(data.users, function (index, user) { - $('#users').append('
  • ' + user.nick + ' [' + user.modes + ']
  • '); + $('#users').append('
  • ' + + user.nick + ' [' + user.modes + ']
  • '); }); $('#channel_name').text('ChanServe'); selectedChannel = 'ChanServe'; @@ -152,11 +156,18 @@ socket.on('channel:parted', function (data) { }); socket.on('channel:joined', function (data) { + if(!data.users || data.users.length <= 1){ + openDirectMessage(data.channel); + return; + } data.channel[0] == '#' ? selectedChannel = data.channel.substring(1) : selectedChannel = data.channel; $('#users').empty(); $('#messages').empty(); + data.users.sort((a, b) => (a.modes > b.modes ? 1 : -1)); $.each(data.users, function (index, user) { - $('#users').append('
  • ' + user.nick + ' [' + user.modes + ']
  • '); + $('#users').append('
  • ' + + user.nick + ' [' + user.modes + ']
  • '); }); // add to channels if not exists if(!channels.filter(channel => channel.name == data.channel).length > 0){ diff --git a/services/mongo.ts b/services/mongo.ts index 64a38a0..060bac1 100644 --- a/services/mongo.ts +++ b/services/mongo.ts @@ -1,6 +1,6 @@ // Mongoose controller import mongoose from "mongoose"; -import { Channel, DirectMessage, IChannel, IMessage, IDirectMessage } from "../models/channel"; +import { Channel, DirectMessages, IChannel, IMessage } from "../models/channel"; import { MessageQueue, IMessageQueue } from "../models/messageQueue"; // MONGODB MONGOOS DAL CLASS @@ -31,10 +31,6 @@ const MongooseDal = { return Channel.updateOne( { name: channelName }, { $push: { messages: message }, updated_at: new Date() }); }, - addDirectMessage: async (message: IDirectMessage) => { - console.log(message); - return await DirectMessage.create(message); - }, getChannelsForUser: async (username: string) => { return await Channel.find({ owner: username, active: true }, { name: 1, updated_at: 1 }); }, @@ -42,8 +38,16 @@ const MongooseDal = { var messages = await Channel.findOne({ name: channelName }, { messages: 1 }); return messages; }, - getDirectMessagesForUser: async (owner: string, sender: string) => { - return await DirectMessage.find({ owner, sender }); + getDirectMessagesForUser: async (owner: string, external_user: string) => { + return await DirectMessages.findOne({ owner, external_user }, { messages: 1 }); + }, + addDirectMessage: async (owner:string, external_user:string, message:IMessage) => { + const directMessage = await DirectMessages.findOne({ owner, external_user }); + if (!directMessage) { + return await DirectMessages.create({ owner, external_user, messages: [message] }); + } else { + return await DirectMessages.updateOne({ owner, external_user }, { $push: { messages: message } }); + } }, addMessageToQueue: async (message: IMessageQueue) => { return await MessageQueue.create(message); diff --git a/services/socket.ts b/services/socket.ts index d00744a..c3a3ae5 100644 --- a/services/socket.ts +++ b/services/socket.ts @@ -1,6 +1,6 @@ import { Client } from "irc-framework"; import { Server } from "socket.io"; -import { IDirectMessage, IMessage } from "../models/channel"; +import { IDirectMessages, IMessage } from "../models/channel"; import UserSettings from "../config"; import MongooseDal from "./mongo"; import Utils from "./utils"; @@ -52,15 +52,14 @@ export class SocketService { // Direct Message socket.on("client:direct", async (message) => { - const directMessage: IDirectMessage = { - sender: message.from, - owner: message.to, - message: message.message, - created_at: new Date(), - }; - - await MongooseDal.addDirectMessage(directMessage); - this.ircClient.say(message.to, message.message); + const owner = UserSettings.nick; // TODO : get session user + const directMessage: IMessage = { + sender: owner, + message: message.message, + created_at: new Date(), + }; + await MongooseDal.addDirectMessage(owner, message.to, directMessage); + this.ircClient.say(message.to, message.message); }); }); @@ -84,14 +83,13 @@ export class SocketService { } async sendDirectMessageAsync(message: string, nick: string) { - const directMessage: IDirectMessage = { - sender: nick, - owner: UserSettings.nick, - message: message, - created_at: new Date(), - }; - - await MongooseDal.addDirectMessage(directMessage); + const owner = UserSettings.nick; // TODO : get session user + const directMessage: IMessage = { + sender: nick, + message: message, + created_at: new Date(), + }; + await MongooseDal.addDirectMessage(owner, nick, directMessage); console.log("sending direct message to " + nick); this.io.emit("chat:direct", { From 8d671499df449f9334f06b13aba12435e9c6dbd5 Mon Sep 17 00:00:00 2001 From: Adam Robins Date: Thu, 30 Jan 2025 21:26:20 +0100 Subject: [PATCH 3/3] Cleanup console --- main.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/main.ts b/main.ts index 7da1c9c..abb1802 100644 --- a/main.ts +++ b/main.ts @@ -44,7 +44,6 @@ app.use("/login", Express.static("public/login/login.html")); app.post("/join/dm/:nick", isLoggedIn, async (req, res) => { const nick = req.params.nick; var dms = await MongooseDal.getDirectMessagesForUser(UserSettings.nick, nick); - console.log(dms); res.send({ nick: nick, messages: dms?.messages || [] }); }); @@ -65,8 +64,6 @@ app.post("/channel/join", isLoggedIn, async (req, res) => { }; var channelMessages = await MongooseDal.getMessagesForChannel(req.body.channel); - - await MongooseDal.createChannel(channelMongo); channel.updateUsers(() => {