Реализация сервера обмена сообщениями, которая использует двунаправленный протокол RPC для реализации общения, подобного чату. Предназначен для решения общих проблем общедоступной сети, таких как надежная доставка, несколько подключений от одного пользователя, разрешения и присутствия в реальном времени. RPC Запрос обработки и формат сообщений комнаты настраивается с помощью крючков, что позволяет реализовать что-либо от сервера чата до совместного приложения со сложным разрешением конфликтов. Сообщения номера также могут быть использованы для создания публичных API или для туннельных сообщений M2M для устройств IoT.
Надежный помещение в помещении с использованием хранения истории на стороне сервера и API синхронизации.
Произвольные сообщения форматируют только функцию проверки (крючок), позволяя пользовательским/гетерогенным форматам сообщений (включая двоичные данные внутри сообщений).
API присутствия пользователя с уведомлениями.
Создание комнаты в реальном времени и API-интерфейсы для управления пользователями в режиме реального времени. Поддержки для режимов доступа на основе черного списка или белого списка и дополнительной группы администраторов.
Бесплатная поддержка подключений нескольких пользователей от различных разработок с любым экземпляром службы.
Написанный в виде микросервиса без сохранения состояния, использует Redis (также поддерживает конфигурации кластеров) в качестве государственного хранилища, может быть горизонтально масштабирован по требованию.
Обширная поддержка настройки. Пользовательская функциональность может быть добавлена через крючки до/после любой обработки запросов клиента. И обработчики запросов (команды) могут быть вызваны на стороне сервера через API.
Планируемый сетевой транспорт. Связь с клиентом проводится с помощью двунаправленного протокола RPC. Включена внедрение транспорта Socket.io.
Планируемый государственный магазин. Магазины памяти и Redis включены.
Поддерживает легкого онлайн -пользователя для онлайн -сообщений пользователей.
Прочитайте эту статью для получения дополнительной информации.
Этот проект представляет собой модуль узла, доступный через NPM. Проверьте их, если у вас их не установлено локально.
$ npm i chat-serviceСначала определите конфигурацию сервера. На стороне сервера определяют крючок подключения к сокету, так как служба полагается на реализацию Extern Auth. Пользователю просто нужно пройти проверку на авторитет, и явное добавление пользователя не требуется.
const ChatService = require ( 'chat-service' )
const port = 8000
function onConnect ( service , id ) {
// Assuming that auth data is passed in a query string.
let { query } = service . transport . getHandshakeData ( id )
let { userName } = query
// Actually check auth data.
// ...
// Return a promise that resolves with a login string.
return Promise . resolve ( userName )
} Создание сервера - это простой экземпляр объекта. ПРИМЕЧАНИЕ. Метод close должен быть вызван для правильного выключения экземпляра службы (см. Удовлетворение сбоев).
const chatService = new ChatService ( { port } , { onConnect } )
process . on ( 'SIGINT' , ( ) => chatService . close ( ) . finally ( ( ) => process . exit ( ) ) ) Сервер теперь работает на порту 8000 , используя состояние memory . По умолчанию используется пространство имен Socket.io '/chat-service' . Добавьте комнату с пользователем admin в качестве владельца комнаты. Все комнаты должны быть явно созданы (также предоставлена возможность создавать комнаты со стороны клиента).
// The room configuration and messages will persist if redis state is
// used. addRoom will reject a promise if the room is already created.
chatService . hasRoom ( 'default' ) . then ( hasRoom => {
if ( ! hasRoom ) {
return chatService . addRoom ( 'default' , { owner : 'admin' } )
}
} ) На клиенте требуется реализация socket.io-client . Чтобы отправить запрос (команда) Использовать метод emit , результат (или ошибка) будет возвращен в Socket.io ACK обратный вызов. Для прослушивания сообщений сервера используются on методе.
const io = require ( 'socket.io-client' )
// Use https or wss in production.
let url = 'ws://localhost:8000/chat-service'
let userName = 'user' // for example and debug
let token = 'token' // auth token
let query = `userName= ${ userName } &token= ${ token } `
let opts = { query }
// Connect to a server.
let socket = io . connect ( url , opts )
// Rooms messages handler (own messages are here too).
socket . on ( 'roomMessage' , ( room , msg ) => {
console . log ( ` ${ msg . author } : ${ msg . textMessage } ` )
} )
// Auth success handler.
socket . on ( 'loginConfirmed' , userName => {
// Join room named 'default'.
socket . emit ( 'roomJoin' , 'default' , ( error , data ) => {
// Check for a command error.
if ( error ) { return }
// Now we will receive 'default' room messages in 'roomMessage' handler.
// Now we can also send a message to 'default' room:
socket . emit ( 'roomMessage' , 'default' , { textMessage : 'Hello!' } )
} )
} )
// Auth error handler.
socket . on ( 'loginRejected' , error => {
console . error ( error )
} ) Это запускаемый код, файлы находятся в example каталога.
Можно использовать другие транспорты, кроме Socket.io. Существует доказательство концепции транспорта, которое использует соединение WebSocket с некоторым минимальным уровнем абстракции API WS-Messaging и простой эмиттер-пубсб-брокером в качестве абстракции фанатов Backend Message Fanout.
Вот основные вещи, которые должен позволить транспорт:
Отправляйте сообщения с сервера на группы клиентов (на основе одного строкового полного соответствия, так как обмен сообщениями в комнате).
Реализовать связь с запросом от клиента на сервер.
Реализуйте какое -то постоянное соединение (или семантически эквивалентное), оно требуется для отслеживания присутствия.
Служба чата использует Redis в качестве общего магазина с настойчивостью. В реальном приложении некоторая информация может потребоваться другим услугам, но не практически полностью переосмыслить государственный магазин. Лучшим альтернативным подходом является использование крючков. Например, чтобы сохранить все сообщения комнаты в другой базе данных, только можно использовать крюк roomMessageAfter . Также ServiceAPI может быть выставлен с помощью автобусов обмена бэкэнд на других внутренних серверах.
При обычных обстоятельствах все ошибки, которые возвращаются пользователю службы (через ответы на запросы, loginConfirmed или loginRejected сообщения) являются экземплярами ChatServiceError . Все остальные ошибки указывают на ошибку программы или сбой в сервисной инфраструктуре. Чтобы включить регистрацию отладки таких ошибок, используйте export NODE_DEBUG=ChatService . Библиотека использует реализацию Bluebird ^3.0.0 , поэтому для включения длинных трассов стека используйте export BLUEBIRD_DEBUG=1 . Настоятельно рекомендуется использовать перспективные версии API для крючков и подклассов ChatServiceError для возврата крючков.
API API и RPC на стороне сервера доступна в Интернете.
Служба полностью абстрагирует концепцию подключения из концепции пользователя, поэтому у одного пользователя может быть более одного соединения (включая соединения по разным узлам). Для присутствия пользователя количество соединенных гнезлок должно быть больше нуля. Все API, предназначенные для работы на пользовательском уровне, обрабатывая многочисленные подключения пользователя.
Соединения полностью независимы, дополнительная поддержка на стороне клиента не требуется. Но есть информационные сообщения и команды, которые можно использовать для получения информации о подключениях других пользователей. Это делает возможным реализовать паттерны синхронизации на стороне клиента, например, поддерживать все соединения, чтобы соединиться с теми же комнатами.
В каждом комнате есть система разрешений. Существует единый пользователь, который имеет все привилегии администратора и может назначать пользователей группе администраторов. Администраторы могут управлять разрешениями доступа других пользователей. Поддерживаются два режима: черный список и белый список. После списков доступа/модификаций режима служба автоматически удаляет пользователей, которые потеряли разрешение на доступ.
Если параметры enableRoomsManagement включены, пользователи могут создавать комнаты с помощью команды roomCreate . Создатель комнаты будет ее владельцем и также может удалить его с помощью команды roomDelete .
Прежде чем крючки могут быть использованы для реализации дополнительных систем разрешений.
Когда пользователь отправляет номера, в ответе RPC id сообщения возвращается. Это означает, что сообщение было сохранено в магазине (в приложении только круговой структуры, такой как структура). Идентификаторы сообщений комнаты - это последовательность, начиная с 1 , которая увеличивается по одному для каждого успешно отправленного сообщения в комнате. Клиент всегда может проверить идентификатор сообщения о последнем номере с помощью команды roomHistoryInfo и использовать команду roomHistoryGet , чтобы получить отсутствующие сообщения. Такой подход гарантирует, что сообщение может быть получено, если оно не удалено из -за вращения.
По умолчанию клиент может отправлять сообщения, которые ограничены только {textMessage: 'Some string'} . Для включения пользовательских сообщений Format предоставьте directMessagesChecker или roomMessagesChecker Hooks. Когда крюк разрешается, формат сообщения принимается. Сообщения могут быть произвольными данными с несколькими ограничениями. Верхний уровень должен быть Object , без timestamp , author или полей id (служба заполнит эти поля перед отправкой сообщений). Вложенные уровни могут включать произвольные типы данных (даже бинарные), но без вложенных объектов с type поля, установленным в 'Buffer' (используется для манипуляций с бинарными данными).
Каждая пользовательская команда поддерживает до и после добавления Hook, и поддерживаются клиентские крючки подключения/отключения. Команда и крючки выполняются последовательно: до Chook - Command - After Hook (она также будет вызвана по ошибкам команды). Последовательность завершения в крючках возможно. Клиенты могут отправлять дополнительные командные аргументы, крючки могут прочитать их и ответить дополнительными аргументами.
Для выполнения пользовательского командного сервера предоставлена execUserCommand . Кроме того, есть еще несколько методов на стороне сервера, предоставляемых ServiceAPI и TransportInterface . Ищите некоторые случаи настройки в примерах настройки.
Служба хранит присутствие пользователя и данные об подключении в магазине, которые могут быть постоянными или общими. Таким образом, если экземпляр неверно выключается (без вызова или ожидания метода close ) или потеряно полностью сетевое соединение с хранилищем, данные о присутствии станут неверными. Чтобы исправить этот случай, приведен метод instanceRecovery .
Также существуют более тонкие случаи, касающиеся согласованности данных с зависимостью от подключения. Экземпляры транспортной связи и экземпляры хранения могут испытывать различные виды сетевых, программных или аппаратных сбоев. В некоторых случаях (например, операция для нескольких пользователей) такие сбои могут вызывать несоответствия (по большей части ошибки будут возвращены эмитентам команды). Эти события сообщаются с помощью эмиттера экземпляра (например, событие storeConsistencyFailure ), и данные могут быть синхронизированы с помощью методов RecoveryAPI .
По умолчанию каждый пользователь имеет уникальный вход (имя пользователя). Вместо управления генерацией имен можно использовать интеграцию с отдельным транспортом (или мультиплексированное соединение, например, другое пространство имен сокета). Сообщения в номерах могут быть пересылки из roomMessage за крючком на транспорт, который доступен без входа. И наоборот, анонимные пользователи могут выполнять некоторые команды службы через execUserCommand с включенным опцией обходных разрешений.
roomMessage после крючка может также использоваться для пересылки сообщений из одной комнаты в другую. Таким образом, комнаты можно использовать для агрегации сообщений из других комнат. Поскольку крючки являются просто функциями и имеют полный доступ к контенту сообщений, он позволяет реализовать произвольные правила пересылки на основе контента. Включая реализацию систем с высоко персонализированными пользовательскими (клиентскими) конкретными каналами.
По умолчанию у других пользователей нет возможности узнать номер и типы пользовательских соединений, соединенных в комнату. Такая информация может быть передана, например, в строке запроса, а затем сохранена через подключаемый крючок. Объявление может быть сделано в крючках onJoin и onLeave , используя метод непосредственно транспортировки sendToChannel . Также дополнительная информация о типах соединенных устройств должна быть отправлена из roomGetAccessList после Hook (когда имя списка равна 'userlist' ).
Там нет операции «Удалить» или «Редактировать операцию», так как они будут делать несоответствия в истории комнаты. Общей альтернативой для удаления и редактирования является использование сообщений комнаты с особым значением, которое клиенты будут использовать для скрытия или изменения сообщений.
Если вы столкнетесь с ошибкой в этом пакете, отправьте отчет об ошибке в проблемы Github Repo.
PR также принимаются.
Грань