OpisDescription

Moduł RateLimit kontroluje częstotliwość wykonywania akcji w aplikacji. Obsługuje różne strategie limitowania (sliding window, token bucket) i integruje sięThe RateLimit module controls action execution frequency in the app. Supports various rate limiting strategies (sliding window, token bucket) and integrates z Timer.cooldown oraz SecureStorage dla persystencji.

Podstawowe użycieBasic Usage

// Sprawdź i wykonaj
if (ADict.RateLimit.tryAcquire("api_call")) {
    makeApiCall()
} else {
    showRateLimitedMessage()
}

// Z automatyczną akcją
ADict.RateLimit.tryAcquire("share_button", cooldownMs = 5000L) {
    shareContent()
}

// Z fallbackiem
val result = ADict.RateLimit.withLimit("search", fallback = emptyList()) {
    api.search(query)
}

KonfiguracjaConfiguration limitów

// Sliding window - 60 req/min
ADict.RateLimit.configure("api_call") {
    maxRequests = 60
    windowMinutes(1)
    strategy = Strategy.SLIDING_WINDOW
}

// Token bucket - burst + sustained rate
ADict.RateLimit.configure("ad_request") {
    maxRequests = 10
    windowMs = 60_000L
    strategy = Strategy.TOKEN_BUCKET
    burstSize = 3
    refillRatePerSecond = 0.5
}

// Z blokowaniem po przekroczeniu
ADict.RateLimit.configure("login_attempt") {
    maxRequests = 5
    windowMinutes(15)
    blockDurationMs = 30_000L  // Zablokuj na 30s
}

StrategieStrategies

Strategia OpisDescription UżycieUsage
FIXED_WINDOW Stałe okno czasoweFixed time window Proste limity, np. 100/godz
SLIDING_WINDOW Przesuwne okno (domyślna)Sliding window (default) Płynne limity bez spike'ówSmooth limits without spikes
TOKEN_BUCKET Burst + sustained rate API z burstami, reklamyAPIs with bursts, ads
LEAKY_BUCKET Stały output rateConstant output rate Równomierny przepływUniform flow

PresetyPresets

// Użyj gotowych presetów
ADict.RateLimit.applyPreset(RateLimit.Presets.API_STANDARD)      // 60/min
ADict.RateLimit.applyPreset(RateLimit.Presets.API_STRICT)        // 10/min + block
ADict.RateLimit.applyPreset(RateLimit.Presets.BUTTON_ANTISPAM)   // 5/10s
ADict.RateLimit.applyPreset(RateLimit.Presets.AD_REQUEST)        // Token bucket
ADict.RateLimit.applyPreset(RateLimit.Presets.SHARE)             // 10/5min

StatystykiStatistics

val stats = ADict.RateLimit.getStats("api_call")
println("Użyto: ${stats?.currentCount}/${stats?.maxRequests}")
println("Pozostało: ${stats?.remainingRequests}")
println("Reset za: ${stats?.resetInMs}ms")
println("Zablokowano: ${stats?.blockedCount} razy")

// Quick checks
val remaining = ADict.RateLimit.getRemaining("api_call")
val isLimited = ADict.RateLimit.isLimited("api_call")
val resetTime = ADict.RateLimit.getResetTime("api_call")

CallbackiCallbacks

ADict.RateLimit.onLimitReached { id, stats ->
    analytics.log("rate_limited", mapOf(
        "action" to id,
        "blocked_count" to stats.blockedCount
    ))

    if (id == "api_call") {
        showApiLimitWarning()
    }
}

Remote Config

// Dynamiczne limity z Remote Config
// Format w RC: "maxRequests,windowMs,strategy"
// np. "100,60000,SLIDING_WINDOW"
ADict.RateLimit.configureFromRemote(
    id = "api_call",
    remoteKey = "rate_limit_api",
    defaultConfig = RateLimit.Presets.API_STANDARD
)

Reset

// Reset pojedynczego limitu
ADict.RateLimit.reset("api_call")

// Reset wszystkich
ADict.RateLimit.resetAll()

DebounceDebounce

Executes action only after delay with no new calls. Each new call resets the timer.Wykonuje akcję tylko po opóźnieniu bez nowych wywołań. Każde nowe wywołanie resetuje timer.

// In search field - wait for user to stop typing
searchField.addTextChangedListener { text ->
    ADict.RateLimit.debounce("search", 300L) {
        performSearch(text.toString())
    }
}

// Cancel pending debounce
ADict.RateLimit.cancelDebounce("search")

ThrottleThrottle

Executes action at most once per interval. First call executes immediately.Wykonuje akcję co najwyżej raz na interwał. Pierwsze wywołanie wykonywane natychmiast.

// Button throttle - max once per second
button.setOnClickListener {
    ADict.RateLimit.throttle("save_button", 1000L) {
        saveData()
    }
}

// Throttle with trailing edge - executes last call after interval
scrollView.setOnScrollChangeListener { _, _, _, _, _ ->
    ADict.RateLimit.throttleTrailing("scroll_analytics", 500L) {
        logScrollPosition()
    }
}

// Reset throttle (allow immediate execution)
ADict.RateLimit.resetThrottle("save_button")

View ExtensionsRozszerzenia widoków

import rip.nerd.adictlibrary.modules.setOnClickDebounced
import rip.nerd.adictlibrary.modules.setOnClickThrottled
import rip.nerd.adictlibrary.modules.setOnClickRateLimited

// Debounced click - prevents double clicks
button.setOnClickDebounced(500L) {
    navigateToNextScreen()
}

// Throttled click - max once per interval
likeButton.setOnClickThrottled(1000L) {
    toggleLike()
}

// Rate limited click with callback
shareButton.setOnClickRateLimited(
    limitId = "share_action",
    maxClicks = 3,
    windowMs = 10_000L,
    onLimitReached = { showTooManySharesMessage() }
) {
    shareContent()
}