discord4j.connect.rabbitmq.shared.ExampleRabbitDistributedCacheLeader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of connect-examples Show documentation
Show all versions of connect-examples Show documentation
Distributed Bot Components for Discord4J
/*
* 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 .
*/
package discord4j.connect.rabbitmq.shared;
import discord4j.common.JacksonResources;
import discord4j.connect.Constants;
import discord4j.connect.common.ConnectGatewayOptions;
import discord4j.connect.common.UpstreamGatewayClient;
import discord4j.connect.rabbitmq.ConnectRabbitMQ;
import discord4j.connect.rabbitmq.gateway.RabbitMQPayloadSink;
import discord4j.connect.rabbitmq.gateway.RabbitMQPayloadSource;
import discord4j.connect.rabbitmq.gateway.RabbitMQSinkMapper;
import discord4j.connect.rabbitmq.gateway.RabbitMQSourceMapper;
import discord4j.connect.rsocket.global.RSocketGlobalRateLimiter;
import discord4j.connect.rsocket.router.RSocketRouter;
import discord4j.connect.rsocket.router.RSocketRouterOptions;
import discord4j.connect.rsocket.shard.RSocketShardCoordinator;
import discord4j.connect.support.LogoutHttpServer;
import discord4j.core.DiscordClient;
import discord4j.core.GatewayDiscordClient;
import discord4j.core.event.dispatch.DispatchEventMapper;
import discord4j.core.object.presence.Presence;
import discord4j.core.shard.InvalidationStrategy;
import discord4j.core.shard.ShardingStrategy;
import discord4j.gateway.intent.Intent;
import discord4j.gateway.intent.IntentSet;
import discord4j.store.redis.RedisStoreService;
import io.lettuce.core.RedisClient;
import reactor.util.Logger;
import reactor.util.Loggers;
import java.net.InetSocketAddress;
/**
* An example distributed Discord4J leader, or a node that is capable of connecting to Discord Gateway and routing
* its messages to other nodes, across JVM boundaries.
*
* In particular, this example covers:
*
* - Connecting to a distributed GlobalRateLimiter for API requests
* - Connecting to a distributed Router for API requests
* - Connecting to a distributed ShardCoordinator for connect/IDENTIFY request rate limiting
* - Connecting to a RabbitMQ broker to send and receive messages from other nodes
* - Connecting to a redis server to use it as entity cache, writing every update from the Gateway
*
*/
public class ExampleRabbitDistributedCacheLeader {
public static void main(String[] args) {
/*
* Define the location of the Global Router Server (GRS). A GRS combines coordinated routing across API
* requests while also dealing with the global rate limits.
*
* We will use RSocket GRS in this example: see ExampleRSocketGlobalRouterServer
*/
InetSocketAddress globalRouterServerAddress = new InetSocketAddress(Constants.GLOBAL_ROUTER_SERVER_PORT);
/*
* Define the location of the Shard Coordinator Server (SCS). An SCS establishes predictable ordering across
* multiple leaders attempting to connect to the Gateway.
*
* We will use RSocket SCS in this example: see ExampleRSocket
*/
InetSocketAddress coordinatorServerAddress = new InetSocketAddress(Constants.SHARD_COORDINATOR_SERVER_PORT);
/*
* Define the redis server that will be used as entity cache.
*/
RedisClient redisClient = RedisClient.create(Constants.REDIS_CLIENT_URI);
/*
* Create a default factory for working with Jackson, this can be reused across the application.
*/
JacksonResources jackson = JacksonResources.create();
/*
* Define the sharding strategy. Refer to the class docs for more details or options.
*/
ShardingStrategy shardingStrategy = ShardingStrategy.recommended();
/*
* Define the key resources for working with RabbitMQ.
* - ConnectRabbitMQ defines the parameters to a server
* - RabbitMQSinkMapper will be used to PRODUCE payloads to other nodes
* - "createBinarySinkToDirect" will create binary messages, sent to the "payload" queue directly.
* - RabbitMQSourceMapper will be used to CONSUME payloads from other nodes
* - "createBinarySource" will read binary messages
*/
ConnectRabbitMQ rabbitMQ = ConnectRabbitMQ.createDefault();
RabbitMQSinkMapper sink = RabbitMQSinkMapper.createBinarySinkToDirect("payload");
RabbitMQSourceMapper source = RabbitMQSourceMapper.createBinarySource();
GatewayDiscordClient client = DiscordClient.builder(System.getenv("token"))
.setJacksonResources(jackson)
.setGlobalRateLimiter(RSocketGlobalRateLimiter.createWithServerAddress(globalRouterServerAddress))
.setExtraOptions(o -> new RSocketRouterOptions(o, request -> globalRouterServerAddress))
.build(RSocketRouter::new)
.gateway()
.setSharding(shardingStrategy)
// Properly coordinate IDENTIFY attempts across all shards
.setShardCoordinator(RSocketShardCoordinator.createWithServerAddress(coordinatorServerAddress))
.setDisabledIntents(IntentSet.of(
Intent.GUILD_PRESENCES,
Intent.GUILD_MESSAGE_TYPING,
Intent.DIRECT_MESSAGE_TYPING))
.setInitialStatus(s -> Presence.invisible())
// Disable invalidation strategy and event publishing to save memory usage
.setInvalidationStrategy(InvalidationStrategy.disable())
.setDispatchEventMapper(DispatchEventMapper.discardEvents())
// Define the entity cache
.setStoreService(RedisStoreService.builder()
.redisClient(redisClient)
.useSharedConnection(false)
.build())
// Turn this gateway into a RabbitMQ-based one
.setExtraOptions(o -> new ConnectGatewayOptions(o,
RabbitMQPayloadSink.create(sink, rabbitMQ),
RabbitMQPayloadSource.create(source, rabbitMQ, "gateway")))
// UpstreamGatewayClient connects to Discord Gateway and forwards payloads to other nodes
.login(UpstreamGatewayClient::new)
.blockOptional()
.orElseThrow(RuntimeException::new);
LogoutHttpServer.startAsync(client);
client.onDisconnect().block();
rabbitMQ.close();
}
private static final Logger log = Loggers.getLogger(ExampleRabbitDistributedCacheLeader.class);
}