Skip to content

Commit

Permalink
Add slash commands to discord4j-rest and discord4j-gateway (#823)
Browse files Browse the repository at this point in the history
* Bump discord-json
* Implement new Routes
* Add ApplicationService functions to get/create/modify/delete commands
* Snowflake -> long for ids
* Add InteractionService, and new webhook routes
* Add a temporary backport of webhook execution functionality
* Handle command gateway events
* Switch to using InteractionCreate, rather than InteractionData
* Add ApplicationCommandOptionType and InteractionResponseType
* Update gradle.properties
* Accommodate suggestions for improving enums
  • Loading branch information
UnderMybrella committed Jan 2, 2021
1 parent 53201ba commit 3d9bf9a
Show file tree
Hide file tree
Showing 14 changed files with 572 additions and 108 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ allprojects {

repositories {
mavenCentral()

if (!isRelease || isJitpack) {
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
maven { url 'https://oss.sonatype.org/content/repositories/staging' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ public abstract class EventNames {
public static final String WEBHOOKS_UPDATE = "WEBHOOKS_UPDATE";
public static final String INVITE_CREATE = "INVITE_CREATE";
public static final String INVITE_DELETE = "INVITE_DELETE";
public static final String APPLICATION_COMMAND_CREATE = "APPLICATION_COMMAND_CREATE";
public static final String APPLICATION_COMMAND_UPDATE = "APPLICATION_COMMAND_UPDATE";
public static final String APPLICATION_COMMAND_DELETE = "APPLICATION_COMMAND_DELETE";
public static final String INTERACTION_CREATE = "INTERACTION_CREATE";

// Ignored
public static final String PRESENCES_REPLACE = "PRESENCES_REPLACE";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package discord4j.gateway.json.jackson;

import discord4j.discordjson.json.InteractionData;
import discord4j.discordjson.json.gateway.*;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
Expand Down Expand Up @@ -75,6 +76,10 @@ public class PayloadDeserializer extends StdDeserializer<GatewayPayload<?>> {
dispatchTypes.put(EventNames.WEBHOOKS_UPDATE, WebhooksUpdate.class);
dispatchTypes.put(EventNames.INVITE_CREATE, InviteCreate.class);
dispatchTypes.put(EventNames.INVITE_DELETE, InviteDelete.class);
dispatchTypes.put(EventNames.APPLICATION_COMMAND_CREATE, ApplicationCommandCreate.class);
dispatchTypes.put(EventNames.APPLICATION_COMMAND_UPDATE, ApplicationCommandUpdate.class);
dispatchTypes.put(EventNames.APPLICATION_COMMAND_DELETE, ApplicationCommandDelete.class);
dispatchTypes.put(EventNames.INTERACTION_CREATE, InteractionCreate.class);

// Ignored
dispatchTypes.put(EventNames.PRESENCES_REPLACE, null);
Expand Down
10 changes: 10 additions & 0 deletions rest/src/main/java/discord4j/rest/RestClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class RestClient {
private final EmojiService emojiService;
private final GatewayService gatewayService;
private final GuildService guildService;
private final InteractionService interactionService;
private final InviteService inviteService;
private final UserService userService;
private final VoiceService voiceService;
Expand Down Expand Up @@ -82,6 +83,7 @@ protected RestClient(final RestResources restResources) {
this.emojiService = new EmojiService(router);
this.gatewayService = new GatewayService(router);
this.guildService = new GuildService(router);
this.interactionService = new InteractionService(router);
this.inviteService = new InviteService(router);
this.userService = new UserService(router);
this.voiceService = new VoiceService(router);
Expand Down Expand Up @@ -403,6 +405,14 @@ public GuildService getGuildService() {
return guildService;
}

/**
* Access a low-level representation of the API endpoints for the Interaction resource.
* @return a handle to perform low-level requests to the API
*/
public InteractionService getInteractionService() {
return interactionService;
}

/**
* Access a low-level representation of the API endpoints for the Invite resource. It is recommended you use
* methods like {@link #getInvite(String)}, or {@link RestInvite#create(RestClient, String)}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public interface ExchangeStrategies {
static ExchangeStrategies jackson(ObjectMapper mapper) {
List<WriterStrategy<?>> writerStrategies = new ArrayList<>();
writerStrategies.add(new MultipartWriterStrategy(mapper));
writerStrategies.add(new WebhookMultipartWriterStrategy(mapper));
writerStrategies.add(new JacksonWriterStrategy(mapper));
writerStrategies.add(new EmptyWriterStrategy());
List<ReaderStrategy<?>> readerStrategies = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public MultipartWriterStrategy(ObjectMapper objectMapper) {

@Override
public boolean canWrite(@Nullable Class<?> type, @Nullable String contentType) {
return contentType != null && contentType.equals("multipart/form-data");
return contentType != null && contentType.equals("multipart/form-data") && type == null || type == MultipartRequest.class;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* This file is part of Discord4J.
*
* Discord4J is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Discord4J 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Discord4J. If not, see <http://www.gnu.org/licenses/>.
*/
package discord4j.rest.http;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import discord4j.discordjson.json.MessageCreateRequest;
import discord4j.discordjson.json.WebhookExecuteRequest;
import discord4j.rest.util.MultipartRequest;
import discord4j.rest.util.WebhookMultipartRequest;
import reactor.core.Exceptions;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.HttpClientForm;
import reactor.util.Logger;
import reactor.util.Loggers;
import reactor.util.annotation.Nullable;
import reactor.util.function.Tuple2;

import java.io.InputStream;
import java.util.List;

/**
* Write to a request from a {@code Consumer<HttpClientRequest.Form>} using reactor-netty's {@link
* HttpClient.RequestSender#sendForm(java.util.function.BiConsumer)}.
*
* Note: This is a hold-over class to backport webhook execute functionality from 3.2.x
*
* @see HttpClientForm
*/
@Deprecated
public class WebhookMultipartWriterStrategy implements WriterStrategy<WebhookMultipartRequest> {

private static final Logger log = Loggers.getLogger(WebhookMultipartWriterStrategy.class);

private final ObjectMapper objectMapper;

public WebhookMultipartWriterStrategy(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}

@Override
public boolean canWrite(@Nullable Class<?> type, @Nullable String contentType) {
return contentType != null && contentType.equals("multipart/form-data") && type == null || type == WebhookMultipartRequest.class;
}

@Override
public Mono<HttpClient.ResponseReceiver<?>> write(HttpClient.RequestSender send, @Nullable WebhookMultipartRequest body) {
if (body == null) {
return Mono.empty(); // or .error() ?
}
final WebhookExecuteRequest executeRequest = body.getExecuteRequest();
final List<Tuple2<String, InputStream>> files = body.getFiles();
return Mono.fromCallable(() -> send.sendForm((request, form) -> {
form.multipart(true);
if (body.getFiles().size() == 1) {
form.file("file", files.get(0).getT1(), files.get(0).getT2(), "application/octet-stream");
} else {
for (int i = 0; i < files.size(); i++) {
form.file("file" + i, files.get(i).getT1(), files.get(i).getT2(), "application/octet-stream");
}
}

if (executeRequest != null) {
try {
String payload = objectMapper.writeValueAsString(executeRequest);
if (log.isTraceEnabled()) {
log.trace("{}", payload);
}
form.attr("payload_json", payload);
} catch (JsonProcessingException e) {
throw Exceptions.propagate(e);
}
}
}));
}
}

0 comments on commit 3d9bf9a

Please sign in to comment.