Compare commits

...

8 Commits

Author SHA1 Message Date
bae077654e
refactor(Discord4J): implement CommandRegisterer refactor
Some checks failed
github-mirror / push-github (push) Successful in 1m44s
Build / Gradle-Build (push) Successful in 55s
Test / Gradle-Test (push) Failing after 41s
2025-03-16 17:16:26 +01:00
203498de68
refactor(javacord): implement CommandRegisterer refactor 2025-03-16 17:07:14 +01:00
24df1731da
refactor(command): add CommandRegisterer 2025-03-16 17:06:37 +01:00
e3fc10a1ce
fix(util): ObjectListAggregator syntax 2025-03-16 02:48:24 +01:00
78cacb7eb6
feat(util): add ObjectListAggregator 2025-03-16 02:47:16 +01:00
7287d44645
refactor(util): add multiple key support to ObjectAggregator 2025-03-16 02:46:55 +01:00
630c8ddee5
feat(register): add convenience getter 2025-03-16 01:49:24 +01:00
4e27e6ce56
feat(struct): introduce ObjectAggregator 2025-03-16 01:36:23 +01:00
11 changed files with 213 additions and 82 deletions

View File

@ -95,6 +95,10 @@ public class SlashCommandDefinition {
return this.rootIdentifier().equals(other.rootIdentifier());
}
public long[] serverIds() {
return rootIdentifier().serverIds();
}
public Set<InteractionIdentifier> entries() {
return this.entries;
}

View File

@ -1,7 +1,7 @@
package net.tomatentum.marinara.registry;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@ -13,9 +13,10 @@ import net.tomatentum.marinara.Marinara;
import net.tomatentum.marinara.interaction.InteractionHandler;
import net.tomatentum.marinara.interaction.InteractionType;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
import net.tomatentum.marinara.interaction.ident.InteractionIdentifier;
import net.tomatentum.marinara.interaction.ident.RootCommandIdentifier;
import net.tomatentum.marinara.interaction.ident.SlashCommandIdentifier;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.util.ObjectAggregator;
import net.tomatentum.marinara.wrapper.IdentifierProvider;
import net.tomatentum.marinara.interaction.methods.InteractionMethod;
@ -51,26 +52,19 @@ public class InteractionRegistry {
}
public void registerCommands() {
List<SlashCommandDefinition> defs = new ArrayList<>();
List<SlashCommandIdentifier> slashIdentifiers = interactions.stream()
List<InteractionIdentifier> slashIdentifiers = interactions.stream()
.filter((x) -> x.type().equals(InteractionType.COMMAND))
.map((x) -> (SlashCommandIdentifier)x.identifier())
.map((x) -> x.identifier())
.toList();
slashIdentifiers.forEach((ident) -> {
Optional<SlashCommandDefinition> appDef = defs.stream()
.filter((x) -> x.rootIdentifier().equals(ident.rootNode()))
.findFirst();
SlashCommandDefinition[] defs = new ObjectAggregator<InteractionIdentifier, RootCommandIdentifier, SlashCommandDefinition>(
i -> Arrays.asList((RootCommandIdentifier)i.rootNode()),
SlashCommandDefinition::addIdentifier,
SlashCommandDefinition::new)
.aggregate(slashIdentifiers)
.toArray(SlashCommandDefinition[]::new);
if (appDef.isPresent())
appDef.get().addIdentifier(ident);
else
defs.add(
new SlashCommandDefinition((RootCommandIdentifier) ident.rootNode())
.addIdentifier(ident));
});
marinara.getWrapper().registerSlashCommands(defs.toArray(SlashCommandDefinition[]::new));
marinara.getWrapper().getRegisterer().register(defs);
logger.info("Registered all SlashCommands");
}

View File

@ -0,0 +1,46 @@
package net.tomatentum.marinara.util;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class ObjectAggregator<O, K, V> {
private Function<O, Iterable<K>> keySupplier;
private BiConsumer<V, O> valueConsumer;
private Function<K, V> defaultGenerator;
public ObjectAggregator(
Function<O, Iterable<K>> keySupplier,
BiConsumer<V, O> valueConsumer,
Function<K, V> defaultGenerator) {
this.keySupplier = keySupplier;
this.valueConsumer = valueConsumer;
this.defaultGenerator = defaultGenerator;
}
public ObjectAggregator(
Function<O, Iterable<K>> keySupplier,
BiConsumer<V, O> valueConsumer,
Supplier<V> defaultGenerator) {
this.keySupplier = keySupplier;
this.valueConsumer = valueConsumer;
this.defaultGenerator = _ -> defaultGenerator.get();
}
public Collection<V> aggregate(Iterable<O> iterator) {
Map<K, V> map = new HashMap<>();
for (O element : iterator) {
Iterable<K> keys = this.keySupplier.apply(element);
for (K key : keys) {
V value = map.getOrDefault(key, this.defaultGenerator.apply(key));
this.valueConsumer.accept(value, element);
map.putIfAbsent(key, value);
}
}
return map.values();
}
}

View File

@ -0,0 +1,15 @@
package net.tomatentum.marinara.util;
import java.util.ArrayList;
import java.util.function.Function;
public class ObjectListAggregator<O, K, V> extends ObjectAggregator<O, K, ArrayList<V>> {
public ObjectListAggregator(Function<O, Iterable<K>> keySupplier, Function<O, V> valueConsumer) {
super(keySupplier,
(l, o) -> l.add(valueConsumer.apply(o)),
() -> new ArrayList<>());
}
}

View File

@ -0,0 +1,45 @@
package net.tomatentum.marinara.wrapper;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
import net.tomatentum.marinara.util.ObjectAggregator;
public class CommandRegisterer<A extends Object> {
public static <A extends Object> CommandRegisterer<A> of(Strategy<A> strategy, CommandConverter<A, ?, ?> converter) {
return new CommandRegisterer<A>(strategy, converter);
}
private Strategy<A> strategy;
private CommandConverter<A, ?, ?> converter;
CommandRegisterer(Strategy<A> strategy, CommandConverter<A, ?, ?> converter) {
this.strategy = strategy;
this.converter = converter;
}
public void register(SlashCommandDefinition[] slashDefs) {
Set<ServerCommandList<A>> serverCommands = new ObjectAggregator<SlashCommandDefinition, Long, ServerCommandList<A>>(
def -> Arrays.stream(def.serverIds()).boxed().toList(),
(l, o) -> l.add(converter.convert(o)),
ServerCommandList::new)
.aggregate(Arrays.asList(slashDefs)).stream()
.collect(Collectors.toSet());
Set<A> globalCommands = Arrays.stream(slashDefs)
.filter(x -> x.serverIds().length <= 0)
.map(converter::convert)
.collect(Collectors.toSet());
serverCommands.forEach(strategy::registerServer);
strategy.registerGlobal(globalCommands);
}
public interface Strategy<A extends Object> {
void registerServer(ServerCommandList<A> commands);
void registerGlobal(Set<A> defs);
}
}

View File

@ -3,9 +3,6 @@ package net.tomatentum.marinara.wrapper;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
public abstract class LibraryWrapper {
private List<Consumer<Object>> interactionSubscriber;
@ -25,8 +22,7 @@ public abstract class LibraryWrapper {
interactionSubscriber.remove(consumer);
}
public abstract void registerSlashCommands(SlashCommandDefinition[] defs);
public abstract CommandRegisterer<?> getRegisterer();
public abstract IdentifierProvider createIdentifierProvider();
public abstract ContextObjectProvider getContextObjectProvider();

View File

@ -0,0 +1,16 @@
package net.tomatentum.marinara.wrapper;
import java.util.HashSet;
public class ServerCommandList<A> extends HashSet<A>{
private long serverId;
public ServerCommandList(long serverId) {
this.serverId = serverId;
}
public long serverId() {
return serverId;
}
}

View File

@ -0,0 +1,32 @@
package net.tomatentum.marinara.wrapper.discord4j;
import java.util.ArrayList;
import java.util.Set;
import discord4j.core.GatewayDiscordClient;
import discord4j.discordjson.json.ApplicationCommandRequest;
import discord4j.rest.service.ApplicationService;
import net.tomatentum.marinara.wrapper.CommandRegisterer;
import net.tomatentum.marinara.wrapper.ServerCommandList;
public class Discord4JRegistererStrategy implements CommandRegisterer.Strategy<ApplicationCommandRequest> {
private ApplicationService appService;
private long applicationId;
public Discord4JRegistererStrategy(GatewayDiscordClient api) {
this.appService = api.getRestClient().getApplicationService();
this.applicationId = api.getRestClient().getApplicationId().block();
}
@Override
public void registerServer(ServerCommandList<ApplicationCommandRequest> commands) {
appService.bulkOverwriteGuildApplicationCommand(applicationId, commands.serverId(), new ArrayList<>(commands));
}
@Override
public void registerGlobal(Set<ApplicationCommandRequest> defs) {
appService.bulkOverwriteGlobalApplicationCommand(applicationId, new ArrayList<>(defs));
}
}

View File

@ -1,7 +1,5 @@
package net.tomatentum.marinara.wrapper.discord4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.Function;
@ -11,13 +9,11 @@ import discord4j.core.GatewayDiscordClient;
import discord4j.core.event.domain.interaction.InteractionCreateEvent;
import discord4j.core.object.command.ApplicationCommandInteractionOption;
import discord4j.core.object.command.ApplicationCommandOption.Type;
import discord4j.discordjson.json.ApplicationCommandOptionChoiceData;
import discord4j.discordjson.json.ApplicationCommandOptionData;
import discord4j.discordjson.json.ApplicationCommandRequest;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
import net.tomatentum.marinara.util.LoggerUtil;
import net.tomatentum.marinara.wrapper.CommandConverter;
import net.tomatentum.marinara.wrapper.CommandRegisterer;
import net.tomatentum.marinara.wrapper.ContextObjectProvider;
import net.tomatentum.marinara.wrapper.IdentifierProvider;
import net.tomatentum.marinara.wrapper.LibraryWrapper;
@ -37,16 +33,15 @@ public class Discord4JWrapper extends LibraryWrapper {
.filter(o -> !o.getType().equals(Type.SUB_COMMAND) && !o.getType().equals(Type.SUB_COMMAND_GROUP))
.toList();
private GatewayDiscordClient api;
private Discord4JContextObjectProvider contextObjectProvider;
private CommandConverter<ApplicationCommandRequest, ApplicationCommandOptionData, ApplicationCommandOptionChoiceData> commandConverter;
private CommandRegisterer<ApplicationCommandRequest> commandRegisterer;
private Logger logger = LoggerUtil.getLogger(getClass());
public Discord4JWrapper(GatewayDiscordClient api) {
this.api = api;
this.contextObjectProvider = new Discord4JContextObjectProvider();
this.commandConverter = CommandConverter.of(new Discord4JConverterSpec());
var converter = CommandConverter.of(new Discord4JConverterSpec());
this.commandRegisterer = CommandRegisterer.of(new Discord4JRegistererStrategy(api), converter);
if (api != null)
api.on(InteractionCreateEvent.class)
@ -58,26 +53,8 @@ public class Discord4JWrapper extends LibraryWrapper {
}
@Override
public void registerSlashCommands(SlashCommandDefinition[] defs) {
HashMap<Long, List<ApplicationCommandRequest>> serverCommands = new HashMap<>();
List<ApplicationCommandRequest> globalCommands = new ArrayList<>();
long applicationId = api.getRestClient().getApplicationId().block();
for (SlashCommandDefinition slashCommandDefinition : defs) {
ApplicationCommandRequest request = this.commandConverter.convert(slashCommandDefinition);
if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) {
for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) {
serverCommands.putIfAbsent(serverId, new ArrayList<>());
serverCommands.get(serverId).add(request);
}
}else
globalCommands.add(request);
}
for (long serverId : serverCommands.keySet()) {
api.getRestClient().getApplicationService().bulkOverwriteGuildApplicationCommand(applicationId, serverId, serverCommands.get(serverId));
}
api.getRestClient().getApplicationService().bulkOverwriteGlobalApplicationCommand(applicationId, globalCommands);
public CommandRegisterer<?> getRegisterer() {
return this.commandRegisterer;
}
@Override
@ -93,5 +70,5 @@ public class Discord4JWrapper extends LibraryWrapper {
public ContextObjectProvider getContextObjectProvider() {
return this.contextObjectProvider;
}
}

View File

@ -0,0 +1,29 @@
package net.tomatentum.marinara.wrapper.javacord;
import java.util.Set;
import org.javacord.api.DiscordApi;
import org.javacord.api.interaction.SlashCommandBuilder;
import net.tomatentum.marinara.wrapper.CommandRegisterer;
import net.tomatentum.marinara.wrapper.ServerCommandList;
public class JavacordRegistererStrategy implements CommandRegisterer.Strategy<SlashCommandBuilder> {
private DiscordApi api;
public JavacordRegistererStrategy(DiscordApi api) {
this.api = api;
}
@Override
public void registerServer(ServerCommandList<SlashCommandBuilder> commands) {
api.bulkOverwriteServerApplicationCommands(commands.serverId(), commands);
}
@Override
public void registerGlobal(Set<SlashCommandBuilder> defs) {
api.bulkOverwriteGlobalApplicationCommands(defs);
}
}

View File

@ -1,17 +1,11 @@
package net.tomatentum.marinara.wrapper.javacord;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import org.apache.logging.log4j.Logger;
import org.javacord.api.DiscordApi;
import org.javacord.api.interaction.SlashCommandBuilder;
import org.javacord.api.interaction.SlashCommandOption;
import org.javacord.api.interaction.SlashCommandOptionChoice;
import net.tomatentum.marinara.interaction.commands.SlashCommandDefinition;
import net.tomatentum.marinara.wrapper.CommandConverter;
import net.tomatentum.marinara.wrapper.CommandRegisterer;
import net.tomatentum.marinara.wrapper.ContextObjectProvider;
import net.tomatentum.marinara.wrapper.IdentifierProvider;
import net.tomatentum.marinara.util.LoggerUtil;
@ -22,16 +16,15 @@ import net.tomatentum.marinara.wrapper.javacord.identifierconverter.SlashCommand
public class JavacordWrapper extends LibraryWrapper {
private DiscordApi api;
private JavacordContextObjectProvider contextObjectProvider;
private CommandConverter<SlashCommandBuilder, SlashCommandOption, SlashCommandOptionChoice> commandConverter;
private CommandRegisterer<SlashCommandBuilder> commandRegisterer;
private Logger logger = LoggerUtil.getLogger(getClass());
public JavacordWrapper(DiscordApi api) {
this.api = api;
this.contextObjectProvider = new JavacordContextObjectProvider();
this.commandConverter = CommandConverter.of(new JavacordConverterSpec());
var converter = CommandConverter.of(new JavacordConverterSpec());
this.commandRegisterer = CommandRegisterer.of(new JavacordRegistererStrategy(api), converter);
if (api != null)
api.addInteractionCreateListener((e) -> handleInteraction(e.getInteraction()));
@ -41,24 +34,8 @@ public class JavacordWrapper extends LibraryWrapper {
}
@Override
public void registerSlashCommands(SlashCommandDefinition[] defs) {
HashMap<Long, Set<SlashCommandBuilder>> serverCommands = new HashMap<>();
Set<SlashCommandBuilder> globalCommands = new HashSet<>();
for (SlashCommandDefinition slashCommandDefinition : defs) {
SlashCommandBuilder builder = commandConverter.convert(slashCommandDefinition);
if (slashCommandDefinition.rootIdentifier().serverIds().length > 0) {
for (long serverId : slashCommandDefinition.rootIdentifier().serverIds()) {
serverCommands.putIfAbsent(serverId, new HashSet<>());
serverCommands.get(serverId).add(builder);
}
}else
globalCommands.add(builder);
}
for (long serverId : serverCommands.keySet()) {
api.bulkOverwriteServerApplicationCommands(serverId, serverCommands.get(serverId));
}
api.bulkOverwriteGlobalApplicationCommands(globalCommands);
public CommandRegisterer<?> getRegisterer() {
return this.commandRegisterer;
}
@Override