func (x *opBot) Run(bot *tgbotapi.BotAPI) {
	bot.Debug = true
	log.Printf("Authorized on account %s", bot.Self.UserName)
	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60
	updates, _ := bot.GetUpdatesChan(u)
	for update := range updates {
		switch {
		case update.CallbackQuery != nil:
			x.handleCallbackQuery(bot, update)
		case update.Message != nil:
			promMessageCount.Inc()
			updateMessageStats(x.statsWriter, update, osProgramadoresGroup)
			x.notifications.manageNotifications(bot, update)
			captcha := userCaptcha(x, bot, update.Message.Chat.ID, update.Message.From.ID)
			if captcha != nil && update.Message.NewChatMembers == nil {
				text := update.Message.Text
				name := formatName(*update.Message.From)
				userid := update.Message.From.ID
				msgid := update.Message.MessageID
				log.Printf("Removing message %d from non-captcha validated user %s (id=%d), want captcha=%04.4d: %q", msgid, name, userid, captcha.code, text)
				deleteMessage(bot, update.Message.Chat.ID, msgid)
				if captchaResendRequest(text) {
					x.sendCaptcha(bot, update, *update.Message.From)
					continue
				}
				if matchCaptcha(*captcha, text) {
					promCaptchaValidatedCount.Inc()
					x.pendingCaptcha.del(userid)
					x.sendWelcome(bot, update, *update.Message.From)
				}
				continue
			}
			admin, err := isAdmin(bot, update.Message.Chat.ID, update.Message.From.ID)
			if err != nil {
				log.Printf("Unable to determine if user is an admin. Assuming not.")
			}
			if x.config.NewUserProbationTime.Hours() > 0 && !admin {
				x.processNewUsers(bot, update)
			}
			switch {
			case x.config.DeleteFwd && isForwarded(update.Message):
				bot.DeleteMessage(tgbotapi.DeleteMessageConfig{
					ChatID:    update.Message.Chat.ID,
					MessageID: update.Message.MessageID,
				})
				log.Printf("Removed forwarded message. ChatID: %v, MessageID: %v", update.Message.Chat.ID, update.Message.MessageID)
			case update.Message.Location != nil:
				x.processLocationRequest(bot, update)
			case update.Message.NewChatMembers != nil:
				for _, newUser := range *update.Message.NewChatMembers {
					promJoinCount.Inc()
					log.Printf("Processing new user request for user %q, uid=%d\n", formatName(newUser), newUser.ID)
					if newUser.IsBot {
						x.banNewBots(bot, update, newUser)
					}
					log.Printf("Captcha time is %d, captcha enabled = %v", x.captchaTime, captchaEnabled(x))
					if captchaEnabled(x) {
						x.sendCaptcha(bot, update, newUser)
						x.captchaReaper(bot, update, newUser)
					} else {
						x.sendWelcome(bot, update, newUser)
					}
				}
			case update.Message.IsCommand():
				x.processUserCommands(bot, update)
			}
		}
	}
}
Run is the main message dispatcher for the bot.
package main
import (
	"fmt"
	"github.com/go-telegram-bot-api/telegram-bot-api"
	"github.com/patrickmn/go-cache"
	"io"
	"log"
	"math/rand"
	"strings"
	"time"
)
const (
	osProgramadoresURL = "https://osprogramadores.com"
	osProgramadoresRulesURL = "https://osprogramadores.com/regras/"
	osProgramadoresGroup = "osprogramadores"
)
type opBot struct {
	config   botConfig
	commands map[string]botCommand
	newUserCache *cache.Cache
	pendingCaptcha *pendingCaptchaType
	newUserWarningCache *cache.Cache
	welcomeMessageTTL time.Duration
	captchaTime time.Duration
	notifications notificationsInterface
	media         mediaInterface
	bans          bansInterface
	geolocations  geoLocationsInterface
	statsWriter io.WriteCloser
}
type botCommand struct {
	desc      string
	adminOnly bool
	pvtOnly   bool
	enabled   bool
	handler   func(tgbotInterface, tgbotapi.Update) error
}
func newOpBot(config botConfig) (opBot, error) {
	sw, err := initStats()
	if err != nil {
		return opBot{}, fmt.Errorf("error initializing stats: %v", err)
	}
	rand.Seed(time.Now().UnixNano())
	duration := config.NewUserProbationTime.Duration
	return opBot{
		config:        config,
		notifications: newNotifications(),
		media:         newBotMedia(),
		bans:          newBans(),
		geolocations:  newGeolocations(config.LocationKey),
		statsWriter:   sw,
		newUserCache:   cache.New(duration, duration),
		pendingCaptcha: newPendingCaptchaType(),
		newUserWarningCache: cache.New(30*time.Minute, time.Hour),
		welcomeMessageTTL: 30 * time.Minute,
		captchaTime: 1 * time.Minute,
	}, nil
}
func (x *opBot) Close() {
	x.statsWriter.Close()
}