v1.0.5

Архитектура termi#

Цель структуры — чтобы по папкам и именам классов было понятно, что где лежит и зачем. Одно правило на весь проект: обработчик пакета тонкий, логика живёт в сервисах, сервисы не знают про сеть.

1. Слои и зависимости#

text
┌───────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Client │ │ Hub │ │ Server │ │ Bot │ приложения └─────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ └──────────────┴──────┬───────┴──────────────┘ ▼ ┌────────────┐ │ Termi.Core │ протокол · шифрование · сеть · JSON · файлы └────────────┘

Приложения зависят только от Core и не знают друг о друге — они общаются по сети (JSON-строки поверх защищённого TCP). Core подключается к каждому проекту исходниками (<Compile Include="..\Termi.Core\**\*.cs">), поэтому каждый exe — один файл без dll рядом.

Termi.Core#

папкаnamespaceчто внутри
Protocol/Termi.ProtocolPkt (один пакет), User/RInfo/CInfo/PInfo, Perm (права), Names (имена и токены входа)
Security/Termi.SecurityX25519, Gcm (AES-256-GCM), Crypto (SHA, HMAC, PBKDF2, резервная копия ключа) — в .NET Framework своих нет
Networking/Termi.NetworkingConn (шифрованное соединение, очередь отправки), PacketRouter<TSession> + IPacketHandler<TSession>
Serialization/Termi.SerializationJson — маленький сериализатор по публичным полям (формат совместим с версией на Go)
Files/Termi.FilesFileStore — файлы сообщений, кусками до 100 МБ, шифруются на диске
Util/Termi.UtilArgs, Log, U

2. Сетевой протокол#

JSON-строки; перед ними — рукопожатие X25519 (статический ключ сервера + эфемерный клиентский), дальше каждая строка шифруется AES-GCM. Клиент запоминает отпечаток ключа сервера при первом входе (TOFU). Личные сообщения дополнительно шифруются между клиентами (e1: + base64), hub видит только шифртекст. Поле t пакета — его тип; список типов — в обработчиках (Net/Handlers/*, свойство Types).

3. Termi.Server — как устроен#

text
TcpListener ─► ConnectionHandler ─► PacketRouter ─► Handler ─► Service ─► Storage │ рукопожатие по полю t тонкий логика диск │ вход, бан, │ PlayerLoginEvent └─ на выходе: PlayerQuitEvent
папкароль
Hosting/ServerHost — корень: создаёт всё и держит Lock; ClientSession (одно подключение = IPlayer), SessionRegistry, ServerOptions
Net/ConnectionHandler (жизнь подключения), Handlers/ — SessionHandler, ChatHandler, VoiceHandler, FileHandler, AdminHandler
Services/PermissionService, ChannelService, MemberService, ChatService, VoiceService, ModerationService, FileTransferService, ClientPluginCatalog
Storage/ConfigStore (роли, баны, каналы), HistoryStore (шифрованный журнал), AuditLog, MemberBook
Commands/встроенные команды: по классу на команду (RoleCommand, KickCommand, …), PlayerSender/ConsoleSender
Plugins/ServerPluginManager — поиск dll, порядок по зависимостям, включение/выключение
Api/публичный API плагинов — единственная папка, которую читает автор плагина
Terminal/консоль оператора (те же команды)

Потоки и блокировки. Каждое подключение — свой поток, общее состояние защищено одной реентерабельной блокировкой ServerHost.Lock. Методы сервисов вызываются под ней; поэтому обработчики событий плагинов тоже выполняются под ней и могут свободно вызывать API сервера. Отправка клиенту неблокирующая (очередь в Conn), так что медленный клиент не тормозит остальных.

Как добавить…#

чточто сделать
новый тип пакетаметод в подходящем сервисе → строка в Types и case в подходящем Handlers/* (или новый IPacketHandler<ClientSession> + Router.Add в ServerHost)
встроенную командукласс-наследник BuiltinCommand в Commands/ + строка в RegisterBuiltinCommands
событиекласс в Api/Events/ + Events.Call(new …) в нужном сервисе
хранилищекласс в Storage/, создать в ServerHost.LoadStorage

4. Termi.Hub#

Та же схема: Hosting/HubHost → Net/ConnectionHandler → PacketRouter<UserSession> → Handlers/* → Services/* → Storage/*. Сервисы: AuthService (регистрация/вход, PBKDF2), PresenceService, ContactService, ProfileService, DirectMessageService, CallService.

5. Termi.Client#

text
Tui/ терминал: цвета, текст, экранный буфер, клавиши, строка ввода Imaging/ картинки: Image2, декодеры (JPEG/PNG/GIF/DIB), sixel и kitty, видео-кадры звонков Os/ всё, что зависит от ОС — за интерфейсом IPlatform Windows/ winmm · GDI · VFW · WinForms (буфер, трей, всплывающие окна) · нативные плагины-DLL Linux/ ffmpeg · grim · parecord/paplay · xclip/wl-paste DemoPlatform заглушки для тестов (TERMI_DEMO=1) Model/ данные: сообщения, серверы, темы, настройки, шифрование личных сообщений Application/ само приложение — разбито по функциям (partial class App) Rendering/ отрисовка панелей и главный цикл (sixel/kitty) Ui/ модальные окна Network/ подключение к hub, приём пакетов Social/ контакты, личные чаты, файлы Profile/ профиль и баннер Servers/ роли и участники сервера Plugins/ подключение к серверам, клиентские плагины Calls/ звонки и голосовые каналы (VoiceMixer — микшер) Extras/ выбор фото, вставка

Os/Platform.cs выбирает IPlatform (Windows / Linux / Demo) один раз; остальной код вызывает Platform.ScreenWorker(...), Platform.StartAudio(...) и не знает, какая ОС под ним. Пространства имён подключены глобально (GlobalUsings.cs), поэтому в файлах нет длинных списков using.

6. Плагины двух видов — не путать#

серверныеклиентские
гдепапка plugins/ серверапапка client-plugins/ сервера
что.NET-сборки с классом PluginBaseнативные DLL с функцией termi_command
работаютна сервере, для всех участникову каждого клиента (Windows), скачиваются при входе
описаниеdocs/PLUGINS.mdPLUGINS.txt в сборке для Windows