createDefaultProxied
Creates a RateLimiter implementation which retrieves its buckets using proxyManager, see DefaultRateLimitHandler and ProxyBucketAccessor for details.
Requirements
The proxy requires a String to store the bucket key.
Using a database
First, install the PostgreSQL module for Bucket4J (recommended, Bucket4J supports other RDBMs), then, use the following DDL to create the tables storing the buckets, I recommend you put this in a migration script, using Flyway:
CREATE TABLE bucket(id TEXT PRIMARY KEY, state BYTEA, expires_at BIGINT);Note:
You can use any RDBMs supported by Bucket4J, as you are passing the DataSource directly.
You may need to set the default schema on your DataSource to
public, or the schema you store the table in.
Anything else
You can also use anything that accepts a String as your bucket key, such as JCache and Redis, see the Bucket4J docs for more details.
Example
@BService
class ProxyManagerProvider {
@BService
open fun proxyManager(hikariSourceSupplier: HikariSourceSupplier): ProxyManager<String> {
// Create a proxy to manager buckets, persisting with PostgreSQL,
// see https://bucket4j.com/8.14.0/toc.html#postgresqlselectforupdatebasedproxymanager
return Bucket4jPostgreSQL.selectForUpdateBasedBuilder(hikariSourceSupplier.source)
// Bucket expiration, needs to be triggered manually,
// see https://bucket4j.com/8.14.0/toc.html#expiration-policy
.expirationAfterWrite(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(1.minutes.toJavaDuration()))
// RateLimiter#createDefaultProxied uses a String key
.primaryKeyMapper(PreparedStatement::setString)
.build()
}
}@Command
class SlashPersistentRateLimit(private val proxyManager: ProxyManager<String>) : ApplicationCommand(), GlobalApplicationCommandProvider {
fun onSlashPersistentRateLimit(event: GuildSlashEvent) {
event.reply_("Hi", ephemeral = true).queue()
}
override fun declareGlobalApplicationCommands(manager: GlobalApplicationCommandManager) {
manager.slashCommand("persistent_rate_limit", function = ::onSlashPersistentRateLimit) {
// Allow using the command once every hour
// NOTE: this won't take effect if you are the bot owner
val cooldown = Buckets.ofCooldown(1.hours)
// Apply limit on each user, regardless or guild/channel
val rateLimiter = RateLimiter.createDefaultProxied(RateLimitScope.USER, proxyManager, cooldown.toSupplier())
// Register anonymous rate limit, only on this command
rateLimit(rateLimiter)
}
}
}Parameters
Scope of the rate limit, see RateLimitScope values.
The proxy supplying buckets from a key, based on the scope
A supplier of BucketConfiguration, describing the rate limits
Whether the rate limit message should be deleted after expiring