Добавлена документация
This commit is contained in:
@@ -51,7 +51,7 @@ public interface IMessengerAdapter
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Контракт конфигурации адаптера.
|
/// Контракт конфигурации адаптера.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMessangerAdapterSetup : IMessengerAdapter
|
public interface IMessengerAdapterSetup : IMessengerAdapter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Запуск работы адаптера
|
/// Запуск работы адаптера
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ namespace BotPages.Core.Abstractions;
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Фабрика адаптеров мессенджеров.
|
/// Фабрика адаптеров мессенджеров.
|
||||||
/// Используется для разрешения конкретного <see cref="IMessangerAdapterSetup"/> по типу мессенджера.
|
/// Используется для разрешения конкретного <see cref="IMessengerAdapterSetup"/> по типу мессенджера.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMessengerAdapterFactory
|
public interface IMessengerAdapterFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Список зарегистрированных адаптеров.
|
/// Список зарегистрированных адаптеров.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, IMessangerAdapterSetup> Adapters { get; }
|
Dictionary<string, IMessengerAdapterSetup> Adapters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Зарегистрировать адаптер для указанного типа мессенджера.
|
/// Зарегистрировать адаптер для указанного типа мессенджера.
|
||||||
@@ -23,9 +23,9 @@ public interface IMessengerAdapterFactory
|
|||||||
/// Экземпляр адаптера, реализующий <see cref="IMessengerAdapter"/>.
|
/// Экземпляр адаптера, реализующий <see cref="IMessengerAdapter"/>.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Текущий экземпляр <see cref="MultiAdapterFactory"/> для цепочки вызовов.
|
/// Текущий экземпляр <see cref="IMessengerAdapterFactory"/> для цепочки вызовов.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
IMessengerAdapterFactory Register(string messengerType, IMessangerAdapterSetup adapter);
|
IMessengerAdapterFactory Register(string messengerType, IMessengerAdapterSetup adapter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить адаптер для указанного мессенджера.
|
/// Получить адаптер для указанного мессенджера.
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class MultiAdapterFactory : IMessengerAdapterFactory
|
public sealed class MultiAdapterFactory : IMessengerAdapterFactory
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, IMessangerAdapterSetup> _adapters = new(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, IMessengerAdapterSetup> _adapters = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Список зарегистрированных адаптеров.
|
/// Список зарегистрированных адаптеров.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, IMessangerAdapterSetup> Adapters => _adapters;
|
public Dictionary<string, IMessengerAdapterSetup> Adapters => _adapters;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Зарегистрировать адаптер для указанного типа мессенджера.
|
/// Зарегистрировать адаптер для указанного типа мессенджера.
|
||||||
@@ -25,7 +25,7 @@ public sealed class MultiAdapterFactory : IMessengerAdapterFactory
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// Текущий экземпляр <see cref="MultiAdapterFactory"/> для цепочки вызовов.
|
/// Текущий экземпляр <see cref="MultiAdapterFactory"/> для цепочки вызовов.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public IMessengerAdapterFactory Register(string messengerType, IMessangerAdapterSetup adapter)
|
public IMessengerAdapterFactory Register(string messengerType, IMessengerAdapterSetup adapter)
|
||||||
{
|
{
|
||||||
_adapters[messengerType] = adapter;
|
_adapters[messengerType] = adapter;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public sealed class BotPagesApp
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавить адаптер.
|
/// Добавить адаптер.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BotPagesApp AddAdapter(string messengerType, IMessangerAdapterSetup adapter)
|
public BotPagesApp AddAdapter(string messengerType, IMessengerAdapterSetup adapter)
|
||||||
{
|
{
|
||||||
_adapterFactory.Register(messengerType, adapter);
|
_adapterFactory.Register(messengerType, adapter);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
164
README.md
164
README.md
@@ -1,92 +1,96 @@
|
|||||||
# BotPages Framework
|
# BotPages
|
||||||
|
|
||||||
BotPages — это архитектурный фреймворк для построения Telegram/MAX‑ботов с чистыми слоями, расширяемыми API и удобным developer experience.
|
BotPages — кроссплатформенный фреймворк для создания диалоговых ботов с системой страниц (page‑based conversational framework).
|
||||||
|
|
||||||
## ✨ Возможности
|
Цели проекта:
|
||||||
- **Навигация через страницы**: каждая страница — отдельный обработчик логики.
|
- Простая модель страниц и навигации.
|
||||||
- **Единый метод GoToAsync**: автоматически поддерживает как `SingletonPage`, так и `StatefulPage`.
|
- Портируемость между мессенджерами через адаптеры.
|
||||||
- **StatefulPage**: свойства автоматически сохраняются в `StateStorage`.
|
- Поддержка middleware и декларативной системы команд.
|
||||||
- **SingletonPage**: один экземпляр на всё приложение, без состояния.
|
- Минимум boilerplate и удобный developer experience.
|
||||||
- **Middleware**: подключение промежуточных обработчиков (логирование, обработка ошибок).
|
|
||||||
- **Автоматическая регистрация страниц**: через рефлексию.
|
Структура репозитория
|
||||||
- **Роутинг страниц**: возможность устанавливать пути вызова для страниц.
|
|
||||||
- **Команды**: возможность установки команд, которые работают приоритетнее обработчиков страниц.
|
- `BotPages.Core` — ядро фреймворка: навигация, страницы, маршрутизация, реестр команд, middleware, абстракции адаптеров и хранилища состояния.
|
||||||
- **Минимум boilerplate**: декларативные интерфейсы и fluent API.
|
- `BotPages.Telegram` — адаптер для Telegram Bot API (реализация `IMessangerAdapterSetup`/`IMessengerAdapter`).
|
||||||
|
- `Demo` — пример приложения с несколькими страницами и конфигурацией адаптера.
|
||||||
|
- `BotPages` — мета‑проект для упаковки библиотек.
|
||||||
|
- `docs/` — внутренняя документация проекта (Quickstart, API reference и т.д.).
|
||||||
|
|
||||||
|
Требования
|
||||||
|
|
||||||
|
- .NET 8 SDK
|
||||||
|
- C# 12
|
||||||
|
|
||||||
|
Быстрый старт (локально)
|
||||||
|
|
||||||
|
1. Клонируйте репозиторий:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.frigat.duckdns.org/FrigaT/BotPages.git
|
||||||
|
cd BotPages
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Соберите решения:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet build
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Запуск демо (Telegram):
|
||||||
|
|
||||||
|
- Установите переменную окружения `TELEGRAM_TOKEN` с токеном бота.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
setx TELEGRAM_TOKEN "<token>" # Windows
|
||||||
|
export TELEGRAM_TOKEN="<token>" # Linux/macOS
|
||||||
|
```
|
||||||
|
|
||||||
|
- Запустите demo:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run --project Demo
|
||||||
|
```
|
||||||
|
|
||||||
|
Основные концепции
|
||||||
|
|
||||||
|
- `BotPagesApp` — точка конфигурации приложения: регистрация адаптеров, middleware, маршрутов и команд, запуск.
|
||||||
|
- `Page`, `StatefulPage`, `SingletonPage` — модели страниц с жизненным циклом (`OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError`).
|
||||||
|
- `NavigationService` — управление переходами между страницами и определение текущей страницы по сессии.
|
||||||
|
- `CommandsRegistry` — шаблоны команд вида `/cmd {arg} {opt?}` с поддержкой именованных и опциональных аргументов.
|
||||||
|
- `IPageMiddleware` — middleware-конвейер, выполняющийся для каждого апдейта.
|
||||||
|
- `IMessangerAdapterSetup` / `IMessengerAdapter` — интерфейсы, позволяющие подключать новые мессенджеры.
|
||||||
|
|
||||||
|
Документация
|
||||||
|
|
||||||
|
Полная внутренняя документация находится в `docs/`:
|
||||||
|
- `docs/GETTING_STARTED.md` — быстрый старт и примеры конфигурации.
|
||||||
|
- `docs/API_REFERENCE.md` — краткий reference публичных API.
|
||||||
|
- `docs/PROJECT_DOCUMENTATION.md` — обзор архитектуры и компонентов.
|
||||||
|
|
||||||
|
XML‑документация генерируется при сборке (опция `GenerateDocumentationFile` в `.csproj`), её можно использовать для генерации HTML‑референса (docfx, MkDocs и т.п.).
|
||||||
|
|
||||||
|
Примеры использования
|
||||||
|
|
||||||
## 🚀 Быстрый старт
|
|
||||||
```csharp
|
```csharp
|
||||||
var app = new BotPagesApp(factory, state, logger)
|
var app = new BotPagesApp(stateStorage, logger)
|
||||||
.UseDefaultPage<WelcomePage>()
|
.AddAdapter("telegram", new TelegramAdapterSetup(token))
|
||||||
|
.AddDefaultPage<WelcomePage>()
|
||||||
.MapCommand<WelcomePage>("/start")
|
.MapCommand<WelcomePage>("/start")
|
||||||
.AddMiddleware(new LoggingMiddleware(logger))
|
.AddMiddleware(new LoggingMiddleware(logger));
|
||||||
.AddMiddleware(new ErrorHandlingMiddleware(logger));
|
|
||||||
|
await app.Build(CancellationToken.None);
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📄 Пример страниц
|
Вклад и тестирование
|
||||||
|
|
||||||
### StatefulPage
|
- Принимам пулл‑реквесты. Описание PR должно содержать цель и краткое описание изменения.
|
||||||
```csharp
|
- Следуйте единому стилю кода и включённым nullable-аннотациям.
|
||||||
public sealed class WelcomePage : StatefulPage
|
|
||||||
{
|
|
||||||
[Statefull("visitCount")]
|
|
||||||
private int VisitCount;
|
|
||||||
|
|
||||||
private PageContext? Context { get; set; }
|
Лицензия
|
||||||
|
|
||||||
public override async Task OnEnter(PageContext ctx, CancellationToken ct)
|
Проект распространяется под лицензией MIT. Смотрите файл `LICENSE`.
|
||||||
{
|
|
||||||
Context = ctx;
|
|
||||||
|
|
||||||
LoadState();
|
Контакты
|
||||||
VisitCount++;
|
|
||||||
SaveState();
|
|
||||||
|
|
||||||
await ctx.SendTextAsync($"Добро пожаловать 🚀. Вы заходили сюда {VisitCount} раз(а).", ct: ct);
|
Автор: FrigaT
|
||||||
}
|
Репозиторий: https://git.frigat.duckdns.org/FrigaT/BotPages
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### SingletonPage
|
|
||||||
```csharp
|
|
||||||
public sealed class HelpPage : SingletonPage
|
|
||||||
{
|
|
||||||
public override Task OnEnter(PageContext ctx, CancellationToken ct)
|
|
||||||
=> ctx.SendTextAsync("Это справка 📖", ct: ct);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🧩 Навигация
|
|
||||||
```csharp
|
|
||||||
await ctx.Navigation.GoToAsync<WelcomePage>(ctx, ct); // Stateful
|
|
||||||
await ctx.Navigation.GoToAsync<WelcomePage>(ctx, agrs, ct); // Stateful with arguments
|
|
||||||
await ctx.Navigation.GoToAsync<HelpPage>(ctx, ct); // Singleton
|
|
||||||
await ctx.Navigation.GoToHome(ctx, ct); // Stateful
|
|
||||||
```
|
|
||||||
|
|
||||||
## ⚙️ Middleware
|
|
||||||
```csharp
|
|
||||||
public sealed class LoggingMiddleware : IPageMiddleware
|
|
||||||
{
|
|
||||||
private readonly ILogger _logger;
|
|
||||||
public LoggingMiddleware(ILogger logger) => _logger = logger;
|
|
||||||
|
|
||||||
public async Task InvokeAsync(PageContext ctx, Func<Task> next, CancellationToken ct)
|
|
||||||
{
|
|
||||||
_logger.Log(LogLevel.Info, $"Update: {ctx.Update.Kind}");
|
|
||||||
await next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🏗 Архитектурные принципы
|
|
||||||
- **Separation of concerns**: страницы не знают о транспорте, всё через адаптеры.
|
|
||||||
- **Расширяемость**: новые страницы и middleware подключаются декларативно.
|
|
||||||
- **Прозрачность**: минимум скрытой логики, всё явно через контекст.
|
|
||||||
- **Developer Experience**: удобные API, автоматическая регистрация, документация через `///summary`.
|
|
||||||
|
|
||||||
## 📌 Итог
|
|
||||||
BotPages позволяет писать чистые, расширяемые и удобные для команды боты:
|
|
||||||
- минимум boilerplate,
|
|
||||||
- декларативные интерфейсы,
|
|
||||||
- прозрачная навигация,
|
|
||||||
- автоматическое управление состоянием.
|
|
||||||
30
docfx.json
Normal file
30
docfx.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"src": [
|
||||||
|
{ "files": ["BotPages.Core/BotPages.Core.csproj"] },
|
||||||
|
{ "files": ["BotPages.Telegram/BotPages.Telegram.csproj"] },
|
||||||
|
{ "files": ["BotPages/BotPages.csproj"] }
|
||||||
|
],
|
||||||
|
"dest": "api",
|
||||||
|
"properties": {
|
||||||
|
"TargetFramework": "net8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build": {
|
||||||
|
"content": [
|
||||||
|
{ "files": ["docs/**.md"] },
|
||||||
|
{ "files": ["README.md"] },
|
||||||
|
{ "files": ["api/**.yml"], "dest": "api" }
|
||||||
|
],
|
||||||
|
"resource": [
|
||||||
|
{ "files": ["docs/**.png", "docs/**.jpg", "docs/**.svg"] }
|
||||||
|
],
|
||||||
|
"dest": "_site",
|
||||||
|
"globalMetadata": {
|
||||||
|
"_enableSearch": true
|
||||||
|
},
|
||||||
|
"template": [ "default" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
57
docs/API_REFERENCE.md
Normal file
57
docs/API_REFERENCE.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# API Reference (краткий)
|
||||||
|
|
||||||
|
Документ перечисляет публичные API фреймворка и их назначение.
|
||||||
|
|
||||||
|
## BotPages.Core
|
||||||
|
|
||||||
|
### `BotPagesApp`
|
||||||
|
- `AddAdapter(string messengerType, IMessangerAdapterSetup adapter)` — зарегистрировать адаптер для мессенджера.
|
||||||
|
- `AddDefaultPage<TPage>() where TPage : SingletonPage` — установить "домашнюю" страницу приложения.
|
||||||
|
- `AddMiddleware<TMiddleware>(TMiddleware instance) where TMiddleware : IPageMiddleware` — добавить middleware в конвейер.
|
||||||
|
- `MapCommand<TPage>(string commandTemplate) where TPage : Page` — зарегистрировать команду, ведущую на страницу.
|
||||||
|
- `MapCommand(string template, CommandHandler handler)` — зарегистрировать кастомный обработчик команды.
|
||||||
|
- `MapRoute<TPage>(string template) where TPage : Page` — вручную зарегистрировать маршрут для страницы.
|
||||||
|
- `AutoMapRoute()` — автоматически найти и зарегистрировать все Page-типы в загруженных сборках.
|
||||||
|
- `HandleUpdateAsync(UpdateContext update, CancellationToken ct)` — главный обработчик апдейтов (вызвается адаптером).
|
||||||
|
- `Build(CancellationToken ct)` — запустить все адаптеры и начать обработку апдейтов.
|
||||||
|
|
||||||
|
### Страницы
|
||||||
|
- `Page` — абстрактный базовый класс.
|
||||||
|
- `StatefulPage` — страница с сохранением состояния.
|
||||||
|
- `SingletonPage` — одноэкземплярная страница.
|
||||||
|
|
||||||
|
### Навигация
|
||||||
|
- `NavigationService` — отвечает за определение текущей страницы и переходы.
|
||||||
|
- `GoToAsync<TPage>(PageContext ctx, CancellationToken ct)`
|
||||||
|
- `GoToHomeAsync(PageContext ctx, CancellationToken ct)`
|
||||||
|
|
||||||
|
### Команды
|
||||||
|
- `CommandsRegistry` — реестр команд (внутренний). Поддерживает шаблоны с именованными аргументами и опциональными параметрами.
|
||||||
|
|
||||||
|
### Middleware
|
||||||
|
- `IPageMiddleware` — интерфейс middleware.
|
||||||
|
- `InvokeAsync(PageContext ctx, Func<Task> next, CancellationToken ct)`
|
||||||
|
|
||||||
|
### Абстракции адаптеров
|
||||||
|
- `IMessangerAdapterSetup` — настройка адаптера.
|
||||||
|
- `IMessengerAdapter` — экземпляр адаптера, реализующий `StartAdapterAsync(Func<UpdateContext, Task> onUpdate, List<Command> commands, CancellationToken ct)`.
|
||||||
|
- `IMessengerAdapterFactory` — фабрика/реестр адаптеров (`MultiAdapterFactory` — реализация).
|
||||||
|
|
||||||
|
### Хранилище состояний
|
||||||
|
- `IStateStorage` — абстракция для сохранения состояния страниц между сессиями.
|
||||||
|
|
||||||
|
## BotPages.Telegram
|
||||||
|
- Реализация адаптера для Telegram на базе `Telegram.Bot`.
|
||||||
|
- `TelegramUpdateMapper` — маппит апдейты Telegram в `UpdateContext`.
|
||||||
|
- `TelegramAlbumBuilder` — собирает медиа-альбомы из последовательных апдейтов.
|
||||||
|
- `TelegramAdapter` — реализация адаптера, стартует `StartAdapterAsync`.
|
||||||
|
|
||||||
|
|
||||||
|
# Генерация документации
|
||||||
|
|
||||||
|
Рекомендуется использовать `docfx` или `Doxygen` для генерации HTML-документации из XML-файлов, которые генерируются при сборке (см. `GenerateDocumentationFile` в `.csproj`).
|
||||||
|
|
||||||
|
|
||||||
|
# Примечания
|
||||||
|
|
||||||
|
Этот документ — краткое описание API. Для полного списка публичных типов и методов можно сгенерировать reference из XML-вывода компиляции.
|
||||||
19
docs/CONTRIBUTING.md
Normal file
19
docs/CONTRIBUTING.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Contributing to BotPages
|
||||||
|
|
||||||
|
Спасибо за интерес к проекту! Пожалуйста, перед отправкой PR убедитесь, что:
|
||||||
|
|
||||||
|
- Ваш код проходит сборку: `dotnet build`.
|
||||||
|
- Добавлены/обновлены тесты, если уместно.
|
||||||
|
- Следуется стиль кода проекта и включены nullable-аннотации.
|
||||||
|
|
||||||
|
Документация генерируется через `docfx`. См. `docfx.json` в корне репозитория и скрипты в `scripts/`.
|
||||||
|
|
||||||
|
Пример локальной генерации документации:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Unix
|
||||||
|
./scripts/generate-docs.sh
|
||||||
|
|
||||||
|
# Windows PowerShell
|
||||||
|
./scripts/generate-docs.ps1
|
||||||
|
```
|
||||||
47
docs/GETTING_STARTED.md
Normal file
47
docs/GETTING_STARTED.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Быстрый старт — BotPages
|
||||||
|
|
||||||
|
Эта инструкция поможет запустить и протестировать проект локально.
|
||||||
|
|
||||||
|
Требования
|
||||||
|
- .NET 8 SDK
|
||||||
|
- Токен Telegram (если используете Telegram-адаптер)
|
||||||
|
|
||||||
|
Сборка
|
||||||
|
```bash
|
||||||
|
dotnet build
|
||||||
|
```
|
||||||
|
|
||||||
|
Запуск демонстрации
|
||||||
|
1. Откройте проект `Demo`.
|
||||||
|
2. Внесите токен Telegram (если используется) в код инициализации адаптера или в переменные окружения проекта Demo.
|
||||||
|
3. Запустите:
|
||||||
|
```bash
|
||||||
|
dotnet run --project Demo
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример конфигурации приложения
|
||||||
|
```csharp
|
||||||
|
var app = new BotPagesApp(stateStorage, logger)
|
||||||
|
.AddAdapter("telegram", new TelegramAdapterSetup("<token>"))
|
||||||
|
.AddDefaultPage<WelcomePage>()
|
||||||
|
.MapCommand<WelcomePage>("/start")
|
||||||
|
.AddMiddleware(new LoggingMiddleware(logger));
|
||||||
|
|
||||||
|
await app.Build(CancellationToken.None);
|
||||||
|
```
|
||||||
|
|
||||||
|
Как написать страницу
|
||||||
|
- Наследуйте `StatefulPage` для страниц с пер-сессионным состоянием.
|
||||||
|
- Наследуйте `SingletonPage` для одноэкземплярных страниц.
|
||||||
|
- Переопределите `OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError` по необходимости.
|
||||||
|
- Для автоматического маппинга маршрутов используйте `AutoMapRoute()`.
|
||||||
|
|
||||||
|
Тестирование команд
|
||||||
|
- Команды регистрируются в `BotPagesApp.MapCommand`.
|
||||||
|
- Шаблон команд поддерживает именованные и опциональные аргументы: `/cmd {a} {b?}`.
|
||||||
|
|
||||||
|
Подсказки
|
||||||
|
- Middleware выполняются в том порядке, в котором их добавляют в `BotPagesApp`.
|
||||||
|
- Команды имеют приоритет над обработкой страниц (если текст начинается с `/`).
|
||||||
|
|
||||||
|
Если требуется подробный справочник API — смотрите `docs/API_REFERENCE.md`.
|
||||||
114
docs/PROJECT_DOCUMENTATION.md
Normal file
114
docs/PROJECT_DOCUMENTATION.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# Документация проекта BotPages
|
||||||
|
|
||||||
|
Краткая документация по всему проекту. Описывает архитектуру, основные компоненты, сценарии использования и сборки.
|
||||||
|
|
||||||
|
## Структура репозитория
|
||||||
|
|
||||||
|
- `BotPages.Core` — ядро фреймворка.
|
||||||
|
- Навигация: `NavigationService`, страницы: `Page`, `StatefulPage`, `SingletonPage`.
|
||||||
|
- Маршрутизация: `RoutesRegistry` (авторегистрация через `AutoMapRoute`).
|
||||||
|
- Команды: `CommandsRegistry` (парсер шаблонов команд, `TryDispatch`).
|
||||||
|
- Middleware: интерфейс `IPageMiddleware` и реализация `LoggingMiddleware`.
|
||||||
|
- Абстракции адаптеров/адаптер-фабрика: `IMessangerAdapterSetup`, `IMessengerAdapterFactory` (например `MultiAdapterFactory`).
|
||||||
|
- Хранилище состояния: `IStateStorage`.
|
||||||
|
|
||||||
|
- `BotPages.Telegram` — реализация адаптера для Telegram (использует `Telegram.Bot`).
|
||||||
|
|
||||||
|
- `Demo` — демонстрационное приложение с примерами страниц и конфигурации.
|
||||||
|
|
||||||
|
- `BotPages` — мета-проект/пакет для упаковки.
|
||||||
|
|
||||||
|
## Главные сущности и сценарии использования
|
||||||
|
|
||||||
|
- `BotPagesApp` — точка конфигурации и запуска приложения.
|
||||||
|
- Регистрация адаптеров: `AddAdapter(string messengerType, IMessangerAdapterSetup adapter)`.
|
||||||
|
- Регистрация middleware: `AddMiddleware<T>(T instance)`.
|
||||||
|
- Регистрация команд: `MapCommand<TPage>(string template)` или `MapCommand(string template, CommandHandler handler)`.
|
||||||
|
- Маршруты: `MapRoute<TPage>(string template)` и `AutoMapRoute()` для автоматического поиска страниц по рефлексии.
|
||||||
|
- Запуск: `Build(CancellationToken)` — старт адаптеров и приём апдейтов.
|
||||||
|
|
||||||
|
- Страницы:
|
||||||
|
- `Page` — базовый класс (абстрактный) с жизненным циклом (`OnEnter`, `OnUpdate`, `OnText`, `OnButton`, `OnFile`, `OnError`).
|
||||||
|
- `StatefulPage` — хранит состояние в `IStateStorage` (сериализация полей, атрибуты для stateful-полей).
|
||||||
|
- `SingletonPage` — один экземпляр на приложение, без per-session состояния.
|
||||||
|
|
||||||
|
- Навигация: `NavigationService` управляет текущей страницей пользователя (определяется по `PageContext.SessionKey`) и предоставляет методы `GoToAsync<TPage>`, `GoToHomeAsync`.
|
||||||
|
|
||||||
|
- Команды: шаблоны вида `/cmd {arg} {opt?}`. Парсер в `CommandsRegistry.ToRegex` поддерживает именованные группы и опциональные аргументы. При совпадении вызывается `CommandHandler(PageContext, IDictionary<string,string>, CancellationToken)`.
|
||||||
|
|
||||||
|
- Middleware: реализуют `IPageMiddleware.InvokeAsync(PageContext, Func<Task> next, CancellationToken ct)`; вызываются в порядке регистрации (конвейер).
|
||||||
|
|
||||||
|
## Формат и схема апдейта
|
||||||
|
|
||||||
|
- `UpdateContext` содержит данные апдейта: `MessengerType`, `Chat`, `User`, `Kind` (флаги `Text`, `Button`, `File`), `Text`, `Files`.
|
||||||
|
- При поступлении апдейта `BotPagesApp.HandleUpdateAsync` создаёт `PageContext` и:
|
||||||
|
1. Проверяет команды (если текст и начинается с `/`) — команды имеют приоритет.
|
||||||
|
2. Запускает pipeline middleware.
|
||||||
|
3. Передаёт управление текущей странице через `DispatchToPageAsync`.
|
||||||
|
|
||||||
|
## Расширение и адаптеры
|
||||||
|
|
||||||
|
- Чтобы добавить новый мессенджер, реализуйте `IMessangerAdapterSetup`/`IMessengerAdapter` и зарегистрируйте через `BotPagesApp.AddAdapter`.
|
||||||
|
- `MultiAdapterFactory` служит для хранения и разрешения адаптеров по ключу `messengerType`.
|
||||||
|
|
||||||
|
## Сборка и запуск
|
||||||
|
|
||||||
|
Требования:
|
||||||
|
- .NET 8 SDK
|
||||||
|
|
||||||
|
Сборка проекта:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet build
|
||||||
|
```
|
||||||
|
|
||||||
|
Запуск демонстрации:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dotnet run --project Demo
|
||||||
|
```
|
||||||
|
|
||||||
|
Для Telegram-адаптера настройте токен и параметры в `Demo` (или в коде инициализации адаптера).
|
||||||
|
|
||||||
|
## Документы API и комментарии
|
||||||
|
|
||||||
|
XML-документация генерируется флагом `GenerateDocumentationFile` в `.csproj` для проектов. Для автогенерации документации используйте стандартные инструменты (например, `docfx`, `doxygen` или `MkDocs` с генерацией из XML).
|
||||||
|
|
||||||
|
## Примеры
|
||||||
|
|
||||||
|
- Пример регистрации кусочка конфигурации:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var app = new BotPagesApp(stateStorage, logger)
|
||||||
|
.AddAdapter("telegram", new TelegramAdapterSetup(token))
|
||||||
|
.AddMiddleware(new LoggingMiddleware(logger))
|
||||||
|
.MapCommand<WelcomePage>("/start")
|
||||||
|
.AddDefaultPage<WelcomePage>();
|
||||||
|
|
||||||
|
await app.Build(CancellationToken.None);
|
||||||
|
```
|
||||||
|
|
||||||
|
- Пример простой страницы:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public sealed class WelcomePage : StatefulPage
|
||||||
|
{
|
||||||
|
public override async Task OnEnter(PageContext ctx, CancellationToken ct)
|
||||||
|
{
|
||||||
|
await ctx.SendTextAsync("Добро пожаловать", ct: ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Вклад и тестирование
|
||||||
|
|
||||||
|
- Направляйте PR в репозиторий. Описывайте изменения в заголовке и теле PR.
|
||||||
|
- Поддерживайте единый стиль кода и null-safe практики (`Nullable` включён).
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
Проект распространяется под лицензией MIT (см. `.csproj` и `LICENSE`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Это краткий обзор. При необходимости можно сгенерировать подробный Reference по API (список публичных типов и методов) в отдельный документ.
|
||||||
2
docs/docfx_project/docfx.css
Normal file
2
docs/docfx_project/docfx.css
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/* Minimal styling overrides for docfx output */
|
||||||
|
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif; }
|
||||||
7
docs/docfx_project/docfx.js
Normal file
7
docs/docfx_project/docfx.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
"templates": {
|
||||||
|
"global": {
|
||||||
|
"favicon": "favicon.ico"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
22
scripts/generate-docs.ps1
Normal file
22
scripts/generate-docs.ps1
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Param(
|
||||||
|
[string]$DocfxPath = "docfx",
|
||||||
|
[string]$WorkingDir = "$(Resolve-Path .)"
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
Write-Host "Generating docfx documentation..."
|
||||||
|
|
||||||
|
if (-not (Get-Command $DocfxPath -ErrorAction SilentlyContinue)) {
|
||||||
|
Write-Host "Docfx not found on PATH. Install docfx or provide full path to docfx.exe" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location $WorkingDir
|
||||||
|
try {
|
||||||
|
& $DocfxPath metadata docfx.json
|
||||||
|
& $DocfxPath build docfx.json
|
||||||
|
Write-Host "Docfx build complete. Output in _site folder" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Pop-Location
|
||||||
|
}
|
||||||
14
scripts/generate-docs.sh
Normal file
14
scripts/generate-docs.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
DOCFX_PATH=${DOCFX_PATH:-docfx}
|
||||||
|
WORKING_DIR=$(pwd)
|
||||||
|
|
||||||
|
if ! command -v "$DOCFX_PATH" >/dev/null 2>&1; then
|
||||||
|
echo "docfx not found. Install it or set DOCFX_PATH to the executable path."
|
||||||
|
fi
|
||||||
|
|
||||||
|
pushd "$WORKING_DIR" > /dev/null
|
||||||
|
$DOCFX_PATH metadata docfx.json
|
||||||
|
$DOCFX_PATH build docfx.json
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
echo "Docfx build complete. Output in _site folder"
|
||||||
Reference in New Issue
Block a user