Язык: C++ с логикой Lua.
Код был протестирован для компиляции и запуска в Ubuntu x86, Ubuntu x86_64 и Gentoo x86_64 при условии использования соответствующей версии LuaJIT. Модификации в libjansson для удаления принудительного форматирования чисел с плавающей запятой с .0 после того, как целые числа были сделаны, чтобы правильно поддерживать «целые числа» и по-прежнему иметь автоматическое преобразование из Lua, который поддерживает только двойные числа.
Он также компилируется в Ubuntu 12.04 LTS x86_64, поскольку libjansson и google-glog собираются вручную.
ЛуаЖИТ
Либев
evhttpclient
Google-глог
google-perftools (tcmalloc) — необязательно при незначительных изменениях исходного кода и make-файла.
Либьянссон
наемник
libicu — см. локальный менеджер пакетов
завиток - см. локальный менеджер пакетов
boost — опционально, если вы замените навязчивые указатели чем-то своим.
Вероятно, потребуются изменения в src/Makefile, чтобы отразить ваши папки установки. Более надежная система сборки приветствуется, но на момент написания проекта она не требовалась. (CMake?)
Я (@zwagoth) здесь кое-что узнал: всегда оставляйте комментарии во время написания. Чтобы компенсировать это, я задокументирую базовую структуру программы, чтобы облегчить понимание.
Извиняюсь за беспорядок в кодовой базе. Это также был один из моих первых проектов на C++ любого масштаба и сложности.
Содержит почти всю базовую логику для обработки сообщений протокола, сообщений RTB и различных обратных вызовов базовых событий, таких как подключение и отключение.
Файл содержит таблицы анонимных функций, названных в честь событий, которые они обрабатывают. Этот файл не должен хранить какое-либо состояние и считается только областью хранения логики. Базовая конструкция этого файла заключается в том, чтобы обеспечить связующую логику, не заставляя Lua выполнять какую-либо тяжелую работу, и минимизировать объем данных, передаваемых в Lua и из него, за счет большего количества вызовов функций в C++.
В глобальное пространство имен файлов добавлены четыре таблицы с короткими именами для удобства ввода:
u
: функции соединения/персонажа (пользователя)
s
: серверные/глобальные функции состояния
c
: функции состояния канала
const
: идентификаторы ошибок и постоянные значения.
Функции обратного вызова протокола принимают два параметра: соединение, с которым связана команда, и копию таблицы предоставленных аргументов json.
Соединения представляют собой непрозрачные числа, и их НЕ следует каким-либо образом изменять. Изменение значения соединения небезопасно. Вы были предупреждены.
Lua-файл переменных конфигурации, которые используются во время запуска и работы демона чата.
Минималистичный флэш-сервер политики. Если вам нужна поддержка Flash, это то, что вам нужно. Настройте встроенную политику в соответствии со своими потребностями.
Точка входа в программу. Занимается инициализацией фоновых потоков и скручиванием.
Делает слишком много вещей. Поток кода начинается с Server::run()
.
Порядок подключения следующий:
listenCallback handshakeCallback connectionWriteCallback connectionReadCallback connectionwriteCallback
listenCallback
устанавливает обработчики событий для каждого соединения и передает поток в...
handshakeCallback
, который обрабатывает чтение для рукопожатий веб-сокета.
connectionWriteCallback
обрабатывает, когда соединение готово к записи, и включается, когда элементы находятся в очереди на запись в соединение. Управляет буферизацией.
connectionReadCallback
обрабатывает все события чтения после завершения фазы установления связи. Здесь происходит весь анализ протокола, а команды отправляются и запускаются изнутри этой функции.
pingCallback
обрабатывает отправку событий ping клиентам. Если протокол будет изменен, это должно быть одним из первых шагов.
connectionTimerCallback
периодически запускается и проверяет, не разорвано ли соединение, и очищает его.
runLuaEvent
— это магия тритона. Также здесь происходит волшебство для каждой команды. Здесь каждая команда переходит в код Lua из кода C++. Обрабатывает все состояния Lua и обратный вызов, чтобы гарантировать, что Lua не попадет в бесконечный цикл. Обрабатывает ошибки печати изнутри Lua.
В этом файле хранятся все данные о состоянии, связанные с каналами, подключениями, банами и модерацией.
Соединения делятся на идентифицированные и неопознанные, поскольку имена персонажей неизвестны до тех пор, пока сервер входа не подтвердит их существование и не допустит их попадания в пул символов, которые можно найти по имени.
Управляет сохранением и восстановлением состояния на диске.
Запускается как фоновый поток, который обрабатывает запросы и ответы на вход в систему и передает их обратно в основной поток.
Сериализованная система входа в систему, использует глобальную очередь входа. Это можно было бы немного улучшить.
Преобразование в cur_multi было бы неплохо, но требует некоторого интересного взаимодействия с libev или большого количества слепых опросов. Очереди должны быть заблокированы до того, как к ним можно будет получить доступ из-за многопоточности.
Базовый класс канала, хранит данные о состоянии канала на протяжении всего его существования. Все низкоуровневые действия, связанные с каналами, происходят в этом файле посредством перехватчиков в Lua. Обычно заключен в навязчивый указатель для управления временем жизни экземпляра.
Здесь происходит сериализация и десериализация каналов из json.
Управляет всеми сетевыми подключениями и отладкой состояний Lua.
Поддерживает списки изломов, статус, сообщение о статусе и пол.
Поддерживает список игнорируемых и друзей.
Ручки для каждого соединения дросселей.
Здесь происходит буферизация выходных данных.
Обычно передаются с использованием навязчивых указателей для управления временем жизни экземпляра.
Поддерживает внутренний список подключенных каналов. Его необходимо синхронизировать с фактическим списком пользователей канала.
Этот файл зарезервирован для нескольких функций, которым требуется высокая скорость, а не возможность настройки. Обрабатывает команду входа в систему ( IDN
). Обрабатывает команду отладки ( ZZZ
). Обрабатывает команду поиска ( FKS
).
Все команды-оболочки Lua, подпадающие под категорию s
в файлах Lua.
Все команды оболочки Lua, которые подпадают под категорию u
в файлах Lua.
Все команды-оболочки Lua, подпадающие под категорию c
в файлах Lua.
Все значения оболочки Lua, подпадающие под категорию const
в файлах Lua.
Сообщения об ошибках и определения.
Используйте определенные макросы для проверки ошибок и типов! Это единственный способ предотвратить сбой, если неправильный тип неожиданно передается в функцию как облегченные данные.
Убедитесь, что ваш стек Lua сбалансирован. Я очень старался убедиться, что это правда, но ошибки сделать легко.
Избегайте возврата таблиц в код Lua: их создание дорогое и часто имеет короткий период использования. Используйте здравый смысл, чтобы сбалансировать стоимость вызовов функций и стоимость построения таблиц.
Избегайте передачи строк в Lua без необходимости. Это может быть дорогостоящим из-за копий памяти.
Злоупотребление тем, что lua принимает несколько возвращаемых значений как встроенная функция. См. два примечания выше.
Обрабатывает push только поток redis. Это небольшая оболочка команд Redis и их возвращаемых значений.
Использует очередь ввода для получения команд. Команды выполняются периодически и не имеют гарантии надежности. Может быть отключен, и игнорирует ввод, если отключен.
GDB хорошо подходит для отладки этого приложения. Отключение tcmalloc и раздела JIT LuaJIT должно значительно помочь в отладке сбоев (tcmalloc может скрыть некоторые незначительные повреждения кучи).
Инструменты профилирования памяти в tcmalloc весьма хороши. Обратитесь к документации tcmalloc для получения дополнительной информации о том, как его использовать.