package message import ( "fmt" "log/slog" "regexp" "strconv" "strings" "sync" tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" "github.com/maximotejeda/us_dop_bot/internal/application/domain" "github.com/maximotejeda/us_dop_bot/internal/application/static" "github.com/maximotejeda/us_dop_bot/internal/ports" ) var ChatPool *sync.Pool type Message struct { bot *tgbotapi.BotAPI update *tgbotapi.Update msg *tgbotapi.MessageConfig log *slog.Logger dolar ports.DolarService user ports.UserService } // NewMessage // Factory for message handler func NewMessage(bot *tgbotapi.BotAPI, update *tgbotapi.Update, dolar ports.DolarService, user ports.UserService) *Message { if ChatPool == nil { ChatPool = &sync.Pool{ New: func() any { return &Message{} }, } for i := 0; i < 20; i++ { ChatPool.Put(ChatPool.New()) } } log := slog.Default() log = log.With("function", "message", "chat", update.Message.Chat.ID, "userid", update.Message.From.ID, "username", update.Message.From.UserName) message := ChatPool.Get().(*Message) message.update = update message.bot = bot message.log = log message.dolar = dolar message.user = user return message } // Empty // Returns pointer to pool func (m *Message) Empty() { m.update = nil m.msg = nil m.log = nil m.dolar = nil m.user = nil ChatPool.Put(m) } // Send // Process message sending to bot func (m *Message) Send() { defer m.Empty() m.bot.Send(m.msg) } // Handler // Manage features for messages func (m *Message) Handler() { msg := tgbotapi.NewMessage(m.update.Message.Chat.ID, "") m.msg = &msg msgtext := static.RemoveAccent(m.update.Message.Text) re := regexp.MustCompile(`(?P([cC]omprar?\s?(me)?|[vV]en(de)?(r)?(ta)?\s?(me)?))\s(?P[0-9.]{1,8})\s(?P(dolar(e)?(s)?|peso(s)?|dollars?))\s?(?P(.*))?`) match := re.FindStringSubmatch(msgtext) if len(match) != 0 { operacion := match[1] operacion = strings.ToLower(operacion) cantidadStr := match[8] cantidad, err := strconv.ParseFloat(cantidadStr, 64) if err != nil { m.log.Error("converting to float cantidad", "error", err) m.msg.Text = "cantidad no reconocidad " + cantidadStr m.Send() return } moneda := match[9] moneda = strings.ToLower(moneda) institucion := match[14] institucion = strings.ToLower(institucion) switch { case strings.Contains(operacion, "compra"): txt := m.Compra(cantidad, moneda, institucion) m.msg.Text = txt case strings.Contains(operacion, "vend"): txt := m.Venta(cantidad, moneda, institucion) m.msg.Text = txt default: m.msg.Text = "operacion no reconocida" } m.Send() } } func (m *Message) Compra(cantidad float64, moneda, institucion string) string { txt := "" inst := static.NewInstList() list := []*domain.History{} if institucion == "" { brd, bp, bhd, bcd := m.getPrincipalBank() list = []*domain.History{brd, bp, bhd, bcd} } else { txtList := inst.GetName(institucion) if len(txtList) <= 0 { txt = "no institution with name " + institucion return txt } else { for _, v := range txtList { i, err := m.dolar.GetLatest(v.Name) if err != nil { m.log.Error("getting latest", "inst", v, "error", err) continue } list = append(list, i) } } } if strings.Contains(moneda, "peso") { txt = fmt.Sprintf("Comprando dolares \nRD.$ %.2f pesos:\n", cantidad) for _, it := range list { compra := cantidad / it.Venta txt = txt + fmt.Sprintf(" %s \t->\t USD$. %.2f\n", inst.GetAbbrev(it.Institution.Name), compra) } } else if strings.Contains(moneda, "dol") { txt = fmt.Sprintf("Comprando %.2f dolares:\n", cantidad) for _, it := range list { compra := cantidad * it.Venta txt = txt + fmt.Sprintf(" %s \t->\t RD$. %.2f\n", inst.GetAbbrev(it.Institution.Name), compra) } } return txt } func (m *Message) Venta(cantidad float64, moneda, institucion string) string { txt := "" list := []*domain.History{} inst := static.NewInstList() if institucion == "" { brd, bp, bhd, bcd := m.getPrincipalBank() list = []*domain.History{brd, bp, bhd, bcd} } else { txtList := inst.GetName(institucion) if len(txtList) <= 0 { txt = "no institution with name " + institucion return txt } else { for _, v := range txtList { i, err := m.dolar.GetLatest(v.Name) if err != nil { m.log.Error("getting latest", "inst", v, "error", err) continue } list = append(list, i) } } } if len(list) <= 0 { return "no institutions found with name " + institucion } if strings.Contains(moneda, "peso") { txt = fmt.Sprintf("Vendiendo equivalente a RD.$ %.2f pesos:\n", cantidad) for _, it := range list { venta := cantidad / it.Compra txt = txt + fmt.Sprintf(" %s \t->\t USD$. %.2f\n", inst.GetAbbrev(it.Institution.Name), venta) } } else if strings.Contains(moneda, "dol") { txt = fmt.Sprintf("Vendiendo USD.$ %.2f dolares\n", cantidad) for _, it := range list { venta := cantidad * it.Compra txt = txt + fmt.Sprintf(" %s \t->\t RD$. %.2f\n", inst.GetAbbrev(it.Institution.Name), venta) } } return txt } func (m *Message) getPrincipalBank() (brd, bp, bhd, bcd *domain.History) { // principales bancos // bhd reservas popular central brd, err := m.dolar.GetLatest("banreservas") if err != nil { m.log.Error("query latest for banreservas", "error", err) } bp, err = m.dolar.GetLatest("banco popular") if err != nil { m.log.Error("query latest for banco popular") } bhd, err = m.dolar.GetLatest("banco hipotecario dominicano") if err != nil { m.log.Error("query latest for banreservas") } bcd, err = m.dolar.GetLatest("banco central dominicano") if err != nil { m.log.Error("query latest for banreservas") } return brd, bp, bhd, bcd }