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.

125 lines
4.4 KiB

  1. const net = require("net")
  2. const User = require("../src/user.js")
  3. const RPL_WELCOME = '001'
  4. const ERR_NOSUCHNICK = '401'
  5. const ERR_NOSUCHCHANNEL = '403'
  6. const ERR_CANNOTSENDTOCHAN = '404'
  7. const ERR_UNKNOWNCOMMAND = '421'
  8. const ERR_ERRONEUSNICKNAME = '432'
  9. const ERR_NONICKNAMEGIVEN = '431'
  10. const ERR_NICKNAMEINUSE = '433'
  11. const ERR_NEEDMOREPARAMS = '461'
  12. let server = {}
  13. server.create = function create(config = {}) {
  14. let password
  15. if (config.password) {
  16. password = config.password
  17. }
  18. let userlist = {}
  19. let server = net.createServer((socket) => {
  20. const user = new User(socket)
  21. if (!config.password) {
  22. user.authenticated = true
  23. }
  24. socket.on('data', function (data) {
  25. data.toString("ascii").split("\r\n").forEach(function (commandline) {
  26. if (commandline == "") {
  27. return
  28. }
  29. let splitted = commandline.split(" ")
  30. let tokenized = []
  31. let lastParam = -1
  32. for (let i = 0; i < splitted.length; i++) {
  33. if (lastParam > 0) {
  34. tokenized[lastParam] = tokenized[lastParam] + " " + splitted[i]
  35. } else if (splitted[i].charAt(0) == ":" && i > 0) {
  36. lastParam = i
  37. tokenized[lastParam] = splitted[i].slice(1)
  38. } else {
  39. tokenized[i] = splitted[i]
  40. }
  41. }
  42. let command = tokenized[0].toUpperCase()
  43. switch (command) {
  44. case "PING":
  45. if (tokenized[1] && tokenized[1] === "irc.example.com") {
  46. socket.write("PONG irc.example.com\r\n")
  47. }
  48. break;
  49. case "NICK":
  50. if (tokenized[1]) {
  51. let nickname = tokenized[1]
  52. // nick collision test
  53. if (!Object.keys(userlist).includes(nickname)) {
  54. user.setNickname(nickname)
  55. userlist[user.nickname] = user
  56. } else {
  57. socket.write(ERR_NICKNAMEINUSE, " nickname in use")
  58. }
  59. } else {
  60. socket.write(ERR_NONICKNAMEGIVEN, "ERROR: NO NICKNAME PROVIDED")
  61. }
  62. break;
  63. case "USER":
  64. // ignoring servername and hostname, not useful these days
  65. user.register(tokenized[1], tokenized[4])
  66. let address = user.getAddress()
  67. socket.write(`:irc.example.com 001 ${user.nickname} :Welcome to the example IRC Project ${user.nickname}!~${user.username}@${address}\r\n`, "ascii")
  68. break;
  69. case "PRIVMSG":
  70. let target = userlist[tokenized[1]]
  71. let message = tokenized[2]
  72. if (target.registered === false) {
  73. socket.write(`:irc.example.com ${ERR_NOSUCHNICK} ${target} no such nick/channel`)
  74. } else {
  75. target.sendMsg(user, message)
  76. }
  77. break;
  78. case "QUIT":
  79. server.closeConnection(user.nickname)
  80. break;
  81. case "PASS":
  82. if (tokenized[1] === config.password) {
  83. user.authenticated = true
  84. } else {
  85. user.closeConnection()
  86. }
  87. break;
  88. default:
  89. console.error(`Unknown command: ${command}`);
  90. }
  91. });
  92. }).on('error', (err) => {
  93. console.error(err);
  94. })
  95. }).on('error', (err) => {
  96. console.error(err);
  97. throw err;
  98. });
  99. server.getUserlist = function () {
  100. return userlist
  101. }
  102. server.closeConnection = function (user_nickname) {
  103. let user = userlist[user_nickname]
  104. user.closeConnection()
  105. delete userlist[user_nickname];
  106. }
  107. return server
  108. }
  109. module.exports = server