You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
5.3 KiB
142 lines
5.3 KiB
const net = require("net")
|
|
const User = require("../src/user.js")
|
|
const Channel = require("../src/channel.js")
|
|
|
|
const RPL_WELCOME = '001'
|
|
const ERR_NOSUCHNICK = '401'
|
|
const ERR_NOSUCHCHANNEL = '403'
|
|
const ERR_CANNOTSENDTOCHAN = '404'
|
|
const ERR_UNKNOWNCOMMAND = '421'
|
|
const ERR_ERRONEUSNICKNAME = '432'
|
|
const ERR_NONICKNAMEGIVEN = '431'
|
|
const ERR_NICKNAMEINUSE = '433'
|
|
const ERR_NEEDMOREPARAMS = '461'
|
|
|
|
|
|
let server = {}
|
|
|
|
server.create = function create(config = {}) {
|
|
let password
|
|
if (config.password) {
|
|
password = config.password
|
|
}
|
|
let userlist = {}
|
|
let channellist = {}
|
|
let server = net.createServer((socket) => {
|
|
const user = new User(socket, !config.password)
|
|
socket.on('data', function (data) {
|
|
data.toString("ascii").split("\r\n").forEach(function (commandline) {
|
|
if (commandline == "") {
|
|
return
|
|
}
|
|
let splitted = commandline.split(" ")
|
|
let tokenized = []
|
|
let lastParam = -1
|
|
for (let i = 0; i < splitted.length; i++) {
|
|
if (lastParam > 0) {
|
|
tokenized[lastParam] = tokenized[lastParam] + " " + splitted[i]
|
|
} else if (splitted[i].charAt(0) == ":" && i > 0) {
|
|
lastParam = i
|
|
tokenized[lastParam] = splitted[i].slice(1)
|
|
} else {
|
|
tokenized[i] = splitted[i]
|
|
}
|
|
}
|
|
let command = tokenized[0].toUpperCase()
|
|
switch (command) {
|
|
case "PING":
|
|
if (tokenized[1] && tokenized[1] === "irc.example.com") {
|
|
socket.write("PONG irc.example.com\r\n")
|
|
}
|
|
break;
|
|
case "NICK":
|
|
if (tokenized[1]) {
|
|
let nickname = tokenized[1]
|
|
// nick collision test
|
|
if (!Object.keys(userlist).includes(nickname)) {
|
|
user.setNickname(nickname)
|
|
userlist[user.nickname] = user
|
|
} else {
|
|
socket.write(`:irc.example.com ${ERR_NICKNAMEINUSE} ${nickname} :Nickname is already in use`, 'ascii')
|
|
}
|
|
|
|
|
|
} else {
|
|
socket.write(`:irc.example.com ${ERR_NONICKNAMEGIVEN} :No nickname given`, 'ascii')
|
|
}
|
|
|
|
break;
|
|
|
|
case "USER":
|
|
// ignoring servername and hostname, not useful these days
|
|
user.register(tokenized[1], tokenized[4])
|
|
let address = user.getAddress()
|
|
socket.write(`:irc.example.com 001 ${user.nickname} :Welcome to the example IRC Project ${user.nickname}!~${user.username}@${address}\r\n`, "ascii")
|
|
break;
|
|
case "PRIVMSG":
|
|
let target
|
|
let message = tokenized[2]
|
|
if (typeof tokenized[1] === 'string' && tokenized[1].charAt(0) === "#") {
|
|
target = channellist[tokenized[1]]
|
|
} else {
|
|
let targetUser = userlist[tokenized[1]]
|
|
if (targetUser && targetUser.registered) {
|
|
target = targetUser
|
|
}
|
|
}
|
|
if (target) {
|
|
target.sendMsg(user, message)
|
|
} else {
|
|
user.sendRaw(`:irc.example.com ${ERR_NOSUCHNICK} ${target} no such nick/channel`)
|
|
}
|
|
|
|
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)
|
|
break;
|
|
case "PASS":
|
|
if (tokenized[1] === config.password) {
|
|
user.authenticated = true
|
|
} else {
|
|
user.closeConnection()
|
|
}
|
|
break;
|
|
|
|
default:
|
|
console.error(`Unknown command: ${command}`);
|
|
}
|
|
});
|
|
}).on('error', (err) => {
|
|
console.error(err);
|
|
})
|
|
}).on('error', (err) => {
|
|
console.error(err);
|
|
throw err;
|
|
});
|
|
|
|
server.getUserlist = function () {
|
|
return userlist
|
|
}
|
|
|
|
server.closeConnection = function (user_nickname) {
|
|
let user = userlist[user_nickname]
|
|
user.closeConnection()
|
|
delete userlist[user_nickname];
|
|
}
|
|
|
|
return server
|
|
}
|
|
|
|
|
|
module.exports = server
|