Files
gateway-telegram/internal/application/usecase/handle_text_message.go

116 lines
3.1 KiB
Go

package usecase
import (
"context"
"fmt"
"log/slog"
"time"
"github.com/google/uuid"
"github.com/paramah/gw_telegram/internal/application/dto"
"github.com/paramah/gw_telegram/internal/domain/apperror"
"github.com/paramah/gw_telegram/internal/domain/entity"
"github.com/paramah/gw_telegram/internal/domain/port"
)
type HandleTextMessage struct {
router port.IntentRouter
dispatcher port.WorkflowDispatcher
sessions port.SessionStore
gateway port.MessageGateway
logger *slog.Logger
}
func NewHandleTextMessage(
router port.IntentRouter,
dispatcher port.WorkflowDispatcher,
sessions port.SessionStore,
gateway port.MessageGateway,
logger *slog.Logger,
) *HandleTextMessage {
return &HandleTextMessage{
router: router,
dispatcher: dispatcher,
sessions: sessions,
gateway: gateway,
logger: logger,
}
}
func (h *HandleTextMessage) Execute(ctx context.Context, in dto.IncomingMessageDTO) error {
if in.Text == "" {
return apperror.ErrMessageEmpty
}
msg := entity.Message{
MessageID: in.MessageID,
ChatID: in.ChatID,
UserID: in.UserID,
Username: in.Username,
Type: entity.MessageTypeText,
Text: in.Text,
Timestamp: in.Timestamp,
Metadata: map[string]any{"language": in.Language},
}
session, err := h.sessions.Get(ctx, in.UserID)
if err != nil {
h.logger.WarnContext(ctx, "session not found, using empty session", "user_id", in.UserID)
session = entity.Session{
UserID: in.UserID,
ChatID: in.ChatID,
Data: make(map[string]any),
UpdatedAt: time.Now(),
}
}
route, err := h.router.Route(ctx, msg)
if err != nil {
h.logger.ErrorContext(ctx, "routing failed", "error", err, "user_id", in.UserID)
_ = h.gateway.SendText(ctx, in.ChatID, "Sorry, I couldn't process your message. Please try again.")
return fmt.Errorf("handle text message: route: %w", err)
}
session.History = append(session.History, msg)
if len(session.History) > 20 {
session.History = session.History[len(session.History)-20:]
}
req := entity.WorkflowRequest{
RequestID: uuid.New().String(),
ChatID: in.ChatID,
UserID: in.UserID,
Username: in.Username,
MessageText: in.Text,
Intent: entity.Intent{
Name: route.IntentName,
},
Session: session,
Timestamp: in.Timestamp,
Metadata: map[string]any{"route_target_type": string(route.Target.Type)},
}
_ = h.gateway.SendTyping(ctx, in.ChatID)
resp, err := h.dispatcher.Dispatch(ctx, req)
if err != nil {
h.logger.ErrorContext(ctx, "dispatch failed", "error", err, "request_id", req.RequestID)
_ = h.gateway.SendText(ctx, in.ChatID, "Sorry, the service is temporarily unavailable. Please try again later.")
return fmt.Errorf("handle text message: dispatch: %w", err)
}
if resp.ReplyText != "" {
if err := h.gateway.SendText(ctx, in.ChatID, resp.ReplyText); err != nil {
return fmt.Errorf("handle text message: send reply: %w", err)
}
}
session.CurrentWorkflow = route.Target.WorkflowID
session.UpdatedAt = time.Now()
if err := h.sessions.Set(ctx, session); err != nil {
h.logger.WarnContext(ctx, "failed to persist session", "error", err, "user_id", in.UserID)
}
return nil
}