From ca4e032dd60902f01b07946304ed4133dcf99945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C3=B3=C5=82grabia?= Date: Sun, 17 Sep 2017 17:13:19 +0200 Subject: [PATCH] Adding semi working chat implementation for channels. --- build.gradle | 1 + .../handlers/JoinCommandHandler.java | 35 +++++- .../handlers/NickCommandHandler.java | 2 +- .../handlers/PingMessageHandler.java | 3 +- .../handlers/PrivMessageHandler.java | 12 +- .../handlers/SessionCommandHandler.java | 7 +- .../handlers/UserCommandHandler.java | 9 +- src/main/resources/static/IrcClient.js | 103 ++++++++++++++++-- src/main/resources/static/index.html | 11 +- src/main/resources/static/index.js | 9 +- 10 files changed, 158 insertions(+), 34 deletions(-) diff --git a/build.gradle b/build.gradle index 85cf61e..17fca05 100644 --- a/build.gradle +++ b/build.gradle @@ -30,5 +30,6 @@ dependencies { compile('org.webjars:bootstrap:3.3.7-1') compile('org.webjars:jquery:3.2.1') compile('org.webjars:bootbox:4.4.0') + compile('org.webjars:jquery:3.2.1') testCompile('org.springframework.boot:spring-boot-starter-test') } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/JoinCommandHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/JoinCommandHandler.java index 8db0163..0d8e711 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/JoinCommandHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/JoinCommandHandler.java @@ -1,13 +1,46 @@ package pl.polgrabiat.websockets.chat.websocketschat.handlers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.web.socket.WebSocketSession; +import pl.polgrabiat.websockets.chat.websocketschat.dto.ChannelCtx; import pl.polgrabiat.websockets.chat.websocketschat.dto.GlobalCtx; +import pl.polgrabiat.websockets.chat.websocketschat.dto.UserCtx; import java.io.IOException; +import java.util.StringTokenizer; public class JoinCommandHandler implements SessionCommandHandler { + + private static final Logger lg = LoggerFactory.getLogger(JoinCommandHandler.class); + @Override public boolean handleCommand(GlobalCtx globalCtx, WebSocketSession session, String payload, String command, String data) throws IOException { - return false; + StringTokenizer tokenizer = new StringTokenizer(data); + String destination = tokenizer.nextToken().trim(); + + ChannelCtx channelCtx = globalCtx.getChannels().get(destination); + if (channelCtx == null) { + channelCtx = new ChannelCtx(); + channelCtx.setName(destination); + globalCtx.getChannels().put(destination, channelCtx); + } + + UserCtx userCtx = globalCtx.getUserSessions().get(session); + channelCtx.getUsers().add(userCtx); + + for (UserCtx user : channelCtx.getUsers()) { + try { + sendMessage(user.getSession(), globalCtx, + destination, + "PRIVMSG " + channelCtx.getName() + " " + + user.getNick() + " has " + + " joined the channel"); + } catch (RuntimeException e) { + lg.error("Error while sending a message", e); + } + } + + return true; } } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/NickCommandHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/NickCommandHandler.java index fb2fd84..f15e918 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/NickCommandHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/NickCommandHandler.java @@ -14,7 +14,7 @@ public class NickCommandHandler implements SessionCommandHandler { String nick = tokenizer.nextToken(); if (nick.equals(globalCtx.getUserSessions().get(session).getNick())) { - sendMessage(session,globalCtx,403, "MSG nick already used"); + sendMessage(session,globalCtx, globalCtx.getServerName(),"MSG nick already used"); return true; } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PingMessageHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PingMessageHandler.java index 65f7e3f..27b0b8c 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PingMessageHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PingMessageHandler.java @@ -8,7 +8,8 @@ import java.io.IOException; public class PingMessageHandler implements SessionCommandHandler { @Override public boolean handleCommand(GlobalCtx globalCtx, WebSocketSession session, String payload, String command, String data) throws IOException { - sendMessage(session,globalCtx,403, "MSG PING message is not accepted from the client-side"); + sendMessage(session,globalCtx, globalCtx.getUserSessions().get(session).getNick(), + "MSG PING message is not accepted from the client-side"); return true; } } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PrivMessageHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PrivMessageHandler.java index f13ceb2..2ca4a5c 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PrivMessageHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/PrivMessageHandler.java @@ -1,6 +1,5 @@ package pl.polgrabiat.websockets.chat.websocketschat.handlers; -import org.apache.catalina.User; import org.springframework.web.socket.WebSocketSession; import pl.polgrabiat.websockets.chat.websocketschat.dto.ChannelCtx; import pl.polgrabiat.websockets.chat.websocketschat.dto.GlobalCtx; @@ -20,21 +19,21 @@ public class PrivMessageHandler implements SessionCommandHandler { ChannelCtx channel = globalCtx.getChannels().get(destination); if (channel == null) { sendMessage(session, - globalCtx, 404, "MSG invalid destination"); + globalCtx, destination,"MSG invalid destination"); return true; } UserCtx userCtx = globalCtx.getUserSessions().get(session); if (!channel.getUsers().contains(userCtx)) { - sendMessage(session, globalCtx, 403, "MSG You are not the member of this channel"); + sendMessage(session, globalCtx, destination, "MSG You are not the member of this channel"); return true; } // sending to other users for (UserCtx user : channel.getUsers()) { - sendMessage(user.getSession(), globalCtx, 200, payload); + sendMessage(user.getSession(), globalCtx, destination, payload); } return true; @@ -42,15 +41,16 @@ public class PrivMessageHandler implements SessionCommandHandler { } else { // user + UserCtx userCtx = globalCtx.getUserSessions().get(destination); if (userCtx == null) { sendMessage(session, - globalCtx, 404, "MSG invalid destination"); + globalCtx, destination,"MSG invalid destination"); return true; } sendMessage(userCtx.getSession(), - globalCtx, 200, payload); + globalCtx, destination, payload); return true; } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/SessionCommandHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/SessionCommandHandler.java index f5fcfcc..ee8e360 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/SessionCommandHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/SessionCommandHandler.java @@ -9,11 +9,10 @@ import java.io.IOException; public interface SessionCommandHandler { boolean handleCommand(GlobalCtx globalCtx, WebSocketSession session, String payload, String command, String data) throws IOException; - default void sendMessage(WebSocketSession session, GlobalCtx globalCtx, int responseCode, String data) throws IOException { - session.sendMessage(new TextMessage(String.format(":%s %d %s %s", + default void sendMessage(WebSocketSession session, GlobalCtx globalCtx, String source, String data) throws IOException { + session.sendMessage(new TextMessage(String.format(":%s %s %s", globalCtx.getServerName(), - responseCode, - globalCtx.getUserSessions().get(session).getNick(), + source, data))); } } diff --git a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/UserCommandHandler.java b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/UserCommandHandler.java index 550076a..7fe54a4 100644 --- a/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/UserCommandHandler.java +++ b/src/main/java/pl/polgrabiat/websockets/chat/websocketschat/handlers/UserCommandHandler.java @@ -15,7 +15,7 @@ public class UserCommandHandler implements SessionCommandHandler { @Override public boolean handleCommand(GlobalCtx globalCtx, WebSocketSession session, String payload, String command, String data) throws IOException { - StringTokenizer tokenizer = new StringTokenizer(data," "); + StringTokenizer tokenizer = new StringTokenizer(data, " "); String userName = tokenizer.nextToken(); String code1 = tokenizer.nextToken(); if (!"0".equals(code1)) { @@ -32,7 +32,9 @@ public class UserCommandHandler implements SessionCommandHandler { UserCtx userCtx = globalCtx.getUserSessions().get(session); if (userCtx == null) { - sendMessage(session, globalCtx, 403, + sendMessage(session, + globalCtx, + globalCtx.getUserSessions().get(session).getNick(), "MSG you nead to select the nick"); return true; } @@ -40,7 +42,8 @@ public class UserCommandHandler implements SessionCommandHandler { userCtx.setUserName(userName); userCtx.setRealName(realName); - sendMessage(session, globalCtx, 200, + sendMessage(session, globalCtx, + globalCtx.getUserSessions().get(session).getNick(), "MSG OK"); return true; } diff --git a/src/main/resources/static/IrcClient.js b/src/main/resources/static/IrcClient.js index 1df7955..e358006 100644 --- a/src/main/resources/static/IrcClient.js +++ b/src/main/resources/static/IrcClient.js @@ -1,22 +1,38 @@ +function tabRef (destination) { + if (destination.startsWith("#")) { + return "c" + destination.substr(1); + } else { + return "u" + destination; + } +}; + function IrcClient(sockJs, nick, userName, realName) { this.sockJs = sockJs; this.nick = nick; this.userName = userName; this.realName = realName; - this.sendMsg = function(msg) { + this.sendMsg = function (msg) { console.log("OUT-MSG " + msg); this.sockJs.send(msg); }; - this.sendNickMsg = function() { + this.sendNickMsg = function () { this.sendMsg("NICK " + this.nick); }; - this.sendUserMsg = function() { + this.sendUserMsg = function () { this.sendMsg("USER " + this.userName + " 0 * :" + this.realName); }; + this.sendPrivMsg = function (msg) { + this.sendDestPrivMsg(this.selectedDestination(), msg); + }; + + this.sendDestPrivMsg = function (dest, msg) { + this.sendMsg("PRIVMSG " + dest + " " + msg); + }; + this.init = function () { this.sendNickMsg(); this.sendUserMsg(); @@ -33,7 +49,7 @@ function IrcClient(sockJs, nick, userName, realName) { console.log("Socket closed"); }; - this.sendPongMsg = function(nr) { + this.sendPongMsg = function (nr) { this.sendMsg("PONG :" + nr); }; @@ -42,15 +58,78 @@ function IrcClient(sockJs, nick, userName, realName) { this.sendPongMsg(data); }; - this.sockJs.onmessage = function (e) { - console.log("Received message: " + e.data); - var server = document.getElementById("server"); - var logRow = document.createElement("div"); - logRow.innerHTML = e.data; - server.appendChild(logRow); - if (e.data.startsWith("PING ")) { - ircClientRef.handlePongMessage(e.data, e.data.substr(7)); + this.createTabEl = function (destination) { + var tabs = $("#tabs"); + var liEl = $("
  • "); + var aEl = $(""); + + aEl.attr("href", "#" + tabRef(destination)); + aEl.attr("data-toggle", "tab"); + aEl.html(destination); + + + liEl.attr("id", "label-" + tabRef(destination)); + liEl.append(aEl); + tabs.append(liEl); + }; + + this.createTabContentEl = function (destination) { + var tabsContent = $("#tabs-content"); + var divEl = $("
    "); + divEl.addClass("tab-pane fade in"); + divEl.attr("id", tabRef(destination)); + tabRef(destination); + + tabsContent.append(divEl); + }; + + this.checkForDestElseCreate = function (destination) { + var tabIdx = tabRef(destination); + if ($("#label-" + tabIdx).length > 0) { + return; } + + ircClientRef.createTabEl(destination); + ircClientRef.createTabContentEl(destination); + }; + + this.displayDestinationMessage = function (destination, msg) { + this.checkForDestElseCreate(destination); + var server = $("#" + tabRef(destination)); + var logRow = $("
    "); + logRow.text(msg); + server.append(logRow); + return server; + }; + + this.selectedDestination = function () { + return $("#tabs").find("li.active").text(); + }; + + this.fetchDestination = function (data) { + var preDestIdx = data.indexOf(" "); + if (preDestIdx < 0) { + return null; + } + + var destIdx = preDestIdx + 1; + var preDataIdx = data.indexOf(" ", destIdx); + return data.substr(destIdx, preDataIdx - destIdx); + }; + + this.sockJs.onmessage = function (e) { + var msg = e.data; + if (msg.startsWith("PING ")) { + ircClientRef.handlePongMessage(msg, msg.substr(7)); + return; + } + + console.log("Received message: " + msg); + var destination = ircClientRef.fetchDestination(e.data); + var tabName = destination; + console.log("Destination of the message: " + destination); + + var server = ircClientRef.displayDestinationMessage(tabName, msg); }; }; \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 1741570..8bd85f5 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -7,21 +7,22 @@ + -