refactor
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"example.com/m/bot"
|
||||
"example.com/m/ui"
|
||||
@@ -18,6 +19,11 @@ type MyProjects struct {
|
||||
WorkspaceID string
|
||||
BackState bot.State
|
||||
OpenPurchases bool
|
||||
|
||||
// Поля для управления фоновой горутиной polling
|
||||
cancel context.CancelFunc
|
||||
pollDone chan struct{}
|
||||
lastProjectCount int
|
||||
}
|
||||
|
||||
func (s *MyProjects) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
@@ -70,6 +76,9 @@ func (s *MyProjects) Enter(b *bot.Bot, mode bot.RenderMode) {
|
||||
}
|
||||
|
||||
s.renderProjects(b, mode, jwt)
|
||||
|
||||
// Запускаем фоновую горутину для автообновления экрана
|
||||
s.startPolling(b, jwt)
|
||||
}
|
||||
|
||||
func (s *MyProjects) renderProjects(b *bot.Bot, mode bot.RenderMode, jwt string) {
|
||||
@@ -80,6 +89,9 @@ func (s *MyProjects) renderProjects(b *bot.Bot, mode bot.RenderMode, jwt string)
|
||||
return
|
||||
}
|
||||
|
||||
// Сохраняем количество проектов для polling
|
||||
s.lastProjectCount = page.Total
|
||||
|
||||
var text string
|
||||
var buttons [][]echotron.InlineKeyboardButton
|
||||
headerTitle := "Мои проекты"
|
||||
@@ -245,3 +257,100 @@ func (s *MyProjects) HandleCallback(b *bot.Bot, u *echotron.Update) {
|
||||
func (s *MyProjects) HandleMessage(_ *bot.Bot, _ *echotron.Update) { return }
|
||||
|
||||
func (s *MyProjects) Handle(_ *bot.Bot, _ *echotron.Update) { return }
|
||||
|
||||
func (s *MyProjects) Exit() {
|
||||
// Останавливаем polling горутину
|
||||
if s.cancel != nil {
|
||||
log.Info().Msg("MyProjects: cancelling polling goroutine")
|
||||
s.cancel()
|
||||
}
|
||||
|
||||
// Ждем завершения горутины с таймаутом 100ms
|
||||
// Это не критично - горутина сама завершится при следующем tick
|
||||
if s.pollDone != nil {
|
||||
select {
|
||||
case <-s.pollDone:
|
||||
log.Info().Msg("MyProjects: polling goroutine finished")
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
log.Info().Msg("MyProjects: polling cleanup timeout, goroutine will finish in background")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MyProjects) startPolling(b *bot.Bot, jwt string) {
|
||||
// Останавливаем предыдущую горутину если она есть
|
||||
if s.cancel != nil {
|
||||
s.cancel()
|
||||
if s.pollDone != nil {
|
||||
<-s.pollDone
|
||||
}
|
||||
}
|
||||
|
||||
// Создаем новый контекст для горутины
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
s.cancel = cancel
|
||||
s.pollDone = make(chan struct{})
|
||||
|
||||
go s.pollProjects(ctx, b, jwt)
|
||||
}
|
||||
|
||||
func (s *MyProjects) pollProjects(ctx context.Context, b *bot.Bot, jwt string) {
|
||||
defer close(s.pollDone)
|
||||
|
||||
// Адаптивный интервал: первые 30 секунд проверяем часто (1 сек),
|
||||
// потом переходим на более редкий polling (3 сек)
|
||||
// Это улучшает UX когда пользователь только добавил проект
|
||||
intervals := []struct {
|
||||
duration time.Duration
|
||||
count int
|
||||
}{
|
||||
{1 * time.Second, 30}, // Первые 30 секунд - каждую секунду
|
||||
{3 * time.Second, -1}, // Потом - каждые 3 секунды (бесконечно)
|
||||
}
|
||||
|
||||
currentIntervalIdx := 0
|
||||
tickCount := 0
|
||||
ticker := time.NewTicker(intervals[0].duration)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Info().Msg("MyProjects polling: context cancelled, stopping")
|
||||
return
|
||||
|
||||
case <-ticker.C:
|
||||
tickCount++
|
||||
|
||||
// Проверяем, нужно ли переключить интервал
|
||||
if currentIntervalIdx < len(intervals)-1 {
|
||||
if intervals[currentIntervalIdx].count > 0 && tickCount >= intervals[currentIntervalIdx].count {
|
||||
currentIntervalIdx++
|
||||
tickCount = 0
|
||||
ticker.Reset(intervals[currentIntervalIdx].duration)
|
||||
log.Info().
|
||||
Dur("new_interval", intervals[currentIntervalIdx].duration).
|
||||
Msg("MyProjects polling: switching to slower interval")
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем количество проектов
|
||||
page, err := b.Backend.GetProjects(context.Background(), jwt, s.WorkspaceID, s.CurrentPage+1, projectsPerPage)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("MyProjects polling: failed to get projects")
|
||||
continue
|
||||
}
|
||||
|
||||
// Если количество изменилось - перерендериваем
|
||||
if page.Total != s.lastProjectCount {
|
||||
log.Info().
|
||||
Int("old_count", s.lastProjectCount).
|
||||
Int("new_count", page.Total).
|
||||
Msg("MyProjects polling: project count changed, re-rendering")
|
||||
|
||||
s.lastProjectCount = page.Total
|
||||
s.renderProjects(b, bot.EditMessage, jwt)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user