feat: initial commit
This commit is contained in:
115
internal/application/usecase/handle_text_message.go
Normal file
115
internal/application/usecase/handle_text_message.go
Normal file
@@ -0,0 +1,115 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user