diff --git a/app/build.gradle b/app/build.gradle index 8efb475..7d465a4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,6 +39,8 @@ dependencies { implementation 'com.discord4j:discord4j-core:3.1.1' implementation 'ch.qos.logback:logback-classic:1.2.3' implementation 'org.postgresql:postgresql:42.2.18.jre7' + implementation 'org.apache.commons:commons-lang3:3.11' + implementation 'net.sf.biweekly:biweekly:0.6.5' } diff --git a/app/src/main/java/xyz/vallat/louis/App.java b/app/src/main/java/xyz/vallat/louis/App.java index 834ff0c..7a22bea 100644 --- a/app/src/main/java/xyz/vallat/louis/App.java +++ b/app/src/main/java/xyz/vallat/louis/App.java @@ -1,8 +1,26 @@ package xyz.vallat.louis; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import xyz.vallat.louis.managers.discord.DiscordManager; + public class App { + private static final Logger logger = LoggerFactory.getLogger(App.class.getCanonicalName()); + public static final String PREFIX = "+"; + public static final String NAME = "PrésencEirb"; + public static final String DESCRIPTION = "Tu as pensé à pointer ?"; + public static final String VERSION = "0.1-SNAPSHOT"; public static void main(String[] args) { + logger.info("Starting {} ver. {}.", NAME, VERSION); + DiscordManager.login(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + logger.info("Received shut down signal. Bye!"); + DiscordManager.logout(); + })); + + DiscordManager.onDisconnect(); } } diff --git a/app/src/main/java/xyz/vallat/louis/commands/Command.java b/app/src/main/java/xyz/vallat/louis/commands/Command.java index 890bc70..b71cd12 100644 --- a/app/src/main/java/xyz/vallat/louis/commands/Command.java +++ b/app/src/main/java/xyz/vallat/louis/commands/Command.java @@ -1,5 +1,57 @@ package xyz.vallat.louis.commands; +import discord4j.core.event.domain.message.MessageCreateEvent; +import discord4j.core.object.reaction.ReactionEmoji; +import discord4j.rest.util.Color; +import org.apache.commons.lang3.RandomStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import java.time.Instant; + public abstract class Command { + protected static final ReactionEmoji WAITING = ReactionEmoji.unicode("⌛"); + private static final Logger logger = LoggerFactory.getLogger(Command.class.getCanonicalName()); + protected final String name; + protected final String description; + protected final String usage; + + protected Command(String name, String description, String usage) { + this.name = name; + this.description = description; + this.usage = usage; + } + + public abstract Mono execute(MessageCreateEvent event); + + public String getUsage() { + return "``" + this.usage + "``"; + } + + public String getDescription() { + return this.description; + } + + public String getName() { + return name; + } + + protected Mono fatalError(MessageCreateEvent event, Throwable throwable) { + return event.getMessage().getChannel().flatMap( + channel -> channel.createEmbed(embed -> { + event.getMessage().removeSelfReaction(WAITING); + String errorCode = RandomStringUtils.random(8, true, true); + logger.error("KERNEL PANIC: {}", errorCode, throwable); + embed.setTitle("KERNEL PANIC").setColor(Color.RED) + .setDescription("A fatal and unhandled error has been encountered. " + + "Please transfer this message to my administrator.") + .addField("IDENTIFIER", errorCode, false).setTimestamp(Instant.now()); + })).then(); + } + + protected String[] getArgArray(MessageCreateEvent event) { + return event.getMessage().getContent().substring(name.length()).split(" "); + } } diff --git a/app/src/main/java/xyz/vallat/louis/commands/Lien.java b/app/src/main/java/xyz/vallat/louis/commands/Lien.java new file mode 100644 index 0000000..973f8da --- /dev/null +++ b/app/src/main/java/xyz/vallat/louis/commands/Lien.java @@ -0,0 +1,20 @@ +package xyz.vallat.louis.commands; + +import discord4j.core.event.domain.message.MessageCreateEvent; +import reactor.core.publisher.Mono; +import xyz.vallat.louis.environment.EnvironmentVariables; + +public class Lien extends Command{ + + public Lien(String name) { + super(name, "Donne le lien vers le moodle de présence.", name); + } + + @Override + public Mono execute(MessageCreateEvent event) { + return event.getMessage().getChannel().flatMap(messageChannel -> messageChannel.createMessage( + event.getMessage().getAuthor().isEmpty() ? "" : + ("<@!" + event.getMessage().getAuthor().get().getId().asString() + "> ") + + System.getenv(EnvironmentVariables.MOODLE_PRESENCE_LINK.getValue()))).then(); + } +} diff --git a/app/src/main/java/xyz/vallat/louis/commands/Subscribe.java b/app/src/main/java/xyz/vallat/louis/commands/Subscribe.java new file mode 100644 index 0000000..34e2f43 --- /dev/null +++ b/app/src/main/java/xyz/vallat/louis/commands/Subscribe.java @@ -0,0 +1,16 @@ +package xyz.vallat.louis.commands; + +import discord4j.core.event.domain.message.MessageCreateEvent; +import reactor.core.publisher.Mono; + +public class Subscribe extends Command { + + public Subscribe(String name) { + super(name, "S'inscrire aux rappels.", name + " "); + } + + @Override + public Mono execute(MessageCreateEvent event) { + return event.getMessage().getChannel().flatMap(messageChannel -> messageChannel.createMessage("Ponnnng!")).then(); + } +} diff --git a/app/src/main/java/xyz/vallat/louis/environment/EnvironmentVariables.java b/app/src/main/java/xyz/vallat/louis/environment/EnvironmentVariables.java index a2384f0..fa21661 100644 --- a/app/src/main/java/xyz/vallat/louis/environment/EnvironmentVariables.java +++ b/app/src/main/java/xyz/vallat/louis/environment/EnvironmentVariables.java @@ -1,17 +1,18 @@ package xyz.vallat.louis.environment; public enum EnvironmentVariables { - DISCORD_TOKEN("DISCORD_TOKEN") + DISCORD_TOKEN("DISCORD_TOKEN"), + MOODLE_PRESENCE_LINK("MOODLE_PRESENCE_LINK") ; - private final String name; + private final String value; EnvironmentVariables(String name) { - this.name = name; + this.value = name; } - public String getName() { - return name; + public String getValue() { + return value; } } diff --git a/app/src/main/java/xyz/vallat/louis/managers/discord/DiscordManager.java b/app/src/main/java/xyz/vallat/louis/managers/discord/DiscordManager.java index f809c92..1f248cd 100644 --- a/app/src/main/java/xyz/vallat/louis/managers/discord/DiscordManager.java +++ b/app/src/main/java/xyz/vallat/louis/managers/discord/DiscordManager.java @@ -1,12 +1,85 @@ package xyz.vallat.louis.managers.discord; +import discord4j.core.DiscordClientBuilder; +import discord4j.core.GatewayDiscordClient; +import discord4j.core.event.domain.lifecycle.ReadyEvent; +import discord4j.core.event.domain.message.MessageCreateEvent; +import discord4j.core.object.entity.User; +import discord4j.core.object.presence.Activity; +import discord4j.core.object.presence.Presence; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import xyz.vallat.louis.commands.Command; +import xyz.vallat.louis.commands.Lien; +import xyz.vallat.louis.commands.Subscribe; +import xyz.vallat.louis.environment.EnvironmentVariables; + +import java.util.ArrayList; +import java.util.List; + +import static xyz.vallat.louis.App.PREFIX; + public class DiscordManager { + private static final List commands = new ArrayList<>(); + private static final Logger logger = LoggerFactory.getLogger(DiscordManager.class.getCanonicalName()); + private static GatewayDiscordClient discordClient; + + static { + commands.add(new Subscribe(PREFIX + "subscribe")); + commands.add(new Lien(PREFIX + "lien")); + } + private DiscordManager() { } - public static void login() { + public static void logout() { + discordClient.logout().block(); + } + private static void registerDiscordCommands() { + for (Command command : commands) + discordClient.getEventDispatcher().on(MessageCreateEvent.class) + .filter(event -> event.getMessage().getAuthor().map(user -> !user.isBot()).orElse(false)) + .filter(event -> event.getMessage().getContent().split(" ")[0].equals(command.getName())) + .flatMap(event -> command.execute(event).then()) + .subscribe(); + } + + public static void login() { + discordClient = DiscordClientBuilder.create(System.getenv(EnvironmentVariables.DISCORD_TOKEN.getValue())) + .build().login().retry(2) + .onErrorMap(throwable -> { + logger.error("Cannot login to Discord right now. Reason: {}", throwable.getMessage()); + return throwable; + } + ).block(); + assert discordClient != null; + setOnline(); + discordClient.getEventDispatcher().on(ReadyEvent.class) + .subscribe(event -> { + User self = event.getSelf(); + logger.info("Logged in on Discord as {}#{}.", self.getUsername(), self.getDiscriminator()); + }); + registerDiscordCommands(); + } + + public static void onDisconnect() { + discordClient.onDisconnect().block(); + } + + public static Mono getGuilds() { + return discordClient.getGuilds().count(); + } + + public static List getCommands() { + return new ArrayList<>(commands); + } + + public static void setOnline() { + if (discordClient != null) + discordClient.updatePresence(Presence.online(Activity.watching("vos emplois du temps"))).subscribe(); } }