116 lines
3.1 KiB
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
|
|
}
|