diff --git a/src/channel.js b/src/channel.js new file mode 100644 index 0000000..f4d82f3 --- /dev/null +++ b/src/channel.js @@ -0,0 +1,14 @@ +function Channel(name) { + this.name = name + this.userlist = [] + + this.join = function(user) { + let channel = this + this.userlist.push(user) + this.userlist.forEach(function(item) { + item.sendRaw(`:${user.nickname} JOIN ${channel.name}`) + }) + } +} + +module.exports = Channel diff --git a/src/server.js b/src/server.js index 988abd9..63e8fc3 100644 --- a/src/server.js +++ b/src/server.js @@ -1,5 +1,6 @@ const net = require("net") const User = require("../src/user.js") +const Channel = require("../src/channel.js") const RPL_WELCOME = '001' const ERR_NOSUCHNICK = '401' @@ -20,6 +21,7 @@ server.create = function create(config = {}) { password = config.password } let userlist = {} + let channellist = {} let server = net.createServer((socket) => { const user = new User(socket) if (!config.password) { @@ -84,6 +86,17 @@ server.create = function create(config = {}) { target.sendMsg(user, message) } + break; + case "JOIN": + let channelname = tokenized[1] + if (Object.keys(channellist).includes(channelname)) { + channellist[channelname].join(user) + } else { + let channel = new Channel(channelname) + channel.join(user) + channellist[channelname] = channel + } + break; case "QUIT": server.closeConnection(user.nickname) diff --git a/src/user.js b/src/user.js index b54678e..a9b454f 100644 --- a/src/user.js +++ b/src/user.js @@ -44,6 +44,9 @@ function User(socket) { this.sendMsg = function (from, message) { this.connection.write(`:${from.nickname} PRIVMSG ${this.nickname} :${message}\r\n`, "ascii") } + this.sendRaw = function(message) { + this.connection.write(`${message}\r\n`, "ascii") + } } module.exports = User diff --git a/test/command_join.js b/test/command_join.js new file mode 100644 index 0000000..6ea8ac3 --- /dev/null +++ b/test/command_join.js @@ -0,0 +1,72 @@ +const assert = require('assert'); +const EventEmitter = require('events'); +const IRCServer = require("../src/server.js"); + +describe("JOIN OK", function () { + it("should handle a JOIN command -> JOIN #testchan", function (done) { + const server = IRCServer.create() + let mockedSock = new EventEmitter() + mockedSock.address = function () { + return {port: 12346, family: 'IPv4', address: '127.0.0.1'} + } + mockedSock.write = function (data) { + let answer = data.toString("ascii") + if (answer.indexOf("JOIN") >= 0) { + assert.equal(answer, ":some_nick JOIN #testchan\r\n") + done() + } + } + mockedSock.destroy = function () { + done("Destroyed socket without answering") + } + + server.emit("connection", mockedSock) + mockedSock.emit('data', Buffer.from("NICK some_nick\r\n", "ascii")) + mockedSock.emit('data', Buffer.from("USER guest tolmoon tolsun :Ronnie Reagan\r\n", "ascii")) + mockedSock.emit('data', Buffer.from("JOIN #testchan\r\n", "ascii")) + }) + + it("should handle a JOIN command for more than one user -> JOIN #testchan and send join events to all channel members", function (done) { + const server = IRCServer.create() + // helper to count join messages for channel + // we should see 2 of them + let counter = 0 + let mockedSock1 = new EventEmitter() + mockedSock1.address = function () { + return {port: 12346, family: 'IPv4', address: '127.0.0.1'} + } + mockedSock1.write = function (data) { + let answer = data.toString("ascii") + if (answer.indexOf("JOIN") >= 0 && counter === 1) { + assert.equal(answer, ":other_nick JOIN #testchan\r\n") + done() + } + if (answer === ":some_nick JOIN #testchan\r\n") { + counter++ + } + } + mockedSock1.destroy = function () { + done("Destroyed socket without answering") + } + + let mockedSock2 = new EventEmitter() + mockedSock2.address = function () { + return {port: 12346, family: 'IPv4', address: '127.0.0.1'} + } + mockedSock2.write = function (data) { + return + } + mockedSock2.destroy = function () { + done("Destroyed socket without answering") + } + + server.emit("connection", mockedSock1) + server.emit("connection", mockedSock2) + mockedSock1.emit('data', Buffer.from("NICK some_nick\r\n", "ascii")) + mockedSock1.emit('data', Buffer.from("USER guest tolmoon tolsun :Ronnie Reagan\r\n", "ascii")) + mockedSock1.emit('data', Buffer.from("JOIN #testchan\r\n", "ascii")) + mockedSock2.emit('data', Buffer.from("NICK other_nick\r\n", "ascii")) + mockedSock2.emit('data', Buffer.from("USER guest tolmoon tolsun :Ronnie Reagan\r\n", "ascii")) + mockedSock2.emit('data', Buffer.from("JOIN #testchan\r\n", "ascii")) + }) +})