Онлайн-чаты (или онлайн-консультанты) сегодня есть на многих сайтах. Кто-то ими активно пользуется, кто-то терпеть не может, а кто-то иногда открывает шутки ради. Для желающих развернуть свой собственный сервер чатов расскажу об open source решении Live Chat Engine.
Возможности
Проект содержит минимально необходимый набор для работы с чатами со стороны пользователя и оператора:
— сам чат;
— возможность оставить отзыв, когда нет активных операторов;
— email оповещения о таких отзывах;
— несколько операторов на один чат;
— браузерная нотификация операторов о новых сообщениях;
— просмотр User-Agent и Ip пользователя;
— просмотр истории чатов и отзывов.
Интеграции с различными мессенджерами пока нет, увы.
Чат на сайте:
Кабинет оператора:
Архитектура
Изначально было решено разделить проект на 3 логических части:
— фронт для операторов (chat-front-server);
— веб-апи и хранилище чатов (chat-node-server);
— координирующий сервер (chat-central-server).
Такой подход позволяет увеличивать количество аккаунтов, просто добавляя в систему новые 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<User>{
public GetAllBlockedUsers() {
//делаем поиск в таблице users
super("users",
//результаты маппим в классы User
User.class,
//список полей в запросе
new UserFields(),
//условие блока WHERE
new AndCondition(
new AccsBlocked(true)
));
}
}
А вот различные примеры вызова:
//INSERT
universal.update(new CreateUser(user));
//SELECT
List<User> 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 ]
Комментарии (16)
akbarovs
18.08.2015 03:37+1Ой, github.com/edolganov/live-chat-engine/search?utf8=%E2%9C%93&q=isThreadLang_EN — что это? Зачем хардкодить?
edolganov
18.08.2015 11:15На данный момент есть только 2 языка (рус и eng).
Поэтому удобно делать такую проверку: «Если isThreadLang_EN, то показать view_en иначе view_ru».
Когда будут другие локали, то сделав поиск по вызову isThreadLang_EN будет легко заменить эту логику на более общий код (а isThreadLang_EN — выбросить). Т.о. код эволюционирует по мере необходимости.akbarovs
19.08.2015 03:39А зачем вообще иметь различные вьюхи в зависимости от языка? Используйте resource bundles и показывайте лейблы и сообщения без того, чтобы клонировать разметку
edolganov
19.08.2015 09:22Да они тоже используются.
Но их не всегда хватает.
Иногда хочется просто сверстать целую страницу на другом языке. Например раздел документации.
Beholder
18.08.2015 09:39+2Тот случай, когда для сборки стоит использовать Maven, при таком-то количестве зависимостей.
edolganov
18.08.2015 11:20-2Да, я думаю о переходе на Maven. На первых этапах отказ от него сделал процесс разработки более быстрым и гибким.
Сейчас, когда код устоялся, можно и зависимости вынести вон из проекта.Lure_of_Chaos
18.08.2015 12:18+2Более быстрым и гибким? Разве ж не утомительно вручную скачивать библиотеки и все зависимости и кидать их в папку, тщательно контролируя наличие всего необходимого и нужных версий?
Мавен как раз автоматизирует задачу, сводя все труды к добавлению пары тегов, что значительно ускоряет как и первичную настройку проекта, так и последующую разработку…
Так же Мавен обеспечивает и гибкость — заменить одну библиотеку с зависимостями на конкурирующую, обновить\откатить версию — со всеми зависимостями становится намного менее хлопотно.
Я уже не говорю о размере проекта за счет выкидывания необходимых бинарников без потери возможности сборки «в один клик», о размере репозитория версионной системы, а также возможных конфликтов истории в этих самых бинарниках.
nikitasius
Какое преимущество вы получаете, использую шаблонизатор вместо обычных insert и select?
Простота отпадает сразу, так как мне, как человеку, который работает с запросами в Java не кажется проще ваше решение.
Но, несомненно оно выглядит «красивее» танцев со строками, будь до append'ы или пачка .replace(), но последние очень просты и достаточно ясно смотрятся.
edolganov
Для себя я получил лаконичность.
Можно быстро собирать простые и скучные запросы в атомарные классы
(в тексте это CreateUser, GetAllBlockedUsers, UpdateUserById)
и потом передавать их в шаблонизатор, скрывая рутину.
Например в одном вызове скрыта вся рутина создания INSERT запроса:
Этот код приятно скрыл всю реализацию, оставив только саму идею, что очень ценно на уровне бизнес-логики, где не хочется отвлекаться на особенности БД.
Тоже самое делает MyBatis (скрывает сложность), но в нем бывает занудно писать в десятый раз очередной селект по id для очередного объекта БД. Поэтому появился этот простой шаблонизатор. :)
zzashpaupat
Советую попробовать JOOQ.
Прост, как 2 копейки, статическая типизация запросов, удобный DSL: пишешь код, как SQL-запрос.
namc
ну и платный к тому же
zzashpaupat
Он платный только для коммерческих СУБД. В контексте «open-source сервера онлайн-чатов» использовать Oracle или другую платную СУБД было бы нелогично.
DigitalSmile
Кроме прочего, такой вариант проще поддерживать:
1) При изменении логики внутри запросов необходимо поправить только xml и не лезть в код (например, в больших командах будет меньше конфликтов в VCS между теми кто поправил код, исправив баг в бизнес логике, и теми кто внес правку в xml).
2) Сами xml могут быть получены извне приложения (да, такое иногда нужно).