Bekassyl
Bekassyl

Reputation: 45

How to run infinite loop and keep getting updates in telegram bot

I'm writing telegram-bot using Go (go-telegram-bot-api). It constantly parses a website and notifies about changes (every minute). Today I added simple keyboard and now can't make them work together.

The problem is that webpage parsing is in the infinite loop and program when it enters the loop ignores updates coming from the "client".

I've tried putting everything in a single loop, changing orders, etc. Maybe there is another or proper way of doing this?

Sample code:

    u := tgbotapi.NewUpdate(0)
    u.Timeout = 60

    updates, err := bot.GetUpdatesChan(u)

    for update := range updates {
            if update.Message != nil {

                  switch update.Message.Text {
                        case "Show Keyboard":
                              Keyboard is sent
                        case "OptionsForParsing":
                              options.applied
                        case "StartParsing":
                              search bool = true
                        case "StopParsing":
                              search bool = false
                   }
            }

            if search == true{  
            for{
                 time.Sleep(1 * time.Minute)
                 AreThereChanges?()
                 if yes{
                         msg := tgbotapi.NewMessage(update.Message.Chat.ID, "help please")
                         bot.Send(msg)
                 }
            }}
     }

Upvotes: 1

Views: 1174

Answers (2)

Bekassyl
Bekassyl

Reputation: 45

Thanks to kimgrey I dug a bit into goroutines and channels. Infinite loop is in a separate goroutine and escaping is done through unbuffered channel (check "game changer" comments in the sample code). Now I can enter and escape infinite loop when needed. Here's how I solved my problem:

u := tgbotapi.NewUpdate(0)
u.Timeout = 60

updates, err := bot.GetUpdatesChan(u)
done := make(chan bool)                       //game changer
for update := range updates {
        if update.Message != nil {

              switch update.Message.Text {
                    case "Show Keyboard":
                          Keyboard is sent
                    case "OptionsForParsing":
                          options.applied
                    case "StartParsing":
                          search bool = true
                    case "StopParsing":
                          search bool = false
                          done<-true                 //game changer
               }

            go func() {
                ticker := time.NewTicker(time.Minute)
                defer ticker.Stop()
                if search{
                for {
                    select {
                        case <-done:                //game changer
                            return
                        case <-ticker.C:
                            AnyChanges?()
                    }
                }}              
            }()
        }
 }

Upvotes: 1

kimrgrey
kimrgrey

Reputation: 562

If I understood everything right you should start parsing loop inside of separated goroutine so updates cycle will keep working.

Try to do something like this:

// you can use cancel to stop running parsing goroutine
ctx, cancel := context.WithCancel(context.Background())

go func() {
  ticker := time.NewTicker(5 * time.Second)
  defer ticker.Stop()

  for {
    select {
      case <-ctx.Done():
        return
      case <-ticker.C:
        AreThereChanges?()
        if yes {
          msg := tgbotapi.NewMessage(update.Message.Chat.ID, "help please")
          bot.Send(msg)
        }
      }
  }
}()

Writing from the top of my brain, so do not expect it to compile from the first attempt, but demonstrates the idea. Please, check out following links for more information regarding Ticker and contexts with cancellation: click, click.

Upvotes: 2

Related Questions