Open source сервер онлайн-чатов на Java

a62d24c353834b4e80498064018633ee.png

Онлайн-чаты (или онлайн-консультанты) сегодня есть на многих сайтах. Кто-то ими активно пользуется, кто-то терпеть не может, а кто-то иногда открывает шутки ради. Для желающих развернуть свой собственный сервер чатов расскажу об
open source решении Live Chat Engine.

Возможности


Проект содержит минимально необходимый набор для работы с чатами со стороны пользователя и оператора:
— сам чат,
— возможность оставить отзыв, когда нет активных операторов,
— email оповещения о таких отзывах,
— несколько операторов на один чат,
— браузерная нотификация операторов о новых сообщениях,
— просмотр User-Agent и Ip пользователя,
— просмотр истории чатов и отзывов.
Интеграции с различными мессенджерами пока нет, увы.

Чат на сайте:
7c7cff0eb50e43f8bc095676b10fe3b2.png

Кабинет оператора:
d8ecb88ddba14a7594fe838ee946180c.png

Архитектура


Изначально было решено разделить проект на 3 логических части:
— фронт для операторов (chat-front-server)
— веб-апи и хранилище чатов (chat-node-server)
— координирующий сервер (chat-central-server)

f902d85ffde64cfd984999f3dff72968.png

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

Режимы работы


Движок чатов можно интегрировать в существующие системы (Tool mode), когда аккаунты заводит админ, фронт доступен только собственным операторам, а node сервер открыт браузерам пользователей сайтов.

Либо же можно запустить движок как самостоятельный сервис (SaaS mode), где аккаунты заводят пользователи, а за их использование ежемесячно берется плата по указанным тарифам… Но тогда, поздравляю, вы создадите еще один сервис чатов и вам придется конкурировать с целой армией похожих сервисов, что будет не просто :)

Особенности реализации


— Фронт и нод сервера запускаются как веб-приложения на веб-сервере Tomcat.
При этом не используется Spring или EJB: да-да, можно писать большие проекты и без популярных стеков.
Я уже как-то рассказывал о таком подходе. В любом случае, этот проект был домашним и мне хотелось многие вещи написать самостоятельно, так что не судите за отсутствие любимых вами фреймворков — и без них все хорошо! :)

— Для общения с базой данных используется MyBatis и еще один внутренний шаблонизатор запросов.
MyBatis, без сомнения, очень удобен для создания заковыристых запросов, но утомителен, для простых, однотипных CRUD.
Поэтому был написал небольшой шаблонизатор
UniversalQueries, формирующий запросы по указанным данным.

Например, вот описание для INSERT-а:

public class CreateUser extends CreateRow {

        public CreateUser(User user) {
                //сохраняем в таблицу "users"
                super("users", 
                        //список полей, которые надо сохранить
                        //каждое поле имеет нужный тип: строка, число, дата и т.д.
                        new Id(user.id),
                        new Login(user.login),
                        new Email(user.email),
                        new PswHash(user.pswHash),
                        new ActivationStateDate(user.activationStateDate),
                        new ActivationCode(user.activationCode));
        }
}

И SELECT-а с условием:

public class GetAllBlockedUsers extends SelectRows{

        public GetAllBlockedUsers() {
                //делаем поиск в таблице users
                super("users", 
                                //результаты маппим в классы User
                                User.class, 
                                //список полей в запросе
                                new UserFields(), 
                                //условие блока WHERE
                                new AndCondition(
                                        new AccsBlocked(true)
                                ));
        }

}

А вот различные примеры вызова:


//INSERT
universal.update(new CreateUser(user));

//SELECT
List users = universal.select(new GetAllBlockedUsers());

//UPDATE - указываем список полей на обновление
universal.update(new UpdateUserById(id, 
                new StatusCode(ACTIVATED),
                new ActivationStateDate(new Date()),
                new ActivationCode(null)));

В итоге все сложные запросы написаны в xml MyBatis, все рутинные — через данный шаблонизатор.

— Фронт для операторов написан на Js вместе с JQuery

Итоги


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

[Ссылка на Github]

© Habrahabr.ru