package http import ( "fmt" "github.com/pocketbase/pocketbase/core" ) // Своё правило ограничителя частоты под корнем приложения. // // Заводится потому, что правило хранилища настроено на **его** корень и наших // адресов больше не покрывает: приложение уехало в своё пространство, и вместе с // переездом ограничитель перестал бы существовать для него вовсе. Потеря тихая — // заметить её нечем, пока кто-нибудь не начнёт опрашивать карточку в цикле. // // Числа скромные намеренно: сервисом пользуются единицы человек, а экран // опрашивает карточку, пока запись идёт по конвейеру. Из них же выводится // частота опроса, которую сервис объявляет приложению, — два числа об одном и // том же разъехались бы при первой правке. const ( appRateMaxRequests = 120 appRateWindowSec = 60 ) // ApplyAppRateLimit ставит правило ограничителя на корень приложения. // // Правило приводится к настройке при каждом подъёме, как и настройки провайдера: // применённый шаг схемы не переписывается, а настройки хранилища живут в базе, и // правило, положенное однажды, не пережило бы ни правки числа, ни чистого // каталога данных. func ApplyAppRateLimit(app core.App) error { settings := app.Settings() rule := core.RateLimitRule{ Label: AppRoot + "/", MaxRequests: appRateMaxRequests, Duration: appRateWindowSec, } replaced := false for i, existing := range settings.RateLimits.Rules { if existing.Label == rule.Label { settings.RateLimits.Rules[i] = rule replaced = true break } } if !replaced { settings.RateLimits.Rules = append(settings.RateLimits.Rules, rule) } settings.RateLimits.Enabled = true if err := app.Save(settings); err != nil { return fmt.Errorf("failed to apply app rate limit: %w", err) } return nil }