RealChat architecture

RealChat - архитектура

описание внутренней архитектуры программы
Автор: Hunter
Дата: 14.06.2009 21:18

Немного истории

Программа писалась в несколько этапов. Сначала это был любительский проект, попытка написать чат, внешне похожий на Intranet Chat. По мере совершенствования возникали новые сложности и приходилось менять архитектуру программы.

Раньше ядра как такового не было - была основная форма, на которой лежали все визуальные и невизуальные объекты (кроме отдельных окошек). При создании новой страницы чата эта страница программно собиралась из составляющих объектов. Страницы идентифицировались по заголовку, т.е. две страницы с одинаковыми заголовками уже не работали. Обращение к объектам на странице происходило напрямую. Т.е. для добавления юзера в список юзеров нужно было найти нужную страницу, и обратиться прямо к визуальному списку, который на ней лежит.

Со временем добавились новые типы страниц - список каналов, список файлов. Обращение к их элементам усложнилось, нужно было проверять тип страницы. При всяком изменении страницы приходилось искать по всей программе обращения к элементам страницы и исправлять их. И вообще структура была запутана, но все это как-то работало.. Но расширять функционал и добавлять новые фичи было очень сложно.

Сейчас функционал поделен на несколько основных частей:

  • Ядро, которое является центром программы. Все обращения между компонентами идут через ядро. Для добавления чего-то нового теперь не нужно рыться по всей программе, а достаточно добавить в ядро вызов этого функционала. Можно даже добавлять «пустые» функции, которые в данный момент не реализованы, но могут быть реализованы позже. Достаточно «прицепить» реализацию функции к ядру в виде плагина или отдельного модуля.
  • Интерфейсная часть, т.е. то, что видит и с чем работает пользователь. Окошки, кнопки, менюшки, поля, галочки, картинки, итд.. Теперь при клике на кнопку не выполняется некий предопределенный кусок программы, а вызывается соответсвующая команда ядра. И ядро может само обрабатать нажатие кнопки, а может передать его модулям. Обращение к интерфейсу из модулей программы тоже идет через ядро. Поскольку элементы интерфейса не имеют жесткой привязки к структуре программы (только к ядру), ими можно манипулировать как угодно - перемещать между окнами, вкладывать друг в друга, создавать и убивать «на лету», по необходимости. Лишь бы не терялась привязка к ядру, а ядро доступно отовсюду.
  • Программные компоненты (модули), которые подключаются к ядру. Это как бы отдельные программы, которые, к примеру, устанавливают связь с сервером и работают как клиенты чата. Тот же клиент IRC не имеет своего визуального интерфейса, а сообщает ядру, что надо создать новую закладку, надо на такую-то закладку вывести такой-то текст. И наоборот, при вводе текста в закладке чата этот текст через ядро приходит к клиету IRC, обрабатывается и отправляется на сервер. Можно включить сразу два клиента с разными настройками. Можно запустить клиентов для разных протоколов.. Модуль может содержать свои собственные визуальные формы, которые может использовать сам, а может через ядро подключать к общему интерфейсу. В принципе, даже само ядро может быть программным компонентом и подключаться к другому ядру или самому себе. =)
  • Конфиг. Это некое подобие виндового реестра. У каждого модуля есть свой конфиг. Есть еще главный конфиг, в нем общие настройки программы. И есть еще глобальный конфиг, который объединяет в себе все прочие конфиги. Конфиг имеет древовидную структуру, но может быть представлен и в виде списка. В принципе, конфиг может использоваться и как простая база данных.

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

Потом настройки были реализованы как свойства отдельного автономного объекта (конфига), а их визуальное представление в виде отдельных панелей было создано заранее и свалено в одну кучу. Стало удобнее, но такой конфиг прописан в коде программы, его нельзя расширить во время работы программы.

Сейчас конфиг реализован по образу и подобию виндового реестра (то есть позволяет хранить одинаковые наборы данных в разных ветках), веткам можно назначать страницу визуальных элементов (контролов), сами страницы настроек не валяются как попало, а сидят на невидимых закладках. Есть универсальная страница настроек, в виде списка настроект данной ветки. Можно подключать ветки настроек из других модулей, копировать их, сохранять все сразу или по отдельности, итд… Кроме того, обращение к элементу конфига идет не по программной ссылке, а по идентификатору или имени - можно легко обращаться к настройкам из плагинов. То есть конфиг получился очень гибким и независимым хранилищем настроек. Но поскольку конфиг используется в каждом кусочке программы, то пришлось переписать почти всю программу.

Состав модулей программы

Основные модули программы:

  • Core.pas (ядро)
  • Main.pas (главная форма)
  • Configs.pas (конфиг)

Интерфейсные модули:

  • OptionsForm.pas (форма настроек)
  • MainOptions.pas (основные настройки)
  • ClientsFrame.pas (форма списка компонентов)
  • InfoFrame.pas (форма справочной информации)
  • ChatPage.pas (страница чата)
  • FilesFrame.pas (страница файлов)

Вспомогательные модули:

  • Misc.pas (вспомогательные функции)
  • Plugins.pas (модуль работы с плагинами)
  • PluginsFunc.pas (реализация командного языка плагинов)
  • AsyncSock.pas (асинхронные сокеты)
  • Timer.pas (расписание событий)
  • Sounds.pas (звуки)

Модули компонентов:

  • IRC.pas (компонент клиента IRC)
  • IRC_Options.pas (настройки IRC)
  • DCC.pas (компонент DCC)
  • DCC_FileAccept.pas (форма принятия файла)
  • ChanListFrame.pas (форма списка каналов)
  • iChatUnit.pas (компонент клиента iChat)
  • iChatOptions.pas (настройки iChat)

Есть и другие модули, часть из них устаревшие.

Подробности устройства программы

Ядро состоит из базовых классов, менеджеров и функций:

  • TPageInfo - подробная информация о странице и ее свойствах
  • TChatClient - базовый класс для протоколов клиентов чата. Содержит набор свойств и методов, которые обязательно должны быть у потомков.
  • TChatPage - Класс, описывающий произвольную страницу. Это может быть страница чата, файлов, состояния, настроек, итд..
  • PagesManager - Менеджер страниц чата. Содержит список всех страниц чата и методы для управления страницами.
  • ClientsManager - Менеджер клиентов чата. Содержит список всех клиентов и методы для управления клиентами, рассылки сообщений.
  • Набор глобальных функций - содержит глобальные функции и процедуры, позволяющие выполнять некоторые действия - проиграть звук, показать записку, показать окно ввода, записать отладочное сообщение, сменить язык или стиль, итд..

Кроме того, в ядре есть такие глобальные объекты, как:

  • MainForm - главная форма содержит набор основных визуальных и невизуальных элементов - менюшек, значков, кнопок, итд.. Доступ к ним должен выполняться только из функций и классов ядра. Только в особых случаях, когда нецелесообразно использование отдельных элементов (например, списка значков и стилей), допустимо использование списков значков и стилей с главной формы. В дальнейшем это должно быть устранено или стандартизировано.
  • MainConf - главный конфиг программы. Содержит общие настройки. Доступ к значениям производится по имени значения, например MainConf['UserName']. Конфиг динамический, можно свободно добавлять и использовать новые значения во время работы. Но следует добавлять только глобальные параметры, которые используются за пределами отдельного компонента. Компоненты должны использовать свои конфиги.
  • LangIni - языковый конфиг. Содержит языковые переменные. Все надписи должны браться из этого конфига. Отличается от других конфигов тем, что не имеет визуальной формы, не имеет древовидной структуры и является обычным ini-файлом.

Создание нового компонента:

  • Интерфейсные компоненты - формы.

Новые формы можно создавать обычным образом. Но нельзя оставлять их в RealChat.dpr. Во время работы программы создайте новую форму, Parent:=MainForm, при закрытии делайте Release().

  • Интерфейсные компоненты - страницы

Форму страницы создавайте в виде фрейма TFrame. Конструктор переопределите так, чтобы он принимал параметр Page: TChatPage, который описывает свойства страницы и позволяет установить обработчики событий страницы. Основные события - смена языка, стиля и статуса активности страницы. Страница не должна обращаться напрямую к другим страницам и компонентам - только к ядру. Для создания страницы используйте PagesManager.CreatePage.

  • Программные компоненты - клиенты

Клиент должен быть наследником Core.TChatClient и реализовывать все его методы и свойства. Это методы обработки сообщений пользователя, работы с настройками, подключение-отключение, итд.. Клиент в свою очередь должен иметь свой конфиг (даже пустой), может создавать новые формы, регистрировать страницы. Доступ у клиента только к ядру и вспомогательным модулям. Если у клиента есть конфиг, то у конфига может быть визуальная форма с набором панелей. Панели содержат интерактивные контролы и привязаны к узлам конфига.

Comments