internal/chat: мультиканальный Router (UserID-сессии, routing, pending Ask/ответ) + Channel интерфейс
All checks were successful
build-test / build (push) Successful in 41s
All checks were successful
build-test / build (push) Successful in 41s
This commit is contained in:
70
internal/chat/types.go
Normal file
70
internal/chat/types.go
Normal file
@@ -0,0 +1,70 @@
|
||||
// Package chat — мультиканальное общение с пользователем.
|
||||
//
|
||||
// Единый Router поверх любых Channel (Telegram / TUI / GUI...). Сессии
|
||||
// ключуются по UserID («кто»), доставка — по Address («где»), а pull/push
|
||||
// разница (polling/scan/подписка) скрыта внутри каждого Channel.
|
||||
//
|
||||
// Примитивы обмена: Send (уведомить), Ask (спросить, асинхронно),
|
||||
// + входящие события через OnMessage. Ask привязан к адресу вопроса.
|
||||
package chat
|
||||
|
||||
import "context"
|
||||
|
||||
// Address — «где» пользователь: конкретный канал+адрес (tg://123, tui://local).
|
||||
type Address string
|
||||
|
||||
// UserID — «кто» владелец сессии (один на человека, канал неважен).
|
||||
type UserID string
|
||||
|
||||
// Option — выбор (кнопка в TG, пронумерованный пункт в TUI).
|
||||
type Option struct {
|
||||
ID string
|
||||
Label string
|
||||
}
|
||||
|
||||
// Message — один исходящий/входящий контент.
|
||||
type Message struct {
|
||||
Text string
|
||||
Options []Option // Confirm = Ask с да/нет; выбор = список
|
||||
QuestionID string // блок 4: идентификатор вопроса в каждом Message
|
||||
}
|
||||
|
||||
// Incoming — входящее событие, канал сам заполняет UserID/Address.
|
||||
type Incoming struct {
|
||||
UserID UserID
|
||||
Address Address
|
||||
Msg Message
|
||||
Channel Channel
|
||||
}
|
||||
|
||||
// Handler — единый вход всех каналов в Router.
|
||||
type Handler func(Incoming)
|
||||
|
||||
// Channel — любой канал связи. pull/push разница скрыта внутри Run.
|
||||
type Channel interface {
|
||||
// Run запускает цикл канала (polling/scan/подписка). Может вернуть
|
||||
// M5 ChannelFatal — тогда Router перезапустит канал.
|
||||
Run(ctx context.Context) error
|
||||
// OnMessage регистрирует единый обработчик входящих (Router).
|
||||
OnMessage(h Handler)
|
||||
// Send — fire-and-forget уведомление. M1 если нет адреса, M2 если не доставлено.
|
||||
Send(ctx context.Context, to Address, m Message) error
|
||||
// Ask — неблокирующий вопрос: регистрирует pending и возвращается сразу.
|
||||
// M3 если pending уже открыт. Ответ придёт через OnMessage с тем же QuestionID.
|
||||
Ask(ctx context.Context, to Address, prompt Message) error
|
||||
// Close закрывает канал.
|
||||
Close() error
|
||||
}
|
||||
|
||||
// PendingQ — незакрытый вопрос (блок 4: один на сессию).
|
||||
type PendingQ struct {
|
||||
UserID UserID
|
||||
AnswerAddr Address
|
||||
Msg Message
|
||||
}
|
||||
|
||||
// Route — куда доставить следующий ответ пользователю.
|
||||
type Route struct {
|
||||
Address Address
|
||||
Channel Channel
|
||||
}
|
||||
Reference in New Issue
Block a user