-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
221 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
src/main/kotlin/me/devoxin/flight/api/annotations/Cooldown.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package me.devoxin.flight.api.annotations | ||
|
||
import me.devoxin.flight.api.entities.BucketType | ||
import java.util.concurrent.TimeUnit | ||
|
||
@Retention(AnnotationRetention.RUNTIME) | ||
@Target(AnnotationTarget.FUNCTION) | ||
annotation class Cooldown( | ||
val duration: Long, | ||
val timeUnit: TimeUnit = TimeUnit.MILLISECONDS, | ||
val bucket: BucketType | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package me.devoxin.flight.api.entities | ||
|
||
enum class BucketType { | ||
USER, | ||
GUILD, | ||
GLOBAL | ||
} |
66 changes: 66 additions & 0 deletions
66
src/main/kotlin/me/devoxin/flight/api/entities/CooldownProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package me.devoxin.flight.api.entities | ||
|
||
import me.devoxin.flight.api.CommandFunction | ||
|
||
interface CooldownProvider { | ||
|
||
/** | ||
* Checks whether the entity associated with the provided ID is on cool-down. | ||
* When BucketType is `GUILD` and the command was invoked in a private context, this | ||
* method won't be called. | ||
* | ||
* @param id | ||
* The ID of the entity. If the bucket type is USER, this will be a user ID. | ||
* If the bucket type is GUILD, this will be the guild id. | ||
* If the bucket type is GLOBAL, this will be -1. | ||
* | ||
* @param bucket | ||
* The type of bucket the cool-down belongs to. | ||
* For example, one bucket for each entity type; USER, GUILD, GLOBAL. | ||
* If this parameter is GUILD, theoretically you would do `bucket[type].get(id) != null` | ||
* | ||
* @param command | ||
* The command that was invoked. | ||
* | ||
* @returns True, if the entity associated with the ID is on cool-down and the command should | ||
* not be executed. | ||
*/ | ||
fun isOnCooldown(id: Long, bucket: BucketType, command: CommandFunction): Boolean | ||
|
||
/** | ||
* Gets the remaining time of the cooldown in milliseconds. | ||
* This may either return 0L, or throw an exception if an entry isn't present, however | ||
* this should not happen as `isOnCooldown` should be called prior to this. | ||
* | ||
* @param id | ||
* The ID of the entity. The ID could belong to a user or guild, or be -1 if the bucket is GLOBAL. | ||
* | ||
* @param bucket | ||
* The type of bucket to check the cool-down of. | ||
* | ||
* @param command | ||
* The command to get the cool-down time of. | ||
*/ | ||
fun getCooldownTime(id: Long, bucket: BucketType, command: CommandFunction): Long | ||
|
||
/** | ||
* Adds a cooldown for the given entity ID. | ||
* It is up to you whether this passively, or actively removes expired cool-downs. | ||
* When BucketType is `GUILD` and the command was invoked in a private context, this | ||
* method won't be called. | ||
* | ||
* @param id | ||
* The ID of the entity, that the cool-down should be associated with. | ||
* This ID could belong to a user or guild. If bucket is GLOBAL, this will be -1. | ||
* | ||
* @param bucket | ||
* The type of bucket the cool-down belongs to. | ||
* | ||
* @param time | ||
* How long the cool-down should last for, in milliseconds. | ||
* | ||
* @param command | ||
* The command to set cool-down for. | ||
*/ | ||
fun setCooldown(id: Long, bucket: BucketType, time: Long, command: CommandFunction) | ||
} |
62 changes: 62 additions & 0 deletions
62
src/main/kotlin/me/devoxin/flight/api/entities/DefaultCooldownProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package me.devoxin.flight.api.entities | ||
|
||
import me.devoxin.flight.api.CommandFunction | ||
import java.util.concurrent.ConcurrentHashMap | ||
import java.util.concurrent.Executors | ||
import java.util.concurrent.TimeUnit | ||
import kotlin.math.abs | ||
|
||
class DefaultCooldownProvider : CooldownProvider { | ||
private val buckets = ConcurrentHashMap<BucketType, Bucket>() | ||
|
||
override fun isOnCooldown(id: Long, bucket: BucketType, command: CommandFunction): Boolean { | ||
return buckets[bucket]?.isOnCooldown(id, command.name) ?: false | ||
} | ||
|
||
override fun getCooldownTime(id: Long, bucket: BucketType, command: CommandFunction): Long { | ||
return buckets[bucket]?.getCooldownRemainingTime(id, command.name) ?: 0 | ||
} | ||
|
||
override fun setCooldown(id: Long, bucket: BucketType, time: Long, command: CommandFunction) { | ||
buckets.computeIfAbsent(bucket) { Bucket() }.setCooldown(id, time, command.name) | ||
} | ||
|
||
inner class Bucket { | ||
private val sweeperThread = Executors.newSingleThreadScheduledExecutor() | ||
private val cooldowns = ConcurrentHashMap<Long, MutableSet<Cooldown>>() // EntityID => [Commands...] | ||
|
||
fun isOnCooldown(id: Long, commandName: String): Boolean { | ||
return getCooldownRemainingTime(id, commandName) > 0 | ||
} | ||
|
||
fun getCooldownRemainingTime(id: Long, commandName: String): Long { | ||
val cd = cooldowns[id]?.firstOrNull { it.name == commandName } | ||
?: return 0 | ||
|
||
return abs(cd.expires - System.currentTimeMillis()) | ||
} | ||
|
||
fun setCooldown(id: Long, time: Long, commandName: String) { | ||
val cds = cooldowns.computeIfAbsent(id) { mutableSetOf() } | ||
val cooldown = Cooldown(commandName, System.currentTimeMillis() + time) | ||
cds.add(cooldown) | ||
|
||
sweeperThread.schedule({ cds.remove(cooldown) }, time, TimeUnit.MILLISECONDS) | ||
} | ||
} | ||
|
||
inner class Cooldown(val name: String, val expires: Long) { | ||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
|
||
other as Cooldown | ||
|
||
return name == other.name | ||
} | ||
|
||
override fun hashCode(): Int { | ||
return 31 * name.hashCode() | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters