diff --git a/cmd/anon3anon/main.go b/cmd/anon3anon/main.go index 086f190..4911ef3 100644 --- a/cmd/anon3anon/main.go +++ b/cmd/anon3anon/main.go @@ -1,38 +1,70 @@ package main import ( + "context" "log" + "os" + "os/signal" - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "github.com/nightnoryu/anon3anon/pkg/app" - "github.com/nightnoryu/anon3anon/pkg/infrastructure" + "github.com/go-telegram/bot" + "github.com/go-telegram/bot/models" ) func main() { + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + conf, err := parseEnv() if err != nil { log.Fatal(err) } - bot, err := tgbotapi.NewBotAPI(conf.TelegramBotToken) - if err != nil { - log.Panic(err) + opts := []bot.Option{ + bot.WithDebug(), + bot.WithMessageTextHandler("/start", bot.MatchTypeExact, getStartHandler()), + bot.WithDefaultHandler(getDefaultHandler(conf)), } - log.Printf("Authorized on account %s", bot.Self.UserName) - errorsChan := make(chan error) - botAPI := infrastructure.NewBotAPI(bot, conf.OwnerChatID) - - commandHandler := app.NewCommandHandler(botAPI) - - service := app.NewAnonymousQuestionsService(errorsChan, commandHandler, botAPI) - go func() { - for err := range errorsChan { - log.Println(err) - } - }() - - if err = service.ServeMessages(); err != nil { + b, err := bot.New(conf.TelegramBotToken, opts...) + if err != nil { log.Fatal(err) } + + b.Start(ctx) +} + +func getStartHandler() bot.HandlerFunc { + return func(ctx context.Context, b *bot.Bot, update *models.Update) { + params := &bot.SendMessageParams{ + ChatID: update.Message.Chat.ID, + Text: "Жду твоих сообщений!!\nОтветы будут в канале @meme_me_a_meme", + } + _, err := b.SendMessage(ctx, params) + if err != nil { + log.Print(err) + } + } +} + +func getDefaultHandler(conf *config) bot.HandlerFunc { + return func(ctx context.Context, b *bot.Bot, update *models.Update) { + params := &bot.CopyMessageParams{ + ChatID: conf.OwnerChatID, + FromChatID: update.Message.Chat.ID, + MessageID: update.Message.ID, + } + _, err := b.CopyMessage(ctx, params) + if err != nil { + log.Print(err) + } + + sendParams := &bot.SendMessageParams{ + ChatID: update.Message.Chat.ID, + Text: "Сообщение отправлено!", + } + _, err = b.SendMessage(ctx, sendParams) + if err != nil { + log.Print(err) + } + } } diff --git a/go.mod b/go.mod index 30b6274..06fd6a5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,8 @@ module github.com/nightnoryu/anon3anon go 1.22.5 require ( - github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/kelseyhightower/envconfig v1.4.0 github.com/pkg/errors v0.9.1 ) + +require github.com/go-telegram/bot v1.13.3 diff --git a/go.sum b/go.sum index 60abbdf..67a7c24 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc= -github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8= +github.com/go-telegram/bot v1.13.3 h1:r2erpHI5rMQsR5TFWJ/XVqWHq9R228fcaejLFvXJsmM= +github.com/go-telegram/bot v1.13.3/go.mod h1:i2TRs7fXWIeaceF3z7KzsMt/he0TwkVC680mvdTFYeM= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= diff --git a/pkg/app/anonymousmessagesservice.go b/pkg/app/anonymousmessagesservice.go deleted file mode 100644 index f841c2f..0000000 --- a/pkg/app/anonymousmessagesservice.go +++ /dev/null @@ -1,73 +0,0 @@ -package app - -func NewAnonymousQuestionsService( - errorsChan chan error, - commandHandler CommandHandler, - api BotAPI, -) AnonymousMessagesService { - return &anonymousMessagesService{ - errorsChan: errorsChan, - commandHandler: commandHandler, - api: api, - } -} - -const ( - messageSentReply = "*Сообщение отправлено!*" - unsupportedMessageReply = "*Такое сообщение не поддерживается :(*" - - newMessageNotification = "Новое анонимное сообщение!" -) - -type AnonymousMessagesService interface { - ServeMessages() error -} - -type anonymousMessagesService struct { - errorsChan chan error - commandHandler CommandHandler - api BotAPI -} - -func (s *anonymousMessagesService) ServeMessages() error { - return s.api.HandleUpdates(func(update MessageUpdate) { - if update.Command != nil { - err := s.commandHandler.HandleCommand(update) - if err != nil { - s.errorsChan <- err - } - return - } - - if update.Message.Sticker != nil { - err := s.api.SendMessage(update.FromChatID, Message{ - Text: unsupportedMessageReply, - UseMarkdown: true, - }) - if err != nil { - s.errorsChan <- err - } - return - } - - notificationText := newMessageNotification + "\n\n" + update.Message.Text - err := s.api.SendMessageToOwner(Message{ - Text: notificationText, - Image: update.Message.Image, - Audio: update.Message.Audio, - Video: update.Message.Video, - Voice: update.Message.Voice, - }) - if err != nil { - s.errorsChan <- err - } - - err = s.api.SendMessage(update.FromChatID, Message{ - Text: messageSentReply, - UseMarkdown: true, - }) - if err != nil { - s.errorsChan <- err - } - }) -} diff --git a/pkg/app/botapi.go b/pkg/app/botapi.go deleted file mode 100644 index 87474f5..0000000 --- a/pkg/app/botapi.go +++ /dev/null @@ -1,55 +0,0 @@ -package app - -type BotAPI interface { - HandleUpdates(handler MessageUpdateHandler) error - SendMessage(chatID int64, message Message) error - SendMessageToOwner(message Message) error -} - -type MessageUpdateHandler func(MessageUpdate) - -type MessageUpdate struct { - Message - UpdateID int - FromChatID int64 - Command *Command -} - -type Message struct { - Text string - UseMarkdown bool - Image *Image - Audio *Audio - Video *Video - Sticker *Sticker - Voice *Voice -} - -type Image struct { - FileID string -} - -type Audio struct { - FileID string -} - -type Video struct { - FileID string -} - -type Sticker struct { - FileID string - Emoji string -} - -type Voice struct { - FileID string -} - -type Command int - -const ( - UnknownCommand Command = iota - StartCommand - InfoCommand -) diff --git a/pkg/app/commandhandler.go b/pkg/app/commandhandler.go deleted file mode 100644 index 957bf52..0000000 --- a/pkg/app/commandhandler.go +++ /dev/null @@ -1,33 +0,0 @@ -package app - -func NewCommandHandler(api BotAPI) CommandHandler { - return &commandHandler{ - api: api, - } -} - -type CommandHandler interface { - HandleCommand(update MessageUpdate) error -} - -type commandHandler struct { - api BotAPI -} - -func (h *commandHandler) HandleCommand(update MessageUpdate) error { - if update.Command == nil { - return nil - } - - var msgText string - switch *update.Command { - case StartCommand: - msgText = "Жду твоих вопросов!!\nОтветы будут в канале @meme_me_a_meme (>ᴗ•)" - case InfoCommand: - msgText = "Бот привязан к каналу @meme_me_a_meme, так что ответы ищи там!!\nНа данный момент поддерживаются текст, фото и видео („• ᴗ •„)" - case UnknownCommand: - msgText = "Неизвестная команда!" - } - - return h.api.SendMessage(update.FromChatID, Message{Text: msgText}) -} diff --git a/pkg/infrastructure/botapi.go b/pkg/infrastructure/botapi.go deleted file mode 100644 index a44ca21..0000000 --- a/pkg/infrastructure/botapi.go +++ /dev/null @@ -1,258 +0,0 @@ -package infrastructure - -import ( - "log" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "github.com/pkg/errors" - - "github.com/nightnoryu/anon3anon/pkg/app" -) - -const ( - updateTimeoutInSeconds = 60 - - startCommand = "start" - infoCommand = "info" -) - -func NewBotAPI(bot *tgbotapi.BotAPI, ownerChatID int64) app.BotAPI { - return &botAPI{ - bot: bot, - ownerChatID: ownerChatID, - } -} - -type botAPI struct { - bot *tgbotapi.BotAPI - ownerChatID int64 -} - -func (api *botAPI) HandleUpdates(handler app.MessageUpdateHandler) error { - u := tgbotapi.NewUpdate(0) - u.Timeout = updateTimeoutInSeconds - - updates := api.bot.GetUpdatesChan(u) - for update := range updates { - if update.Message == nil { - continue - } - - log.Printf("%+v\n", update.Message) - - messageUpdate := app.MessageUpdate{ - Message: api.hydrateMessage(update.Message), - UpdateID: update.UpdateID, - FromChatID: update.FromChat().ID, - Command: api.hydrateCommand(update.Message), - } - - handler(messageUpdate) - } - - return nil -} - -func (api *botAPI) SendMessage(chatID int64, message app.Message) error { - if message.Image != nil { - return api.sendPhotoMessage(chatID, message) - } - - if message.Audio != nil { - return api.sendAudioMessage(chatID, message) - } - - if message.Video != nil { - return api.sendVideoMessage(chatID, message) - } - - if message.Voice != nil { - return api.sendVoiceMessage(chatID, message) - } - - return api.sendTextMessage(chatID, message) -} - -func (api *botAPI) SendMessageToOwner(message app.Message) error { - return api.SendMessage(api.ownerChatID, message) -} - -func (api *botAPI) hydrateMessage(msg *tgbotapi.Message) app.Message { - text := msg.Text - if len(text) == 0 { - text = msg.Caption - } - - return app.Message{ - Text: text, - Image: api.hydrateImage(msg.Photo), - Audio: api.hydrateAudio(msg.Audio), - Video: api.hydrateVideo(msg.Video), - Sticker: api.hydrateSticker(msg.Sticker), - Voice: api.hydrateVoice(msg.Voice), - } -} - -func (api *botAPI) sendTextMessage(chatID int64, message app.Message) error { - msg := tgbotapi.NewMessage( - chatID, - message.Text, - ) - - if message.UseMarkdown { - msg.ParseMode = tgbotapi.ModeMarkdown - } - - _, err := api.bot.Send(msg) - return errors.WithStack(err) -} - -func (api *botAPI) sendPhotoMessage(chatID int64, message app.Message) error { - photos := api.preparePhotos(message) - mediaMsg := tgbotapi.NewMediaGroup(chatID, photos) - - _, err := api.bot.Send(mediaMsg) - return errors.WithStack(err) -} - -func (api *botAPI) sendAudioMessage(chatID int64, message app.Message) error { - audios := api.prepareAudio(message) - mediaMsg := tgbotapi.NewMediaGroup(chatID, audios) - - _, err := api.bot.Send(mediaMsg) - return errors.WithStack(err) -} - -func (api *botAPI) sendVideoMessage(chatID int64, message app.Message) error { - video := api.prepareVideo(message) - mediaMsg := tgbotapi.NewMediaGroup(chatID, video) - - _, err := api.bot.Send(mediaMsg) - return errors.WithStack(err) -} - -func (api *botAPI) sendVoiceMessage(chatID int64, message app.Message) error { - voiceMsg := tgbotapi.NewVoice(chatID, tgbotapi.FileID(message.Voice.FileID)) - - voiceMsg.Caption = message.Text - if message.UseMarkdown { - voiceMsg.ParseMode = tgbotapi.ModeMarkdown - } - - _, err := api.bot.Send(voiceMsg) - return errors.WithStack(err) -} - -func (api *botAPI) hydrateCommand(msg *tgbotapi.Message) *app.Command { - if !msg.IsCommand() { - return nil - } - - var cmd app.Command - switch msg.Command() { - case startCommand: - cmd = app.StartCommand - case infoCommand: - cmd = app.InfoCommand - default: - cmd = app.UnknownCommand - } - - return &cmd -} - -func (api *botAPI) hydrateImage(photos []tgbotapi.PhotoSize) *app.Image { - if len(photos) == 0 { - return nil - } - - var originalFileID string - var originalFileSize int - for _, photo := range photos { - if photo.FileSize > originalFileSize { - originalFileID = photo.FileID - originalFileSize = photo.FileSize - } - } - - return &app.Image{ - FileID: originalFileID, - } -} - -func (api *botAPI) hydrateAudio(audio *tgbotapi.Audio) *app.Audio { - if audio == nil { - return nil - } - - return &app.Audio{ - FileID: audio.FileID, - } -} - -func (api *botAPI) hydrateVideo(video *tgbotapi.Video) *app.Video { - if video == nil { - return nil - } - - return &app.Video{ - FileID: video.FileID, - } -} - -func (api *botAPI) hydrateSticker(sticker *tgbotapi.Sticker) *app.Sticker { - if sticker == nil { - return nil - } - - return &app.Sticker{ - FileID: sticker.FileID, - Emoji: sticker.Emoji, - } -} - -func (api *botAPI) hydrateVoice(voice *tgbotapi.Voice) *app.Voice { - if voice == nil { - return nil - } - - return &app.Voice{ - FileID: voice.FileID, - } -} - -func (api *botAPI) preparePhotos(message app.Message) []interface{} { - photo := tgbotapi.NewInputMediaPhoto(tgbotapi.FileID(message.Image.FileID)) - photo.Caption = message.Text - - if message.UseMarkdown { - photo.ParseMode = tgbotapi.ModeMarkdown - } - - var photos []interface{} - photos = append(photos, photo) - - return photos -} - -func (api *botAPI) prepareAudio(message app.Message) []interface{} { - audio := tgbotapi.NewInputMediaAudio(tgbotapi.FileID(message.Audio.FileID)) - audio.Caption = message.Text - - if message.UseMarkdown { - audio.ParseMode = tgbotapi.ModeMarkdown - } - - return []interface{}{audio} -} - -func (api *botAPI) prepareVideo(message app.Message) []interface{} { - video := tgbotapi.NewInputMediaVideo(tgbotapi.FileID(message.Video.FileID)) - video.Caption = message.Text - - if message.UseMarkdown { - video.ParseMode = tgbotapi.ModeMarkdown - } - - return []interface{}{video} -}