bbgo_origin/pkg/interact/telegram.go

223 lines
5.1 KiB
Go
Raw Normal View History

2022-01-13 14:15:05 +00:00
package interact
import (
2022-01-13 17:58:04 +00:00
"context"
2022-01-13 14:15:05 +00:00
"fmt"
2022-01-13 18:57:39 +00:00
"strings"
"time"
2022-01-13 14:15:05 +00:00
log "github.com/sirupsen/logrus"
"gopkg.in/tucnak/telebot.v2"
)
2022-01-15 16:39:24 +00:00
type TelegramSessionMap map[int64]*TelegramSession
type TelegramSession struct {
BaseSession
telegram *Telegram
User *telebot.User `json:"user"`
Chat *telebot.Chat `json:"chat"`
}
func (s *TelegramSession) ID() string {
return fmt.Sprintf("telegram-%d-%d", s.User.ID, s.Chat.ID)
}
2022-01-15 16:39:24 +00:00
func (s *TelegramSession) SetAuthorized() {
s.BaseSession.SetAuthorized()
s.telegram.EmitAuthorized(s)
}
func NewTelegramSession(telegram *Telegram, message *telebot.Message) *TelegramSession {
return &TelegramSession{
BaseSession: BaseSession{
OriginState: StatePublic,
CurrentState: StatePublic,
Authorized: false,
authorizing: false,
StartedTime: time.Now(),
},
telegram: telegram,
User: message.Sender,
Chat: message.Chat,
}
}
2022-01-13 14:15:05 +00:00
type TelegramReply struct {
bot *telebot.Bot
session *TelegramSession
2022-01-14 18:52:46 +00:00
2022-01-13 14:15:05 +00:00
message string
menu *telebot.ReplyMarkup
buttons [][]telebot.Btn
2022-01-13 18:57:39 +00:00
set bool
2022-01-13 14:15:05 +00:00
}
2022-01-14 18:52:46 +00:00
func (r *TelegramReply) Send(message string) {
checkSendErr(r.bot.Send(r.session.Chat, message))
2022-01-14 18:52:46 +00:00
}
2022-01-13 14:15:05 +00:00
func (r *TelegramReply) Message(message string) {
r.message = message
r.set = true
2022-01-13 14:15:05 +00:00
}
func (r *TelegramReply) RemoveKeyboard() {
r.menu.ReplyKeyboardRemove = true
r.set = true
2022-01-13 14:15:05 +00:00
}
func (r *TelegramReply) AddButton(text string) {
var button = r.menu.Text(text)
if len(r.buttons) == 0 {
r.buttons = append(r.buttons, []telebot.Btn{})
}
r.buttons[len(r.buttons)-1] = append(r.buttons[len(r.buttons)-1], button)
r.set = true
2022-01-13 14:15:05 +00:00
}
func (r *TelegramReply) build() {
var rows []telebot.Row
for _, buttons := range r.buttons {
rows = append(rows, telebot.Row(buttons))
}
r.menu.Reply(rows...)
}
//go:generate callbackgen -type Telegram
2022-01-13 14:15:05 +00:00
type Telegram struct {
2022-01-13 17:58:04 +00:00
Bot *telebot.Bot `json:"-"`
// Private is used to protect the telegram bot, users not authenticated can not see messages or sending commands
Private bool `json:"private,omitempty"`
authorizing bool
2022-01-15 16:39:24 +00:00
sessions map[int64]*TelegramSession
2022-01-13 14:15:05 +00:00
2022-01-13 14:24:51 +00:00
// textMessageResponder is used for interact to register its message handler
textMessageResponder Responder
2022-01-13 18:57:39 +00:00
commands []*Command
authorizedCallbacks []func(s *TelegramSession)
2022-01-13 17:58:04 +00:00
}
func (tm *Telegram) SetTextMessageResponder(textMessageResponder Responder) {
tm.textMessageResponder = textMessageResponder
2022-01-13 14:15:05 +00:00
}
2022-01-13 17:58:04 +00:00
func (tm *Telegram) Start(context.Context) {
tm.Bot.Handle(telebot.OnText, func(m *telebot.Message) {
log.Infof("[telegram] onText: %+v", m)
session := tm.loadSession(m)
if tm.Private {
if !session.authorizing && !session.Authorized {
log.Warn("[telegram] telegram is set to private mode, skipping message")
return
}
}
2022-01-13 14:15:05 +00:00
reply := tm.newReply(session)
2022-01-13 17:58:04 +00:00
if tm.textMessageResponder != nil {
if err := tm.textMessageResponder(session, m.Text, reply); err != nil {
log.WithError(err).Errorf("[telegram] response handling error")
2022-01-13 14:24:51 +00:00
}
2022-01-13 14:15:05 +00:00
}
if reply.set {
reply.build()
2022-01-15 16:39:24 +00:00
checkSendErr(tm.Bot.Send(m.Chat, reply.message, reply.menu))
2022-01-13 14:15:05 +00:00
}
})
2022-01-13 18:57:39 +00:00
var cmdList []telebot.Command
for _, cmd := range tm.commands {
if len(cmd.Desc) == 0 {
continue
}
cmdList = append(cmdList, telebot.Command{
Text: strings.ToLower(strings.TrimLeft(cmd.Name, "/")),
Description: cmd.Desc,
})
}
if err := tm.Bot.SetCommands(cmdList); err != nil {
log.WithError(err).Errorf("[telegram] set commands error")
}
2022-01-13 17:58:04 +00:00
go tm.Bot.Start()
2022-01-13 14:15:05 +00:00
}
2022-01-14 18:52:46 +00:00
func checkSendErr(m *telebot.Message, err error) {
if err != nil {
log.WithError(err).Errorf("[telegram] message send error")
}
}
func (tm *Telegram) loadSession(m *telebot.Message) *TelegramSession {
if tm.sessions == nil {
2022-01-15 16:39:24 +00:00
tm.sessions = make(map[int64]*TelegramSession)
}
2022-01-15 16:39:24 +00:00
session, ok := tm.sessions[m.Chat.ID]
if ok {
return session
}
session = NewTelegramSession(tm, m)
2022-01-15 16:39:24 +00:00
tm.sessions[m.Chat.ID] = session
return session
}
2022-01-13 18:57:39 +00:00
func (tm *Telegram) AddCommand(cmd *Command, responder Responder) {
tm.commands = append(tm.commands, cmd)
tm.Bot.Handle(cmd.Name, func(m *telebot.Message) {
session := tm.loadSession(m)
reply := tm.newReply(session)
if err := responder(session, m.Payload, reply); err != nil {
log.WithError(err).Errorf("[telegram] responder error")
2022-01-15 16:39:24 +00:00
checkSendErr(tm.Bot.Send(m.Chat, fmt.Sprintf("error: %v", err)))
2022-01-13 14:15:05 +00:00
return
}
// build up the response objects
if reply.set {
reply.build()
2022-01-15 16:39:24 +00:00
checkSendErr(tm.Bot.Send(m.Chat, reply.message, reply.menu))
2022-01-13 14:15:05 +00:00
}
})
}
func (tm *Telegram) newReply(session *TelegramSession) *TelegramReply {
2022-01-13 14:15:05 +00:00
return &TelegramReply{
bot: tm.Bot,
session: session,
menu: &telebot.ReplyMarkup{ResizeReplyKeyboard: true},
2022-01-13 14:15:05 +00:00
}
}
func (tm *Telegram) Sessions() TelegramSessionMap {
return tm.sessions
}
func (tm *Telegram) RestoreSessions(sessions TelegramSessionMap) {
if len(sessions) == 0 {
return
}
log.Infof("[telegram] restoring telegram %d sessions", len(sessions))
tm.sessions = sessions
for _, session := range sessions {
if session.IsAuthorized() {
if _, err := tm.Bot.Send(session.Chat, fmt.Sprintf("Hi %s, I'm back. Your telegram session is restored.", session.User.Username)); err != nil {
log.WithError(err).Error("[telegram] can not send telegram message")
}
}
}
}