Skip to content

Commit

Permalink
allow for deletion :)
Browse files Browse the repository at this point in the history
  • Loading branch information
Citymonstret committed Jan 5, 2024
1 parent 59917c4 commit 1998e8c
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 8 deletions.
6 changes: 6 additions & 0 deletions cloud-processors-cooldown/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ dependencies {

compileOnly(libs.cloud.annotations)
}

// TODO(City): Disable this
// we're getting errors on generated files due to -Werror :(
tasks.withType<JavaCompile> {
options.compilerArgs.remove("-Werror")
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import cloud.commandframework.context.CommandContext;
import java.time.Clock;
import java.util.List;
import java.util.function.Predicate;
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.NonNull;
Expand Down Expand Up @@ -69,6 +70,13 @@ public interface CooldownConfiguration<C> {
*/
@NonNull CooldownNotifier<C> cooldownNotifier();

/**
* Returns the creation listeners.
*
* @return creation listeners
*/
@NonNull List<CooldownCreationListener<C>> creationListeners();

/**
* Returns a predicate that determines whether the {@link CommandContext}
* should bypass the cooldown requirement.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// MIT License
//
// Copyright (c) 2024 Incendo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
package org.incendo.cloud.processors.cooldown;

import cloud.commandframework.Command;
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.NonNull;

/**
* Listener that gets invoked when a new cooldown is created.
*
* @param <C> command sender type
* @since 1.0.0
*/
@API(status = API.Status.STABLE, since = "1.0.0")
public interface CooldownCreationListener<C> {

/**
* Invoked when a new cooldown is created.
*
* @param sender sender that the cooldown is created for
* @param command command that triggered the cooldown creation
* @param instance created instance
*/
void cooldownCreated(@NonNull C sender, @NonNull Command<C> command, @NonNull CooldownInstance instance);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.immutables.value.Value;
import org.incendo.cloud.processors.cooldown.profile.CooldownProfile;
import org.incendo.cloud.processors.immutables.StagedImmutableBuilder;

/**
Expand All @@ -45,10 +46,17 @@ public interface CooldownInstance {
*
* @return the builder
*/
static ImmutableCooldownInstance.@NonNull GroupBuildStage builder() {
static ImmutableCooldownInstance.@NonNull ProfileBuildStage builder() {
return ImmutableCooldownInstance.builder();
}

/**
* Returns the profile that owns the cooldown.
*
* @return the owning profile
*/
@NonNull CooldownProfile profile();

/**
* Returns the cooldown group.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,17 @@ public void accept(final @NonNull CommandPostprocessingContext<C> context) {
}

final CooldownInstance instance = CooldownInstance.builder()
.profile(profile)
.group(group)
.duration(((DurationFunction<C>) cooldown.duration()).getDuration(context.commandContext()))
.creationTime(Instant.now(this.cooldownManager.configuration().clock()))
.build();
profile.setCooldown(group, instance);

this.cooldownManager.configuration().creationListeners().forEach(listener -> listener.cooldownCreated(
context.commandContext().sender(),
context.command(),
instance
));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.function.Function;
import org.apiguardian.api.API;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.incendo.cloud.processors.cache.CloudCache;
import org.incendo.cloud.processors.cooldown.profile.CooldownProfile;
import org.incendo.cloud.processors.cooldown.profile.CooldownProfileFactory;
Expand Down Expand Up @@ -97,6 +98,31 @@ public interface CooldownRepository<K> {
*/
@NonNull CooldownProfile getProfile(@NonNull K key, @NonNull CooldownProfileFactory profileFactory);

/**
* Returns the profile for the given {@code key}, if it exists.
*
* @param key key that identifies the profile
* @return the profile, or {@code null}
*/
@Nullable CooldownProfile getProfileIfExists(@NonNull K key);

/**
* Deletes the profile identified by the given {@code key}.
*
* @param key the key
*/
void deleteProfile(@NonNull K key);

/**
* Deletes the cooldown identified by the given {@code key} belonging to the given {@code group}.
*
* <p>If the profile is empty after the deletion, then the profile is deleted too.</p>
*
* @param key key identifying the profile
* @param group group to delete
*/
void deleteCooldown(@NonNull K key, @NonNull CooldownGroup group);


final class MappingCooldownRepository<C, K> implements CooldownRepository<C> {

Expand All @@ -113,12 +139,45 @@ private MappingCooldownRepository(
}

@Override
public @NonNull CooldownProfile getProfile(final @NonNull C key, final @NonNull CooldownProfileFactory profileFactory) {
public @NonNull CooldownProfile getProfile(
final @NonNull C key,
final @NonNull CooldownProfileFactory profileFactory
) {
return this.otherRepository.getProfile(this.mappingFunction.apply(key), profileFactory);
}

@Override
public @Nullable CooldownProfile getProfileIfExists(final @NonNull C key) {
return this.otherRepository.getProfileIfExists(this.mappingFunction.apply(key));
}

@Override
public void deleteProfile(final @NonNull C key) {
this.otherRepository.deleteProfile(this.mappingFunction.apply(key));
}

@Override
public void deleteCooldown(final @NonNull C key, final @NonNull CooldownGroup group) {
this.otherRepository.deleteCooldown(this.mappingFunction.apply(key), group);
}
}

final class MapCooldownRepository<K> implements CooldownRepository<K> {
abstract class AbstractCooldownRepository<K> implements CooldownRepository<K> {

@Override
public synchronized void deleteCooldown(final @NonNull K key, final @NonNull CooldownGroup group) {
final CooldownProfile profile = this.getProfileIfExists(key);
if (profile == null) {
return;
}
profile.deleteCooldown(group);
if (profile.isEmpty()) {
this.deleteProfile(key);
}
}
}

final class MapCooldownRepository<K> extends AbstractCooldownRepository<K> {

private final Map<K, CooldownProfile> map;

Expand All @@ -127,12 +186,25 @@ private MapCooldownRepository(final @NonNull Map<K, CooldownProfile> map) {
}

@Override
public @NonNull CooldownProfile getProfile(final @NonNull K key, final @NonNull CooldownProfileFactory profileFactory) {
public synchronized @NonNull CooldownProfile getProfile(
final @NonNull K key,
final @NonNull CooldownProfileFactory profileFactory
) {
return this.map.computeIfAbsent(key, k -> profileFactory.create());
}

@Override
public synchronized @Nullable CooldownProfile getProfileIfExists(final @NonNull K key) {
return this.map.get(key);
}

@Override
public synchronized void deleteProfile(final @NonNull K key) {
this.map.remove(key);
}
}

final class CacheCooldownRepository<K> implements CooldownRepository<K> {
final class CacheCooldownRepository<K> extends AbstractCooldownRepository<K> {

private final CloudCache<K, CooldownProfile> cache;

Expand All @@ -141,13 +213,26 @@ private CacheCooldownRepository(final @NonNull CloudCache<K, CooldownProfile> ca
}

@Override
public @NonNull CooldownProfile getProfile(final @NonNull K key, final @NonNull CooldownProfileFactory profileFactory) {
public synchronized @NonNull CooldownProfile getProfile(
final @NonNull K key,
final @NonNull CooldownProfileFactory profileFactory
) {
CooldownProfile profile = this.cache.getIfPresent(key);
if (profile == null) {
profile = profileFactory.create();
this.cache.put(key, profile);
}
return profile;
}

@Override
public synchronized @Nullable CooldownProfile getProfileIfExists(final @NonNull K key) {
return this.cache.getIfPresent(key);
}

@Override
public synchronized void deleteProfile(final @NonNull K key) {
this.cache.delete(key);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,18 @@ public interface CooldownProfile {
* @param cooldown cooldown value
*/
void setCooldown(@NonNull CooldownGroup group, @NonNull CooldownInstance cooldown);

/**
* Deletes the cooldown for the given {@code group}, if it exists.
*
* @param group the group
*/
void deleteCooldown(@NonNull CooldownGroup group);

/**
* Returns whether the profile is empty.
*
* @return {@code true} if the profile is empty, else {@code false}
*/
boolean isEmpty();
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ final class CooldownProfileImpl implements CooldownProfile {
}

@Override
public synchronized @Nullable CooldownInstance getCooldown(@NonNull final CooldownGroup group) {
public synchronized @Nullable CooldownInstance getCooldown(final @NonNull CooldownGroup group) {
final CooldownInstance cooldown = this.cooldowns.get(group);
if (cooldown == null) {
return null;
Expand All @@ -58,7 +58,17 @@ final class CooldownProfileImpl implements CooldownProfile {
}

@Override
public synchronized void setCooldown(@NonNull final CooldownGroup group, @NonNull final CooldownInstance cooldown) {
public synchronized void setCooldown(final @NonNull CooldownGroup group, final @NonNull CooldownInstance cooldown) {
this.cooldowns.put(group, cooldown);
}

@Override
public synchronized void deleteCooldown(final @NonNull CooldownGroup group) {
this.cooldowns.remove(group);
}

@Override
public boolean isEmpty() {
return this.cooldowns.isEmpty();
}
}
Loading

0 comments on commit 1998e8c

Please sign in to comment.