Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development

Чат в реальном времени с Node.js 'Readline и Socket.io

by
Difficulty:IntermediateLength:MediumLanguages:

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Final product image
What You'll Be Creating

Node.js имеет недооцененный модуль в своей стандартной библиотеке, что на удивление полезно. Модуль Readline делает то, что и говорит его название: он считывает строку ввода с терминала. Его можно использовать, чтобы задать пользователю вопрос или два или создать запрос в нижней части экрана. В этом уроке я намерен продемонстрировать возможности Readline и создать в режиме реального времени CLI-чат, поддерживаемый Socket.io. Клиент будет не только отправлять простые сообщения, но и иметь команды для эмоций с /me, личные сообщения с /msg и разрешать изменение псевдонимов с помощью /nick.

Немного о Readline

Это, вероятно, самое простое использование Readline:

Мы включаем модуль, создаем интерфейс Readline со стандартными потоками ввода и вывода, а затем задаем пользователю одноразовый вопрос. Это первое использование Readline: задание вопросов. Если вам нужно что-то подтвердить с помощью пользователя, возможно, в форме популярного: «Вы хотите сделать это? (Y/n)», которые пронизывают инструменты CLI, readline.question() - это способ сделать это.

Другая функциональность, которую предоставляет Readline, - это приглашение, которое можно настроить с помощью символа по умолчанию «>» и временно приостановить, чтобы предотвратить ввод. Для нашего клиента чата Readline это будет наш основной интерфейс. Будет одно вхождение readline.question(), чтобы спросить у пользователя псевдоним, но все остальное будет readline.prompt().

Управление вашими зависимостями

Начнем со скучной части: зависимостей. Этот проект будет использовать socket.io, пакет socket.io-client и ansi-color. Ваш файл package.json должен выглядеть примерно так:

Запустите npm install, и все должно выполнится автоматически.

Сервер

Для этого урока мы будем использовать невероятно простой сервер Socket.io:

Все, что он делает, - это принимает входящее сообщение от одного клиента и передает его всем. Вероятно, сервер будет более надежным для крупномасштабного приложения, но для этого простого примера его должно быть достаточно.

Это должно быть сохранено в каталоге проекта как server.js.

Клиент

Прежде чем мы перейдем к интересной части, нам нужно включить наши зависимости, определить некоторые переменные и запустить интерфейс Readline и сокет.

На данный момент код очень понятен. У нас есть переменная nickname, соединение сокета (через пакет socket.io-client) и наш интерфейс Readline.

Socket.io будет подключаться к localhost через порт 3636 в этом примере, конечно, это будет изменено на домен и порт вашего собственного сервера, если вы делаете приложение для рабочего чата.

Клиент: запрашиваем имя пользователя

Теперь пришло время для нашего первого использования Readline! Мы хотим попросить пользователя выбрать ник, который будет идентифицировать их в чате. Для этого мы будем использовать метод questionline() Readline.

Мы устанавливаем переменную ник из значения, полученного от пользователя, отправляем сообщение на сервер (которое будет передано другим клиентам), которое наш пользователь присоединился к чату, затем переключите интерфейс Readline обратно в режим подсказки. Значение true, переданное в prompt(), гарантирует, что символ приглашения будет правильно отображаться. (В противном случае курсор может перейти в нулевую позицию на линии, а «>» не будет отображаться.

К сожалению, у Readline есть разочаровывающая проблема с методом prompt(). Он не очень хорошо сочетается с console.log(), который выводит текст на ту же строку, что и символ приглашения, оставляя блуждающие символы «>»  и другие странности. Чтобы исправить это, мы не будем использовать console.log в любом месте этого приложения, за исключением одного . Вместо этого вывод должен быть передан этой функции:

Это слегка хитрое решение гарантирует, что текущая строка на консоли пуста и что курсор находится в нулевой позиции перед печатью вывода. Затем оно явно требует, чтобы запрос выводился снова, потом.

Итак, в оставшейся части этого руководства вы увидите console_out() вместо console.log().

Клиент: Обработка ввода

Есть два типа ввода, которые пользователь может ввести: чат и команды. Мы знаем, что командам предшествует косая черта, поэтому их легко различить.

В Readline есть несколько обработчиков событий, но наиболее важным является, несомненно, line. Всякий раз, когда символ новой строки обнаруживается во входном потоке (из клавиши возврата или ввода), срабатывает это событие. Поэтому нам нужно подключиться к line для нашего обработчика ввода.

Если первый символ входной строки является косой чертой, мы знаем, что это команда, для которой потребуется больше обработки. В противном случае мы просто отправляем обычное сообщение чата и сбрасываем запрос. Обратите внимание на разницу между данными, переданными через сокет, и для сообщения соединения на предыдущем шаге. Он использует другой type, поэтому принимающий клиент знает, как отформатировать сообщение, и мы также передаем переменную nick.

Имя команды (cmd) и текст, следующий за ним (arg), изолированы  регулярным выражением и магией подстроки, затем мы передаем их функции, обрабатывающей команду.

Если пользователь набирает /nick gollum, то переменная nick сбрасывается на gollum, где раньше, возможно, раньше был smaagol, и на сервер будет отправлено уведомление.

Если пользователь набирает /msg bilbo Where is the precious?, Одно и то же регулярное выражение используется для разделения получателя и сообщения, тогда объект с типом сообщения tell отправляется на сервер. Это будет отображаться немного иначе, чем обычное сообщение и не должно быть видимым для других пользователей. По общему признанию, наш чрезмерно простой сервер будет вслепую отдавать сообщение всем, но клиент будет игнорировать подсказки, которые не адресованы правильному нику. Более надежный сервер может быть более дискретным.

Команда emote используется в форме /me is eating second breakfast. Ник добавляется к emote таким образом, который должен быть знаком любому, кто использовал IRC или играл в многопользовательскую ролевую игру.

Клиент: обработка входящих сообщений

Теперь клиенту нужен способ получения сообщений. Все, что нам нужно сделать, это подключиться к событию message клиента Socket.io и соответствующим образом форматировать данные для вывода.

Сообщения с типом chat, которые не были отправлены клиентом с использованием нашего ника, отображаются с ником и текстом чата. Пользователь уже может видеть, что он набрал в Readline, поэтому нет смысла выводить его снова. Здесь я использую пакет ansi-color, чтобы немного раскрасить результат. Это делать не обязательно, но это облегчает общение с чатом.

Сообщения с типом notice или emote печатаются как есть, хотя и окрашены в голубой цвет.

Если сообщение содержит тип tell, а ник равен текущему имени этого клиента, вывод принимает форму [Somebody->You] Hi!. Конечно, это не очень личное. Если вы хотите видеть сообщения всех, все, что вам нужно сделать, это убрать часть && data.to == nick. В идеале сервер должен знать, какой клиент должен отправить сообщение, а не отправлять его клиентам, которые ему не нужны. Но это добавляет ненужную сложность, которая выходит за рамки данного руководства.

Зажги!

Теперь посмотрим, все ли работает. Чтобы проверить это, запустите сервер, выполнив node server.js, а затем откройте пару новых окон терминала. В новых окнах выполните node client.js и введите ник. Затем вы сможете общаться между ними, считая, что все идет хорошо.

Надеюсь, этот учебник показал вам, как легко начать работу с модулем Readline. Вы можете попробовать добавить дополнительные функции в приложение чата, для большей практики. И, наконец, проверьте документацию Readline для полного API.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.