Skip to content

Commit

Permalink
Implement click callback provider
Browse files Browse the repository at this point in the history
  • Loading branch information
astei committed Apr 20, 2023
1 parent 7f776ab commit 3b17114
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 1 deletion.
3 changes: 3 additions & 0 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ dependencies {
api(libs.brigadier)
api(libs.bundles.configurate)
api(libs.caffeine)

compileOnly(libs.auto.service.annotations)
annotationProcessor(libs.auto.service)
}

tasks {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.velocitypowered.api.plugin.ap;

import com.google.auto.service.AutoService;
import com.google.gson.Gson;
import com.velocitypowered.api.plugin.Plugin;
import java.io.BufferedWriter;
Expand All @@ -16,6 +17,7 @@
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
Expand All @@ -30,6 +32,7 @@
/**
* Annotation processor for Velocity.
*/
@AutoService(Processor.class)
@SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"})
public class PluginAnnotationProcessor extends AbstractProcessor {

Expand Down

This file was deleted.

2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ shadow = "com.github.johnrengelman.shadow:8.1.0"
spotless = "com.diffplug.spotless:6.12.0"

[libraries]
auto-service = "com.google.auto.service:auto-service:1.0.1"
auto-service-annotations = "com.google.auto.service:auto-service-annotations:1.0.1"
adventure-bom = "net.kyori:adventure-bom:4.13.1"
adventure-facet = "net.kyori:adventure-platform-facet:4.3.0"
asynchttpclient = "org.asynchttpclient:async-http-client:2.12.3"
Expand Down
3 changes: 3 additions & 0 deletions proxy/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,8 @@ dependencies {
implementation(libs.lmbda)
implementation(libs.bundles.flare)
compileOnly(libs.spotbugs.annotations)
compileOnly(libs.auto.service.annotations)
testImplementation(libs.mockito)

annotationProcessor(libs.auto.service)
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.ProxyVersion;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.server.ClickCallbackProviderImpl;
import com.velocitypowered.proxy.util.InformationUtils;
import java.io.BufferedWriter;
import java.io.IOException;
Expand All @@ -49,6 +50,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import net.kyori.adventure.text.Component;
Expand Down Expand Up @@ -93,6 +95,7 @@ public VelocityCommand(VelocityServer server) {
.put("reload", new Reload(server))
.put("dump", new Dump(server))
.put("heap", new Heap())
.put("callback", new Callback())
.build();
}

Expand Down Expand Up @@ -485,4 +488,31 @@ public boolean hasPermission(CommandSource source, String @NonNull [] args) {
}

}

/**
* Callback SubCommand.
*/
public static class Callback implements SubCommand {

@Override
public void execute(final CommandSource source, final String @NonNull [] args) {
if (args.length != 1) {
return;
}

final UUID id;
try {
id = UUID.fromString(args[0]);
} catch (final IllegalArgumentException ignored) {
return;
}

ClickCallbackProviderImpl.MANAGER.runCallback(source, id);
}

@Override
public boolean hasPermission(final CommandSource source, final String @NonNull [] args) {
return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (C) 2023 Velocity Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.server;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Expiry;
import com.github.benmanes.caffeine.cache.Scheduler;
import com.google.auto.service.AutoService;
import java.time.Duration;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.event.ClickCallback;
import net.kyori.adventure.text.event.ClickEvent;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Implementation of {@link ClickCallback.Provider}.
*/
@AutoService(ClickCallback.Provider.class)
@SuppressWarnings("UnstableApiUsage") // permitted provider
public class ClickCallbackProviderImpl implements ClickCallback.Provider {

public static final ClickCallbackManager MANAGER = new ClickCallbackManager();

@Override
public @NotNull ClickEvent create(@NotNull ClickCallback<Audience> callback,
@NotNull ClickCallback.Options options) {
final UUID id = MANAGER.register(callback, options);
return ClickEvent.runCommand("/velocity callback " + id);
}

/**
* Click callback manager.
*/
public static class ClickCallbackManager {

private final Cache<UUID, RegisteredCallback> registrations;

private ClickCallbackManager() {
this.registrations = Caffeine.newBuilder()
.expireAfter(new Expiry<UUID, RegisteredCallback>() {
@Override
public long expireAfterCreate(UUID key, RegisteredCallback value, long currentTime) {
return value.duration.toNanos();
}

@Override
public long expireAfterUpdate(UUID key, RegisteredCallback value, long currentTime,
@NonNegative long currentDuration) {
return currentDuration;
}

@Override
public long expireAfterRead(UUID key, RegisteredCallback value, long currentTime,
@NonNegative long currentDuration) {
if (value.remainingUses != null && value.remainingUses.get() <= 0) {
return 0;
}
return currentDuration;
}
})
.scheduler(Scheduler.systemScheduler())
.build();
}

/**
* Run a callback.
*
* @param audience the audience
* @param id the callback's ID
* @return {@code true} if the callback was run, {@code false} if not
*/
public boolean runCallback(final @NotNull Audience audience, final UUID id) {
final RegisteredCallback callback = this.registrations.getIfPresent(id);
if (callback != null && callback.tryUse()) {
callback.callback.accept(audience);
return true;
}
return false;
}

/**
* Registers a click callback.
*
* @param callback the callback to register
* @param options associated options
* @return the callback ID
*/
public UUID register(@NotNull ClickCallback<Audience> callback,
@NotNull ClickCallback.Options options) {
final Duration duration = options.lifetime();
final int maxUses = options.uses();
final UUID id = UUID.randomUUID();
final RegisteredCallback registration = new RegisteredCallback(
duration, maxUses, callback);
this.registrations.put(id, registration);
return id;
}
}

private static class RegisteredCallback {

private final Duration duration;
private final @Nullable AtomicInteger remainingUses;
private final ClickCallback<Audience> callback;

private RegisteredCallback(Duration duration, int maxUses,
ClickCallback<Audience> callback) {
this.duration = duration;
this.remainingUses = maxUses == ClickCallback.UNLIMITED_USES
? null : new AtomicInteger(maxUses);
this.callback = callback;
}

public boolean tryUse() {
if (this.remainingUses != null) {
return this.remainingUses.decrementAndGet() >= 0;
}
return true;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ velocity.command.dump-success=Created an anonymised report containing useful inf
velocity.command.dump-will-expire=This link will expire in a few days.
velocity.command.dump-server-error=An error occurred on the Velocity servers and the dump could not be completed. Please contact the Velocity staff about this problem and provide the details about this error from the Velocity console or server log.
velocity.command.dump-offline=Likely cause: Invalid system DNS settings or no internet connection

# Kick
velocity.kick.shutdown=Proxy shutting down.

0 comments on commit 3b17114

Please sign in to comment.