From 6721dd4f6deedcdf892c1a85250dca69c966b43a Mon Sep 17 00:00:00 2001 From: MysaaJava Date: Fri, 12 Jan 2024 15:58:00 +0100 Subject: [PATCH] =?UTF-8?q?Mise=20=C3=A0=20jour=20du=20bot=20=C3=A0=20une?= =?UTF-8?q?=20version=20de=20JDA=20plus=20r=C3=A9cente,=20et=20ajout=20de?= =?UTF-8?q?=20commentaires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 47 +- .../com/bernard/juliabot/AppelACommande.java | 89 + .../com/bernard/juliabot/CommandCalled.java | 59 - .../bernard/juliabot/CommandeSurchargee.java | 24 +- .../com/bernard/juliabot/EcouteurDEvents.java | 3255 +++++++++++------ src/main/java/com/bernard/juliabot/Julia.java | 956 +++-- .../java/com/bernard/juliabot/JuliaAddon.java | 335 +- .../bernard/juliabot/JuliaErrPrintStream.java | 60 - .../bernard/juliabot/PrintStreamDiscord.java | 184 + .../juliabot/api/ArgumentsComplexes.java | 93 + .../com/bernard/juliabot/api/CCommande.java | 13 +- .../juliabot/api/CCommandeDiscord.java | 60 + .../bernard/juliabot/api/CCommandeString.java | 23 + .../com/bernard/juliabot/api/Command.java | 15 - .../juliabot/api/CommandArguments.java | 45 - .../com/bernard/juliabot/api/Commande.java | 41 + .../com/bernard/juliabot/api/Discord.java | 11 - .../juliabot/api/DiscordCCommande.java | 24 - .../bernard/juliabot/api/EventDiscord.java | 20 + .../java/com/bernard/juliabot/api/Julia.java | 69 + .../com/bernard/juliabot/api/JuliaConfig.java | 40 - .../api/{JuLIAddon.java => Juliaddon.java} | 15 +- .../bernard/juliabot/api/StringCCommande.java | 9 - .../com/bernard/juliabot/api/Trukilie.java | 19 - .../juliabot/internaddon/Internaddon.java | 521 ++- .../juliabot/internaddon/UnstableMessage.java | 36 - upload.sh | 8 + 27 files changed, 4191 insertions(+), 1880 deletions(-) create mode 100644 src/main/java/com/bernard/juliabot/AppelACommande.java delete mode 100644 src/main/java/com/bernard/juliabot/CommandCalled.java delete mode 100644 src/main/java/com/bernard/juliabot/JuliaErrPrintStream.java create mode 100644 src/main/java/com/bernard/juliabot/PrintStreamDiscord.java create mode 100644 src/main/java/com/bernard/juliabot/api/ArgumentsComplexes.java create mode 100644 src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java create mode 100644 src/main/java/com/bernard/juliabot/api/CCommandeString.java delete mode 100644 src/main/java/com/bernard/juliabot/api/Command.java delete mode 100644 src/main/java/com/bernard/juliabot/api/CommandArguments.java create mode 100644 src/main/java/com/bernard/juliabot/api/Commande.java delete mode 100644 src/main/java/com/bernard/juliabot/api/Discord.java delete mode 100644 src/main/java/com/bernard/juliabot/api/DiscordCCommande.java create mode 100644 src/main/java/com/bernard/juliabot/api/EventDiscord.java create mode 100644 src/main/java/com/bernard/juliabot/api/Julia.java delete mode 100644 src/main/java/com/bernard/juliabot/api/JuliaConfig.java rename src/main/java/com/bernard/juliabot/api/{JuLIAddon.java => Juliaddon.java} (65%) delete mode 100644 src/main/java/com/bernard/juliabot/api/StringCCommande.java delete mode 100644 src/main/java/com/bernard/juliabot/api/Trukilie.java delete mode 100644 src/main/java/com/bernard/juliabot/internaddon/UnstableMessage.java create mode 100644 upload.sh diff --git a/build.gradle b/build.gradle index 4a55be4..f0202ce 100644 --- a/build.gradle +++ b/build.gradle @@ -13,11 +13,13 @@ apply plugin: 'java' compileJava.options.encoding = 'UTF-8' -// In this section you declare where to find the dependencies of your project repositories { - // Use jcenter for resolving your dependencies. - // You can declare any Maven/Ivy/file repository here. - jcenter() + mavenCentral() + + maven { + name 'm2-dv8tion' + url 'https://m2.dv8tion.net/releases' + } } sourceSets { @@ -31,7 +33,7 @@ sourceSets { } task apiJar(type: Jar) { - archiveName = "JuliabotAPI.jar" + archiveFileName = "JuliabotAPI.jar" group 'build' description "Fait un jar avec juste l'api" from(sourceSets.main.output) { @@ -40,7 +42,7 @@ task apiJar(type: Jar) { } task internalddonJar(type: Jar) { - archiveName = "JuliabotInternaddon_beta.jar" + archiveFileName = "JuliabotInternaddon_beta.jar" group 'build' description "Fait un jar avec juste l'addon interne" from(sourceSets.main.output) { @@ -51,36 +53,29 @@ task internalddonJar(type: Jar) { task execute(type:JavaExec) { group 'execution' description "Compile et execute le fichier jar" - main = 'com.bernard.juliabot.Julia' + mainClass = 'com.bernard.juliabot.Julia' classpath = sourceSets.main.runtimeClasspath } task copyDependencies(type: Copy) { group 'build' - from configurations.compile + from configurations.default into 'dependencies' } dependencies { - // This dependency is exported to consumers, that is to say found on their compile classpath. - api 'org.apache.commons:commons-math3:3.6.1' + + implementation 'org.slf4j:slf4j-nop:1.7.25' + + implementation 'net.dv8tion:JDA:4.4.0_352' + + implementation 'com.thedeanda:lorem:2.1' + + implementation 'commons-io:commons-io:2.6' + + implementation group: 'org.postgresql', name: 'postgresql', version: '42.2.22' - // This dependency is used internally, and not exposed to consumers on their own compile classpath. - implementation 'com.google.guava:guava:23.0' + implementation 'com.github.mpkorstanje:simmetrics-core:4.1.1' - // Use JUnit test framework - testImplementation 'junit:junit:4.12' - - compile 'org.slf4j:slf4j-nop:1.7.25' - - compile 'net.dv8tion:JDA:4.2.0_189' - - compile 'com.thedeanda:lorem:2.1' - - compile 'commons-io:commons-io:2.6' - - // https://mvnrepository.com/artifact/mysql/mysql-connector-java - compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.21' - } diff --git a/src/main/java/com/bernard/juliabot/AppelACommande.java b/src/main/java/com/bernard/juliabot/AppelACommande.java new file mode 100644 index 0000000..ce28e35 --- /dev/null +++ b/src/main/java/com/bernard/juliabot/AppelACommande.java @@ -0,0 +1,89 @@ +package com.bernard.juliabot; + +import static com.bernard.juliabot.api.Julia.erreur; + +import java.lang.reflect.Method; + +import com.bernard.juliabot.api.CCommande; + +/** + * Objet utilitaire représentant l'appel à une commande, qui suivera l'execution de la + * commande et permet de les gérer dans des threads séparés. + * @author mysaa + * + */ +public class AppelACommande { + + Method called; + CCommande argument; + String name; + String cname; + Object caller; + Thread commandThread; + Throwable exitValue = null; + volatile boolean running; + volatile boolean started; + + /** + * Crée l'objet en spécifiant simplement ses paramètres. + * @param called La méthode qu'il faut appeler pour executer la commande. + * @param argument L'argument à cette méthode, «comment» la commande doit être lancée. + * @param name Le nom de la commande tel qu'il a été demandé. + * @param cname Le nom de la commande l'identifiant, sans alias. + * @param caller L'objet sur lequel doit être invoquée la commande. + */ + public AppelACommande(Method called, CCommande argument, String name, String cname, Object caller) { + this.called = called; + this.argument = argument; + this.name = name; + this.cname = cname; + this.caller = caller; + this.running = true; + } + + + /** + * Définit le therad d'appel de la fonction. + */ + public void setThread(Thread commandThread) { + this.commandThread = commandThread; + } + + /** + * Définit la valeur de retour du programme (un Throwable en java) + * @param t + */ + public void setExitValue(Throwable t) { + this.exitValue = t; + } + + /** + * impose la terminaison de l'execution de la commande. + */ + public void termine() { + running = false; + } + + /** + * Teste si la commande est en cours de résolution + */ + public boolean isRunning() { + return running; + } + + /** + * Met le thread courant en pause jusqu'à ce que la commande soit résolue. + */ + public void waitFin() { + while(running) { + try { + Thread.sleep(42); + } catch (InterruptedException e) { + erreur("On s'est fait intérrompre !",e); + } + } + } + + + +} diff --git a/src/main/java/com/bernard/juliabot/CommandCalled.java b/src/main/java/com/bernard/juliabot/CommandCalled.java deleted file mode 100644 index fe14bab..0000000 --- a/src/main/java/com/bernard/juliabot/CommandCalled.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.bernard.juliabot; - -import java.lang.reflect.Method; - -import com.bernard.juliabot.api.CCommande; - -public class CommandCalled { - - Method called; - CCommande argument; - String name; - String cname; - Object caller; - Thread commandThread; - Throwable exitValue = null; - volatile boolean running; - volatile boolean started; - - public CommandCalled(Method called, CCommande argument, String name, String cname, Object caller) { - this.called = called; - this.argument = argument; - this.name = name; - this.cname = cname; - this.caller = caller; - this.running = true; - } - - - - public void setThread(Thread commandThread) { - this.commandThread = commandThread; - } - - public void setExitValue(Throwable t) { - this.exitValue = t; - } - - public void ended() { - running = false; - } - - public boolean isRunning() { - return running; - } - - public void waitForExecution() { - while(running) { - try { - Thread.sleep(42); - } catch (InterruptedException e) { - System.err.println("Icapacité de pauser le thread : "); - e.printStackTrace(); - } - } - } - - - -} diff --git a/src/main/java/com/bernard/juliabot/CommandeSurchargee.java b/src/main/java/com/bernard/juliabot/CommandeSurchargee.java index 6793d9c..9bc5072 100644 --- a/src/main/java/com/bernard/juliabot/CommandeSurchargee.java +++ b/src/main/java/com/bernard/juliabot/CommandeSurchargee.java @@ -6,25 +6,25 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import com.bernard.juliabot.api.CCommande; -import com.bernard.juliabot.api.Command; +import com.bernard.juliabot.api.Commande; +//TODO la javadoc public class CommandeSurchargee { - String name; - Command command; + String nom; + Commande commande; Map>,Method> versions = new HashMap<>(); - public CommandeSurchargee(Command c) { - this.name = c.name(); - this.command = c; + public CommandeSurchargee(Commande c) { + this.nom = c.name(); + this.commande = c; } - public Method getExecutor(CCommande commande) { + public Method getExecuteur(CCommande commande) { Set> critargs = checkFiliature(Stream.of(commande.getClass()).collect(Collectors.toSet())); - System.out.println("////////"+critargs); return versions.get(versions.keySet().stream().filter(cr -> critargs.containsAll(cr)).findAny().orElse(null)); } @@ -77,11 +77,15 @@ public class CommandeSurchargee { @Override public String toString() { - return "CommandeSurchargee [name=" + name + ", versions=" + versions + "]"; + return "CommandeSurchargee [name=" + nom + ", versions=" + versions + "]"; } public String getDesc() { - return command.description(); + return commande.description(); + } + + public Commande getCommande() { + return commande; } } diff --git a/src/main/java/com/bernard/juliabot/EcouteurDEvents.java b/src/main/java/com/bernard/juliabot/EcouteurDEvents.java index b3d4565..5a18d23 100644 --- a/src/main/java/com/bernard/juliabot/EcouteurDEvents.java +++ b/src/main/java/com/bernard/juliabot/EcouteurDEvents.java @@ -1,37 +1,57 @@ package com.bernard.juliabot; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; +import static com.bernard.juliabot.api.Julia.erreur; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.Array; import java.sql.Connection; -import java.sql.Date; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; import java.sql.Statement; import java.sql.Timestamp; +import java.sql.Types; import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; import java.util.Queue; +import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; import java.util.stream.Collectors; -import com.mysql.cj.jdbc.Blob; +import com.bernard.juliabot.Julia.Laboratoire; +import net.dv8tion.jda.api.entities.AbstractChannel; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.Activity.Emoji; import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.entities.Emote; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.IPermissionHolder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.Message.MessageFlag; +import net.dv8tion.jda.api.entities.MessageActivity; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageReaction; import net.dv8tion.jda.api.entities.MessageReaction.ReactionEmote; +import net.dv8tion.jda.api.entities.MessageSticker; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.RichPresence; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.SelfUser; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.DisconnectEvent; import net.dv8tion.jda.api.events.ExceptionEvent; import net.dv8tion.jda.api.events.GatewayPingEvent; @@ -40,13 +60,12 @@ import net.dv8tion.jda.api.events.RawGatewayEvent; import net.dv8tion.jda.api.events.ReadyEvent; import net.dv8tion.jda.api.events.ShutdownEvent; import net.dv8tion.jda.api.events.StatusChangeEvent; +import net.dv8tion.jda.api.events.application.GenericApplicationCommandEvent; import net.dv8tion.jda.api.events.channel.category.CategoryCreateEvent; import net.dv8tion.jda.api.events.channel.category.CategoryDeleteEvent; import net.dv8tion.jda.api.events.channel.category.GenericCategoryEvent; import net.dv8tion.jda.api.events.channel.category.update.CategoryUpdateNameEvent; import net.dv8tion.jda.api.events.channel.category.update.CategoryUpdatePositionEvent; -import net.dv8tion.jda.api.events.channel.priv.PrivateChannelCreateEvent; -import net.dv8tion.jda.api.events.channel.priv.PrivateChannelDeleteEvent; import net.dv8tion.jda.api.events.channel.store.GenericStoreChannelEvent; import net.dv8tion.jda.api.events.channel.store.StoreChannelCreateEvent; import net.dv8tion.jda.api.events.channel.store.StoreChannelDeleteEvent; @@ -57,6 +76,7 @@ import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent; import net.dv8tion.jda.api.events.channel.text.TextChannelDeleteEvent; import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdateNSFWEvent; import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdateNameEvent; +import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdateNewsEvent; import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdateParentEvent; import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdatePositionEvent; import net.dv8tion.jda.api.events.channel.text.update.TextChannelUpdateSlowmodeEvent; @@ -68,6 +88,7 @@ import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdateBitrate import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdateNameEvent; import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdateParentEvent; import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdatePositionEvent; +import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdateRegionEvent; import net.dv8tion.jda.api.events.channel.voice.update.VoiceChannelUpdateUserLimitEvent; import net.dv8tion.jda.api.events.emote.EmoteAddedEvent; import net.dv8tion.jda.api.events.emote.EmoteRemovedEvent; @@ -80,6 +101,7 @@ import net.dv8tion.jda.api.events.guild.GuildBanEvent; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.events.guild.GuildReadyEvent; +import net.dv8tion.jda.api.events.guild.GuildTimeoutEvent; import net.dv8tion.jda.api.events.guild.GuildUnavailableEvent; import net.dv8tion.jda.api.events.guild.GuildUnbanEvent; import net.dv8tion.jda.api.events.guild.UnavailableGuildJoinedEvent; @@ -92,6 +114,7 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateBoostTimeEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; +import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdatePendingEvent; import net.dv8tion.jda.api.events.guild.override.PermissionOverrideCreateEvent; import net.dv8tion.jda.api.events.guild.override.PermissionOverrideDeleteEvent; import net.dv8tion.jda.api.events.guild.override.PermissionOverrideUpdateEvent; @@ -100,17 +123,19 @@ import net.dv8tion.jda.api.events.guild.update.GuildUpdateAfkTimeoutEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateBannerEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostCountEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateBoostTierEvent; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateCommunityUpdatesChannelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateDescriptionEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateExplicitContentLevelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateFeaturesEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateIconEvent; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateLocaleEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateMFALevelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateMaxMembersEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateMaxPresencesEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateNameEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateNotificationLevelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateOwnerEvent; -import net.dv8tion.jda.api.events.guild.update.GuildUpdateRegionEvent; +import net.dv8tion.jda.api.events.guild.update.GuildUpdateRulesChannelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateSplashEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateSystemChannelEvent; import net.dv8tion.jda.api.events.guild.update.GuildUpdateVanityCodeEvent; @@ -123,10 +148,16 @@ import net.dv8tion.jda.api.events.guild.voice.GuildVoiceJoinEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceLeaveEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMoveEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceMuteEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceRequestToSpeakEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceSelfDeafenEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceSelfMuteEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceStreamEvent; import net.dv8tion.jda.api.events.guild.voice.GuildVoiceSuppressEvent; +import net.dv8tion.jda.api.events.http.HttpRequestEvent; +import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; +import net.dv8tion.jda.api.events.interaction.GenericInteractionCreateEvent; +import net.dv8tion.jda.api.events.interaction.SelectionMenuEvent; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; import net.dv8tion.jda.api.events.message.GenericMessageEvent; import net.dv8tion.jda.api.events.message.MessageBulkDeleteEvent; import net.dv8tion.jda.api.events.message.guild.GenericGuildMessageEvent; @@ -159,103 +190,190 @@ import net.dv8tion.jda.api.events.self.SelfUpdateDiscriminatorEvent; import net.dv8tion.jda.api.events.self.SelfUpdateMFAEvent; import net.dv8tion.jda.api.events.self.SelfUpdateNameEvent; import net.dv8tion.jda.api.events.self.SelfUpdateVerifiedEvent; +import net.dv8tion.jda.api.events.stage.StageInstanceCreateEvent; +import net.dv8tion.jda.api.events.stage.StageInstanceDeleteEvent; +import net.dv8tion.jda.api.events.stage.update.StageInstanceUpdatePrivacyLevelEvent; +import net.dv8tion.jda.api.events.stage.update.StageInstanceUpdateTopicEvent; import net.dv8tion.jda.api.events.user.GenericUserEvent; import net.dv8tion.jda.api.events.user.UserActivityEndEvent; import net.dv8tion.jda.api.events.user.UserActivityStartEvent; import net.dv8tion.jda.api.events.user.UserTypingEvent; +import net.dv8tion.jda.api.events.user.update.UserUpdateActivitiesEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateActivityOrderEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateAvatarEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateDiscriminatorEvent; +import net.dv8tion.jda.api.events.user.update.UserUpdateFlagsEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateNameEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateOnlineStatusEvent; import net.dv8tion.jda.api.hooks.EventListener; +import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.Command.Subcommand; +import net.dv8tion.jda.api.interactions.commands.Command.SubcommandGroup; +import net.dv8tion.jda.api.requests.Response; +/** + * Objet gerant tous les events recus de la jda. + * + * Le travail principal est de les sauvegarder dans la base de données, et + * de déclencher les juliaddons du laboratoire associé à l'event. + * @author mysaa + * + */ public class EcouteurDEvents implements EventListener{ + /** + * File d'attente des events dans la base de données. + */ Queue storeQueue = new ConcurrentLinkedQueue<>(); + /** + * Le thread qui envoie les events de la file d'attente dans la base de données. + */ Thread looper; + /** + * La julia qui a créé cet instance + */ Julia julia; + /** + * Crée un écouteur prêt à l'emploi + * + * Doit nécessairement être appelée après l'initialisation de la base de données. + * @param julia La Julia qui a initié cette écouteur. + */ public EcouteurDEvents(Julia julia) { this.julia = julia; - ResultSet results; - try { - Statement geidS = julia.eventDatabase.createStatement(); - results = geidS.executeQuery("SELECT MAX(GEID) FROM events"); - results.next(); - Long geid = results.getLong(1); - looper = new Thread(new DbLooper(geid),"dbLooper-"+System.nanoTime()); + + looper = new Thread(new DbLooper(),"dbLooper-"+System.nanoTime()); - looper.start(); - } catch (SQLException e) { - System.err.println("IMPOSSIBLE de récuperer le MAX_GEID : L'Écouteur d'évents ne démarera pas"); - e.printStackTrace(); - } + looper.start(); } + /** + * Récupère un event de la JDA et fait deux choses: + * - L'ajoute à la file d'attente pour la base de données + * - L'envoie au laboratoire associé. + */ @Override public void onEvent(GenericEvent event) { storeQueue.add(new PendingEventStore(event,Timestamp.from(Instant.now()))); - this.julia.getLaboratoires().get(getLabo(event)).trigger(event); + getLabo(event).declencher(event); } - public char getLabo(GenericEvent event) { + /** + * Renvoie le laboratoire associé à un event, en déduisant son type. + * @param event L'event à analyser. + * @return Le laboratoire auquel et destiné l'event, le laboratoire par défaut si il est impossible de le déterminer + */ + public Laboratoire getLabo(GenericEvent event) { - if(GenericMessageEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericMessageEvent)event).getChannel().getIdLong()); - if(GenericGuildMessageEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericGuildMessageEvent)event).getChannel().getIdLong()); + // User if(GenericUserEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericUserEvent)event).getUser().getIdLong()); - if(GenericGuildVoiceEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericGuildVoiceEvent)event).getVoiceState().getChannel().getIdLong()); - if(GenericGuildEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericGuildEvent)event).getGuild().getIdLong()); + return g(((GenericUserEvent)event).getUser()); if(GenericPrivateMessageEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericPrivateMessageEvent)event).getChannel().getIdLong()); + return g(((GenericPrivateMessageEvent)event).getChannel().getUser()); - if(event.getClass() == MessageBulkDeleteEvent.class) - return g(((MessageBulkDeleteEvent)event).getChannel().getIdLong()); + // GuildChannel + if(GenericGuildMessageEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericGuildMessageEvent)event).getChannel()); + if(GenericGuildVoiceEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericGuildVoiceEvent)event).getVoiceState().getChannel()); + + // GenericChannel + if(event.getClass() == UserTypingEvent.class) + return gg(((UserTypingEvent)event).getChannel()); if(GenericTextChannelEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericTextChannelEvent)event).getGuild().getIdLong()); + return g(((GenericTextChannelEvent)event).getChannel()); if(GenericVoiceChannelEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericVoiceChannelEvent)event).getGuild().getIdLong()); + return g(((GenericVoiceChannelEvent)event).getChannel()); if(GenericStoreChannelEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericVoiceChannelEvent)event).getGuild().getIdLong()); - if(GenericCategoryEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericCategoryEvent)event).getGuild().getIdLong()); - if(GenericRoleEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericRoleEvent)event).getGuild().getIdLong()); - if(GenericEmoteEvent.class.isAssignableFrom(event.getClass())) - return g(((GenericEmoteEvent)event).getGuild().getIdLong()); - if(event.getClass() == PrivateChannelCreateEvent.class) - return g(((PrivateChannelCreateEvent)event).getUser().getIdLong()); - if(event.getClass() == PrivateChannelDeleteEvent.class) - return g(((PrivateChannelDeleteEvent)event).getUser().getIdLong()); + return g(((GenericStoreChannelEvent)event).getChannel()); + if(GenericInteractionCreateEvent.class.isAssignableFrom(event.getClass())) + return gg(((GenericInteractionCreateEvent)event).getChannel()); + if(GenericMessageEvent.class.isAssignableFrom(event.getClass())) + return gg(((GenericMessageEvent)event).getChannel()); + if(event.getClass() == MessageBulkDeleteEvent.class) + return g(((MessageBulkDeleteEvent)event).getChannel()); - return '#'; + // Guilde + if(GenericGuildEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericGuildEvent)event).getGuild()); + if(GenericCategoryEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericCategoryEvent)event).getGuild()); + if(GenericRoleEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericRoleEvent)event).getGuild()); + if(GenericEmoteEvent.class.isAssignableFrom(event.getClass())) + return g(((GenericEmoteEvent)event).getGuild()); + + + return this.julia.laboParDefaut; } - public Character g(Long id) { - return this.julia.laboratoriesIdentifieurs.getOrDefault(id, '#'); + /** + * Renvoie le laboratoire auquel est destiné un event concernant l'utilisateur donné en paramètre. + */ + private Laboratoire g(User user) { + return this.julia.identifieursDeLabo.getOrDefault(user.getIdLong(), this.julia.laboParDefaut); + } + /** + * Renvoie le laboratoire auquel est destiné un event concernant la guilde donné en paramètre. + */ + private Laboratoire g(Guild gld) { + return this.julia.identifieursDeLabo.getOrDefault(gld, this.julia.laboParDefaut); + } + /** + * Renvoie le laboratoire auquel est destiné un event concernant le canal donné en paramètre. + */ + private Laboratoire g(GuildChannel gchan) { + if(this.julia.identifieursDeLabo.containsKey(gchan.getIdLong())) + return this.julia.identifieursDeLabo.get(gchan.getIdLong()); + return this.julia.identifieursDeLabo.getOrDefault(gchan.getGuild().getIdLong(), this.julia.laboParDefaut); + } + /** + * Renvoie le laboratoire auquel est destiné un event concernant le canal donné en paramètre. + */ + private Laboratoire gg(AbstractChannel mchan) { + switch(mchan.getType()) { + case TEXT: + case VOICE: + case CATEGORY: + case STORE: + return g((GuildChannel)mchan); + case PRIVATE: + return g(((PrivateChannel)mchan).getUser()); + default: + return this.julia.laboParDefaut; + } } + /** + * Runnable enregistrant les events présents dans la file d'attente. + * @author mysaa + * + */ public class DbLooper implements Runnable{ + /** + * L'état actuel de la boucle. + * 1:shouldStop, LSB + * 2:hasStopped + * 3:shouldPause + * 4:hasPaused, HSB + * + */ byte state = 0b0000; - //1:shouldStop, LSB - //2:hasStopped - //3:shouldPause - //4:hasPaused, HSB - public long indexGEID; - public DbLooper(long higherGEID) { - indexGEID = higherGEID+1; - } + /** + * Crée une Loop. + * @param higherGEID Le plus haut geid présent dans la base de données. + */ + public DbLooper() {} + /** + * Teste si le «state» s'execute encore, enregistre l'event sinon + */ @Override public void run() { @@ -266,8 +384,7 @@ public class EcouteurDEvents implements EventListener{ try { Thread.sleep(10); } catch (InterruptedException e) { - System.err.println("Impossible de faire dormir le thread ... On va donc continuer de looper sans pause"); - e.printStackTrace(); + erreur("Le DBLooper s'est fait interrompre !",e); } }else { PendingEventStore pes = storeQueue.poll(); @@ -280,8 +397,7 @@ public class EcouteurDEvents implements EventListener{ try { Thread.sleep(10); } catch (InterruptedException e) { - System.err.println("Impossible de faire dormir le thread ... On va donc continuer de looper sans pause la pause ..."); - e.printStackTrace(); + erreur("La pause du DBLooper s'est fait interrompre !",e); } } /// END PAUSE MODULE @@ -291,1055 +407,2072 @@ public class EcouteurDEvents implements EventListener{ state |= 0b0010; } + /** + * Demande à ce que l'enregistrement des events se mette en pause. + */ public void requestPause() { state |= 0b0100; } + /** + * Demande à ce que l'enregistrement des events reprenne. + */ public void requestPlay() { state &= 0b1011; } + /** + * Demande à ce que l'enregistrement des events s'arrêtte définitivement. + */ public void requestStop() { state |= 0b0001; } + /** + * Teste si l'enregistrement des events est définitivement arrété. + */ public boolean hasStopped() { return (state & 0b0010) == 0; } + /** + * Teste si l'enregistrement est en pause + */ public boolean isPaused() { return (state & 0b1000) == 0; } - - public void storeEvent(GenericEvent e2,Timestamp date) { - if(GenericMessageEvent.class.isAssignableFrom(e2.getClass()))return;//Event non loggé car doublon + /** + * Enregistre l'évenement spécifié dans la base de données. + * @param event L'evenement à enregistrer dans la base de données. + * @param date La date de récéption originelle de l'event, qui peut provenir d'une file d'attente. + */ + public void storeEvent(GenericEvent event,Timestamp date) { + if(GenericMessageEvent.class.isAssignableFrom(event.getClass()))return; //Event non loggé car doublon PreparedStatement s; - Connection db = EcouteurDEvents.this.julia.eventDatabase; + String tbleName = null; + Connection db = EcouteurDEvents.this.julia.juliaBDD; try { - long geid = indexGEID++; + long geid = genId("events.geid"); - PreparedStatement geidS = db.prepareStatement("INSERT INTO events VALUES (?,?,?,?)"); + PreparedStatement geidS = db.prepareStatement("INSERT INTO events.events VALUES (?,?,?,?)"); geidS.setLong(1, geid); geidS.setTimestamp(2, date); - geidS.setLong(3, e2.getResponseNumber()); - geidS.setString(4, e2.getClass().getName()); + geidS.setLong(3, event.getResponseNumber()); + geidS.setString(4, event.getClass().getName()); geidS.executeUpdate(); - switch(e2.getClass().getSimpleName()) { + //System.out.println("Event ! "+event.getClass().getSimpleName()); + switch(event.getClass().getSimpleName()) { + + case "ApplicationCommandCreateEvent": + tbleName = (tbleName==null)?"application_command_create":tbleName; + case "ApplicationCommandDeleteEvent": + tbleName = (tbleName==null)?"application_command_delete":tbleName; + case "ApplicationCommandUpdateEvent": + tbleName = (tbleName==null)?"application_command_update":tbleName; + GenericApplicationCommandEvent eaa = (GenericApplicationCommandEvent)event; + s = db.prepareStatement("INSERT INTO events."+tbleName+" (geid,commande_mid,guild_id) VALUES (?,?,?)"); + + s.setLong(2, storeCommand(eaa.getCommand())); + if(eaa.getGuild()==null) + s.setLong(3,eaa.getGuild().getIdLong()); + else + s.setNull(3, Types.BIGINT); + + break; + case "ButtonClickEvent": + ButtonClickEvent ead = (ButtonClickEvent)event; + s = db.prepareStatement("INSERT INTO events.button_click " + + "(geid,guild_id,channel_type,channel_id,interaction_id,interaction_token,user_id,component_id,message_id)" + + " VALUES (?,?,?::channel_type,?,?,?,?,?,?)"); + + if(ead.getGuild()==null) + s.setLong(2,ead.getGuild().getIdLong()); + else + s.setNull(2, Types.BIGINT); + s.setString(3, ead.getChannelType().name()); + s.setLong(4, ead.getChannel().getIdLong()); + s.setLong(5, ead.getInteraction().getIdLong()); + s.setLong(6, ead.getUser().getIdLong()); + s.setString(7, ead.getComponentId()); + s.setLong(8, ead.getMessageIdLong()); + + break; + case "CategoryCreateEvent": + CategoryCreateEvent eae = (CategoryCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.category_create (geid,guild_id,category_id,category_name) VALUES (?,?,?,?)"); + + s.setLong(2, eae.getGuild().getIdLong()); + s.setLong(3,eae.getIdLong()); + s.setString(4, eae.getCategory().getName()); + + break; + case "CategoryDeleteEvent": + CategoryDeleteEvent eaf = (CategoryDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.category_delete (geid,guild_id,category_id) VALUES (?,?,?)"); + + s.setLong(2, eaf.getGuild().getIdLong()); + s.setLong(3, eaf.getIdLong()); + + break; + case "CategoryUpdateNameEvent": + CategoryUpdateNameEvent eag = (CategoryUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.category_update_name (geid,guild_id,category_id,old_name,new_name) VALUES (?,?,?,?,?)"); + + s.setLong(2, eag.getGuild().getIdLong()); + s.setLong(3, eag.getIdLong()); + s.setString(4, eag.getOldName()); + s.setString(5, eag.getNewName()); + + break; + case "CategoryUpdatePositionEvent": + CategoryUpdatePositionEvent eah = (CategoryUpdatePositionEvent)event; + s = db.prepareStatement("INSERT INTO events.category_update_position (geid,guild_id,category_id,old_position,new_position) VALUES (?,?,?,?,?)"); + + s.setLong(2, eah.getGuild().getIdLong()); + s.setLong(3, eah.getIdLong()); + s.setInt(4, eah.getOldPosition()); + s.setInt(5, eah.getNewPosition()); + + break; + case "DisconnectEvent": + DisconnectEvent eai = (DisconnectEvent)event; + s = db.prepareStatement("INSERT INTO events.disconnect (geid,client_closeframe," + + "server_closeframe,time_disconnected,closed_by_server,closecode) " + + "VALUES (?,?::bit varying,?::bit varying,?,?,?::close_code)"); + + if(eai.getClientCloseFrame() != null) + s.setString(2, bitvarying(eai.getClientCloseFrame().getPayload())); //XXX: T'es sur que ça fonctionne ? + else + s.setNull(2, Types.VARCHAR); + if(eai.getServiceCloseFrame() != null) + s.setString(3, bitvarying(eai.getServiceCloseFrame().getPayload())); + else + s.setNull(3, Types.VARCHAR); + s.setTimestamp(4, timestamp(eai.getTimeDisconnected())); + s.setBoolean(5, eai.isClosedByServer()); + if(eai.getCloseCode() != null) + s.setString(6, eai.getCloseCode().name()); + else + s.setNull(6, Types.VARCHAR); + break; + case "EmoteAddedEvent": + EmoteAddedEvent eaj = (EmoteAddedEvent)event; + s = db.prepareStatement("INSERT INTO events.emote_added (geid,guild_id,emote_mid) VALUES (?,?,?)"); + + s.setLong(2, eaj.getGuild().getIdLong()); + s.setLong(3, storeEmote(eaj.getEmote())); + break; + case "EmoteRemovedEvent": + EmoteRemovedEvent eak = (EmoteRemovedEvent)event; + s = db.prepareStatement("INSERT INTO events.emote_removed (geid,guild_id,emote_mid) VALUES (?,?,?)"); + + s.setLong(2, eak.getGuild().getIdLong()); + s.setLong(3, storeEmote(eak.getEmote())); + break; + case "EmoteUpdateNameEvent": + EmoteUpdateNameEvent eal = (EmoteUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.emote_update_name (geid,guild_id,emote_mid,old_name,new_name) VALUES (?,?,?,?,?)"); + + s.setLong(2, eal.getGuild().getIdLong()); + s.setLong(3, storeEmote(eal.getEmote())); + s.setString(4, eal.getOldName()); + s.setString(5, eal.getNewName()); + break; + case "EmoteUpdateRolesEvent": + EmoteUpdateRolesEvent eam = (EmoteUpdateRolesEvent)event; + s = db.prepareStatement("INSERT INTO events.emote_update_roles (geid,guild_id,emote_mid,old_roles,new_roles) VALUES (?,?,?,?,?)"); + + s.setLong(2, eam.getGuild().getIdLong()); + s.setLong(3, storeEmote(eam.getEmote())); + s.setArray(4, eam.getOldRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + s.setArray(5, eam.getNewRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + break; + case "ExceptionEvent": + ExceptionEvent ean = (ExceptionEvent)event; + s = db.prepareStatement("INSERT INTO events.exception (geid,error_message,error_stacktrace,logged) VALUES (?,?,?,?)"); + + s.setString(2, ean.getCause().getMessage()); + StringWriter sw = new StringWriter(); + ean.getCause().printStackTrace(new PrintWriter(sw)); + s.setString(3, sw.toString()); + s.setBoolean(4, ean.isLogged()); + break; + case "GatewayPingEvent": + GatewayPingEvent eao = (GatewayPingEvent)event; + s = db.prepareStatement("INSERT INTO events.gatewayping (geid,old_ping,new_ping) VALUES (?,?,?)"); + + s.setLong(2, eao.getOldPing()); + s.setLong(3, eao.getNewPing()); + break; + case "GuildAvailableEvent": + GuildAvailableEvent eap = (GuildAvailableEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_available (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, eap.getGuild().getIdLong()); + break; + case "GuildBanEvent": + GuildBanEvent eaq = (GuildBanEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_ban (geid,guild_id,user_id) VALUES (?,?,?)"); + + s.setLong(2, eaq.getGuild().getIdLong()); + s.setLong(3, eaq.getUser().getIdLong()); + break; + case "GuildInviteCreateEvent": + GuildInviteCreateEvent ear = (GuildInviteCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_invite_create (geid,guild_id,code,channel_type,channel_id) VALUES (?,?,?,?::channel_type,?)"); + + s.setLong(2, ear.getGuild().getIdLong()); + s.setString(3, ear.getCode()); + s.setString(4, ear.getChannelType().name()); + s.setLong(5, ear.getChannel().getIdLong()); + break; + case "GuildInviteDeleteEvent": + GuildInviteDeleteEvent eas = (GuildInviteDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_invite_delete (geid,guild_id,code,channel_type,channel_id) VALUES (?,?,?,?::channel_type,?)"); + + s.setLong(2, eas.getGuild().getIdLong()); + s.setString(3, eas.getCode()); + s.setString(4, eas.getChannelType().name()); + s.setLong(5, eas.getChannel().getIdLong()); + break; + case "GuildJoinEvent": + GuildJoinEvent eat = (GuildJoinEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_join (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, eat.getGuild().getIdLong()); + break; + case "GuildLeaveEvent": + GuildLeaveEvent eau = (GuildLeaveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_leave (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, eau.getGuild().getIdLong()); + break; + case "GuildMemberJoinEvent": + GuildMemberJoinEvent eav = (GuildMemberJoinEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_join (geid,guild_id,user_id) VALUES (?,?,?)"); + + s.setLong(2, eav.getGuild().getIdLong()); + s.setLong(3, eav.getUser().getIdLong()); + break; + case "GuildMemberRemoveEvent": + GuildMemberRemoveEvent eaw = (GuildMemberRemoveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_remove (geid,guild_id,user_id) VALUES (?,?,?)"); + + s.setLong(2, eaw.getGuild().getIdLong()); + s.setLong(3, eaw.getUser().getIdLong()); + break; + case "GuildMemberRoleAddEvent": + GuildMemberRoleAddEvent eax = (GuildMemberRoleAddEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_role_add (geid,guild_id,user_id,added_roles) VALUES (?,?,?,?)"); + + s.setLong(2, eax.getGuild().getIdLong()); + s.setLong(3, eax.getUser().getIdLong()); + s.setArray(4, eax.getRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + break; + case "GuildMemberRoleRemoveEvent": + GuildMemberRoleRemoveEvent eay = (GuildMemberRoleRemoveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_role_remove (geid,guild_id,user_id,removed_roles) VALUES (?,?,?,?)"); + + s.setLong(2, eay.getGuild().getIdLong()); + s.setLong(3, eay.getUser().getIdLong()); + s.setArray(4, eay.getRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + break; + case "GuildMemberUpdateBoostTimeEvent": + GuildMemberUpdateBoostTimeEvent eaz = (GuildMemberUpdateBoostTimeEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_update_boosttime (geid,guild_id,user_id,old_timeboosted,new_timeboosted) VALUES (?,?,?,?,?)"); + + s.setLong(2, eaz.getGuild().getIdLong()); + s.setLong(3, eaz.getUser().getIdLong()); + s.setTimestamp(4, timestamp(eaz.getOldTimeBoosted())); + s.setTimestamp(5, timestamp(eaz.getNewTimeBoosted())); + break; + case "GuildMemberUpdateEvent": + + erreur("Je ne sais pas gérer les events GuildMemberUpdateEvent, ils sont trop génériques."); + return; + case "GuildMemberUpdateNicknameEvent": + GuildMemberUpdateNicknameEvent ebb = (GuildMemberUpdateNicknameEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_update_nickname (geid,guild_id,user_id,old_nickname,new_nickname) VALUES (?,?,?,?,?)"); + + s.setLong(2, ebb.getGuild().getIdLong()); + s.setLong(3, ebb.getUser().getIdLong()); + s.setString(4, ebb.getOldNickname()); + s.setString(5, ebb.getNewNickname()); + break; + case "GuildMemberUpdatePendingEvent": + GuildMemberUpdatePendingEvent ebc = (GuildMemberUpdatePendingEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_member_update_pending (geid,guild_id,user_id,old_pending,new_pending) VALUES (?,?,?,?,?)"); + s.setLong(2, ebc.getGuild().getIdLong()); + s.setLong(3, ebc.getUser().getIdLong()); + s.setBoolean(4, ebc.getOldPending()); + s.setBoolean(5, ebc.getNewPending()); + break; + case "GuildMessageDeleteEvent": + GuildMessageDeleteEvent ebd = (GuildMessageDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_delete (geid,guild_id,channel_type,channel_id,message_id) VALUES (?,?,?::channel_type,?,?)"); + + s.setLong(2, ebd.getGuild().getIdLong()); + s.setString(3, ebd.getChannel().getType().name()); + s.setLong(4, ebd.getChannel().getIdLong()); + s.setLong(5, ebd.getMessageIdLong()); + break; + case "GuildMessageEmbedEvent": + GuildMessageEmbedEvent ebe = (GuildMessageEmbedEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_embed (geid,guild_id,channel_type,channel_id,message_id,embeds_mids) VALUES (?,?,?::channel_type,?,?,?)"); + + s.setLong(2, ebe.getGuild().getIdLong()); + s.setString(3, ebe.getChannel().getType().name()); + s.setLong(4, ebe.getChannel().getIdLong()); + s.setLong(5, ebe.getMessageIdLong()); + s.setArray(6, ebe.getMessageEmbeds().stream().map(unex(EcouteurDEvents::storeEmbed)).collect(juliaSqlArrayCollector("bigint"))); + break; + case "GuildMessageReactionAddEvent": + GuildMessageReactionAddEvent ebf = (GuildMessageReactionAddEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_reaction_add " + + "(geid,guild_id,channel_type,channel_id,message_id,user_id,emojimote) VALUES (?,?,?::channel_type,?,?,?,?)"); + + s.setLong(2, ebf.getGuild().getIdLong()); + s.setString(3, ebf.getChannel().getType().name()); + s.setLong(4, ebf.getChannel().getIdLong()); + s.setLong(5, ebf.getMessageIdLong()); + s.setLong(6, ebf.getUserIdLong()); + s.setString(7, reactionEmote(ebf.getReactionEmote())); + + break; + case "GuildMessageReactionRemoveAllEvent": + GuildMessageReactionRemoveAllEvent ebg = (GuildMessageReactionRemoveAllEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_reaction_removeall " + + "(geid,guild_id,channel_type,channel_id,message_id) VALUES (?,?,?::channel_type,?,?)"); + + s.setLong(2, ebg.getGuild().getIdLong()); + s.setString(3, ebg.getChannel().getType().name()); + s.setLong(4, ebg.getChannel().getIdLong()); + s.setLong(5, ebg.getMessageIdLong()); + + break; + case "GuildMessageReactionRemoveEmoteEvent": + GuildMessageReactionRemoveEmoteEvent ebh = (GuildMessageReactionRemoveEmoteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_reaction_remove_emote " + + "(geid,guild_id,channel_type,channel_id,message_id,emojimote) VALUES (?,?,?::channel_type,?,?,?)"); + + s.setLong(2, ebh.getGuild().getIdLong()); + s.setString(3, ebh.getChannel().getType().name()); + s.setLong(4, ebh.getChannel().getIdLong()); + s.setLong(5, ebh.getMessageIdLong()); + s.setString(6, reactionEmote(ebh.getReactionEmote())); + + break; + case "GuildMessageReactionRemoveEvent": + GuildMessageReactionRemoveEvent ebi = (GuildMessageReactionRemoveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_reaction_remove " + + "(geid,guild_id,channel_type,channel_id,message_id,user_id,emojimote) VALUES (?,?,?::channel_type,?,?,?,?)"); + + s.setLong(2, ebi.getGuild().getIdLong()); + s.setString(3, ebi.getChannel().getType().name()); + s.setLong(4, ebi.getChannel().getIdLong()); + s.setLong(5, ebi.getMessageIdLong()); + s.setLong(6, ebi.getUserIdLong()); + s.setString(7, reactionEmote(ebi.getReactionEmote())); + + break; + case "GuildMessageReceivedEvent": + GuildMessageReceivedEvent ebj = (GuildMessageReceivedEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_received " + + "(geid,guild_id,channel_type,channel_id,message_id,message_mid) " + + "VALUES (?,?,?::channel_type,?,?,?)"); + + s.setLong(2, ebj.getGuild().getIdLong()); + s.setString(3, ebj.getChannel().getType().name()); + s.setLong(4, ebj.getChannel().getIdLong()); + s.setLong(5, ebj.getMessageIdLong()); + s.setLong(6, storeMessage(ebj.getMessage())); + break; + case "GuildMessageUpdateEvent": + GuildMessageUpdateEvent ebk = (GuildMessageUpdateEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_message_update (geid,guild_id,channel_type,channel_id,message_id,message_mid) VALUES (?,?,?::channel_type,?,?,?)"); + + s.setLong(2, ebk.getGuild().getIdLong()); + s.setString(3, ebk.getChannel().getType().name()); + s.setLong(4, ebk.getChannel().getIdLong()); + s.setLong(5, ebk.getMessageIdLong()); + s.setLong(6, storeMessage(ebk.getMessage())); + break; + case "GuildReadyEvent": + GuildReadyEvent ebl = (GuildReadyEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_ready (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, ebl.getGuild().getIdLong()); + + break; + case "GuildTimeoutEvent": + GuildTimeoutEvent ebm = (GuildTimeoutEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_timeout (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, ebm.getGuildIdLong()); + + break; + case "GuildUnavailableEvent": + GuildUnavailableEvent ebn = (GuildUnavailableEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_unavailable (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, ebn.getGuild().getIdLong()); + + break; + case "GuildUnbanEvent": + GuildUnbanEvent ebo = (GuildUnbanEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_unban (geid,guild_id,user_id) VALUES (?,?,?)"); + + s.setLong(2, ebo.getGuild().getIdLong()); + s.setLong(3, ebo.getUser().getIdLong()); + + break; + case "GuildUpdateAfkChannelEvent": + GuildUpdateAfkChannelEvent ebp = (GuildUpdateAfkChannelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_afk_channel (geid,guild_id,old_channel_id,new_channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, ebp.getGuild().getIdLong()); + if(ebp.getOldAfkChannel() != null) + s.setLong(3, ebp.getOldAfkChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + if(ebp.getNewAfkChannel() != null) + s.setLong(4, ebp.getNewAfkChannel().getIdLong()); + else + s.setNull(4, Types.BIGINT); + break; + case "GuildUpdateAfkTimeoutEvent": + GuildUpdateAfkTimeoutEvent ebq = (GuildUpdateAfkTimeoutEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_afk_timeout (geid,guild_id,old_timeout,new_timeout) VALUES (?,?,?,?)"); + + s.setLong(2, ebq.getGuild().getIdLong()); + s.setInt(3, ebq.getOldAfkTimeout().getSeconds()); + s.setInt(4, ebq.getNewAfkTimeout().getSeconds()); + break; + case "GuildUpdateBannerEvent": + GuildUpdateBannerEvent ebr = (GuildUpdateBannerEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_banner " + + "(geid, guild_id, old_banner_id, old_banner_url, new_banner_id, new_banner_url) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, ebr.getGuild().getIdLong()); + s.setString(3, ebr.getOldBannerId()); + s.setString(4, ebr.getOldBannerUrl()); + s.setString(5, ebr.getNewBannerId()); + s.setString(6, ebr.getNewBannerUrl()); + break; + case "GuildUpdateBoostCountEvent": + GuildUpdateBoostCountEvent ebs = (GuildUpdateBoostCountEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_boost_count (geid,guild_id,old_count,new_count) VALUES (?,?,?,?)"); + + s.setLong(2, ebs.getGuild().getIdLong()); + s.setInt(3, ebs.getOldBoostCount()); + s.setInt(4, ebs.getNewBoostCount()); + break; + case "GuildUpdateBoostTierEvent": + GuildUpdateBoostTierEvent ebt = (GuildUpdateBoostTierEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_boost_tier (geid,guild_id,old_tier_key,new_tier_key) VALUES (?,?,?,?)"); + + s.setLong(2, ebt.getGuild().getIdLong()); + s.setInt(3, ebt.getOldBoostTier().getKey()); + s.setInt(4, ebt.getNewBoostTier().getKey()); + break; + case "GuildUpdateCommunityUpdatesChannelEvent": + GuildUpdateCommunityUpdatesChannelEvent ebu = (GuildUpdateCommunityUpdatesChannelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_community_updates_channel " + + "(geid,guild_id,old_channel_id,new_channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, ebu.getGuild().getIdLong()); + if(ebu.getOldCommunityUpdatesChannel() != null) + s.setLong(3, ebu.getOldCommunityUpdatesChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + if(ebu.getNewCommunityUpdatesChannel() != null) + s.setLong(4, ebu.getNewCommunityUpdatesChannel().getIdLong()); + else + s.setNull(4, Types.BIGINT); + break; + case "GuildUpdateDescriptionEvent": + GuildUpdateDescriptionEvent ebv = (GuildUpdateDescriptionEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_description (geid,guild_id,old_desc,new_desc) VALUES (?,?,?,?)"); + + s.setLong(2, ebv.getGuild().getIdLong()); + s.setString(3, ebv.getOldDescription()); + s.setString(4, ebv.getNewDescription()); + break; + case "GuildUpdateExplicitContentLevelEvent": + GuildUpdateExplicitContentLevelEvent ebw = (GuildUpdateExplicitContentLevelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_explicit_content_level (geid,guild_id,old_level,new_level) VALUES (?,?,?::explicit_content_level,?::explicit_content_level)"); + + s.setLong(2, ebw.getGuild().getIdLong()); + s.setString(3, ebw.getOldLevel().name()); + s.setString(4, ebw.getNewLevel().name()); + break; + case "GuildUpdateFeaturesEvent": + GuildUpdateFeaturesEvent ebx = (GuildUpdateFeaturesEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_features (geid,guild_id,old_features,new_features) VALUES (?,?,?,?)"); + + s.setLong(2, ebx.getGuild().getIdLong()); + s.setArray(3, ebx.getOldFeatures().stream().collect(juliaSqlArrayCollector("character varying"))); + s.setArray(4, ebx.getNewFeatures().stream().collect(juliaSqlArrayCollector("character varying"))); + break; + case "GuildUpdateIconEvent": + GuildUpdateIconEvent eby = (GuildUpdateIconEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_icon " + + "(geid,guild_id,old_icon_id,old_icon_url,new_icon_id,new_icon_url) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, eby.getGuild().getIdLong()); + s.setString(3, eby.getOldIconId()); + s.setString(4, eby.getOldIconUrl()); + s.setString(5, eby.getNewIconId()); + s.setString(6, eby.getNewIconUrl()); + break; + case "GuildUpdateLocaleEvent": + GuildUpdateLocaleEvent ebz = (GuildUpdateLocaleEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_locale (geid,guild_id,old_locale,new_locale) VALUES (?,?,?,?)"); + + s.setLong(2, ebz.getGuild().getIdLong()); + s.setString(3, ebz.getOldValue().toString()); + s.setString(4, ebz.getNewValue().toString()); + break; + case "GuildUpdateMaxMembersEvent": + GuildUpdateMaxMembersEvent eca = (GuildUpdateMaxMembersEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_max_members (geid,guild_id,old_max,new_max) VALUES (?,?,?,?)"); + + s.setLong(2, eca.getGuild().getIdLong()); + s.setInt(3, eca.getOldMaxMembers()); + s.setInt(4, eca.getNewMaxMembers()); + break; + case "GuildUpdateMaxPresencesEvent": + GuildUpdateMaxPresencesEvent ecb = (GuildUpdateMaxPresencesEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_max_presences (geid,guild_id,old_max,new_max) VALUES (?,?,?,?)"); + + s.setLong(2, ecb.getGuild().getIdLong()); + s.setInt(3, ecb.getOldMaxPresences()); + s.setInt(4, ecb.getNewMaxPresences()); + break; + case "GuildUpdateMFALevelEvent": + GuildUpdateMFALevelEvent ecc = (GuildUpdateMFALevelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_mfa_level (geid,guild_id,old_level,new_level) VALUES (?,?,?::mfa_level,?::mfa_level)"); + + s.setLong(2, ecc.getGuild().getIdLong()); + s.setString(3, ecc.getOldMFALevel().name()); + s.setString(4, ecc.getNewMFALevel().name()); + break; + case "GuildUpdateNameEvent": + GuildUpdateNameEvent ecd = (GuildUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_name (geid,guild_id,old_name,new_name) VALUES (?,?,?,?)"); + + s.setLong(2, ecd.getGuild().getIdLong()); + s.setString(3, ecd.getOldName()); + s.setString(4, ecd.getNewName()); + break; + case "GuildUpdateNotificationLevelEvent": + GuildUpdateNotificationLevelEvent ece = (GuildUpdateNotificationLevelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_notification_level (geid,guild_id,old_level,new_level) VALUES (?,?,?::notification_level,?::notification_level)"); + + s.setLong(2, ece.getGuild().getIdLong()); + s.setString(3, ece.getOldNotificationLevel().name()); + s.setString(4, ece.getNewNotificationLevel().name()); + break; + case "GuildUpdateOwnerEvent": + GuildUpdateOwnerEvent ecf = (GuildUpdateOwnerEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_owner (geid,guild_id,old_user_id,new_user_id) VALUES (?,?,?,?)"); + + s.setLong(2, ecf.getGuild().getIdLong()); + s.setLong(3, ecf.getOldOwnerIdLong()); + s.setLong(4, ecf.getNewOwnerIdLong()); + break; + case "GuildUpdateRulesChannelEvent": + GuildUpdateRulesChannelEvent ecg = (GuildUpdateRulesChannelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_rules_channel (geid,guild_id,old_channel_id,new_channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, ecg.getGuild().getIdLong()); + if(ecg.getOldRulesChannel() != null) + s.setLong(3, ecg.getOldRulesChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + if(ecg.getNewRulesChannel() != null) + s.setLong(4, ecg.getNewRulesChannel().getIdLong()); + else + s.setNull(4, Types.BIGINT); + break; + case "GuildUpdateSplashEvent": + GuildUpdateSplashEvent ech = (GuildUpdateSplashEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_splash " + + "(geid,guild_id,old_splash_id,old_splash_url,new_splash_id,new_splash_url) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, ech.getGuild().getIdLong()); + s.setString(3, ech.getOldSplashId()); + s.setString(4, ech.getOldSplashUrl()); + s.setString(5, ech.getNewSplashId()); + s.setString(6, ech.getNewSplashUrl()); + break; + case "GuildUpdateSystemChannelEvent": + GuildUpdateSystemChannelEvent eci = (GuildUpdateSystemChannelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_system_channel (geid,guild_id,old_channel_id,new_channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, eci.getGuild().getIdLong()); + if(eci.getOldSystemChannel() != null) + s.setLong(3, eci.getOldSystemChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + if(eci.getNewSystemChannel() != null) + s.setLong(4, eci.getNewSystemChannel().getIdLong()); + else + s.setNull(4, Types.BIGINT); + break; + case "GuildUpdateVanityCodeEvent": + GuildUpdateVanityCodeEvent ecj = (GuildUpdateVanityCodeEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_vanity_code (geid,guild_id,old_code,old_url,new_code,new_url) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, ecj.getGuild().getIdLong()); + s.setString(3, ecj.getOldVanityCode()); + s.setString(4, ecj.getOldVanityUrl()); + s.setString(5, ecj.getNewVanityCode()); + s.setString(6, ecj.getNewVanityUrl()); + break; + case "GuildUpdateVerificationLevelEvent": + GuildUpdateVerificationLevelEvent eck = (GuildUpdateVerificationLevelEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_update_verification_level (geid,guild_id,old_level,new_level) VALUES (?,?,?::verification_level,?::verification_level)"); + + s.setLong(2, eck.getGuild().getIdLong()); + s.setString(3, eck.getOldVerificationLevel().name()); + s.setString(4, eck.getNewVerificationLevel().name()); + break; + case "GuildVoiceDeafenEvent": + GuildVoiceDeafenEvent ecl = (GuildVoiceDeafenEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_deafen (geid,guild_id,channel_id,deafened,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecl.getGuild().getIdLong()); + if(ecl.getVoiceState().getChannel() != null) + s.setLong(3, ecl.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecl.isDeafened()); + s.setLong(5, ecl.getMember().getUser().getIdLong()); + break; + case "GuildVoiceGuildDeafenEvent": + GuildVoiceGuildDeafenEvent ecm = (GuildVoiceGuildDeafenEvent)event; + + s = db.prepareStatement("INSERT INTO events.guild_voice_guild_deafen (geid,guild_id,channel_id,guild_deafened,user_id) VALUES (?,?,?,?,?)"); + s.setLong(2, ecm.getGuild().getIdLong()); + if(ecm.getVoiceState().getChannel() != null) + s.setLong(3, ecm.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecm.isGuildDeafened()); + s.setLong(5, ecm.getMember().getUser().getIdLong()); + break; + case "GuildVoiceGuildMuteEvent": + GuildVoiceGuildMuteEvent ecn = (GuildVoiceGuildMuteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_guild_mute (geid,guild_id,channel_id,guild_muted,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecn.getGuild().getIdLong()); + if(ecn.getVoiceState().getChannel() != null) + s.setLong(3, ecn.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecn.isGuildMuted()); + s.setLong(5, ecn.getMember().getUser().getIdLong()); + break; + case "GuildVoiceJoinEvent": + GuildVoiceJoinEvent eco = (GuildVoiceJoinEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_join (geid,guild_id,channel_joined_id,user_id) VALUES (?,?,?,?)"); + + s.setLong(2, eco.getGuild().getIdLong()); + s.setLong(3, eco.getChannelJoined().getIdLong()); + s.setLong(4, eco.getMember().getUser().getIdLong()); + break; + case "GuildVoiceLeaveEvent": + GuildVoiceLeaveEvent ecp = (GuildVoiceLeaveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_leave (geid,guild_id,channel_left_id,user_id) VALUES (?,?,?,?)"); + + s.setLong(2, ecp.getGuild().getIdLong()); + s.setLong(3, ecp.getChannelLeft().getIdLong()); + s.setLong(4, ecp.getMember().getUser().getIdLong()); + break; + case "GuildVoiceMoveEvent": + GuildVoiceMoveEvent ecq = (GuildVoiceMoveEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_move (geid,guild_id,channel_left_id,channel_joined_id,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecq.getGuild().getIdLong()); + s.setLong(3, ecq.getChannelLeft().getIdLong()); + s.setLong(4, ecq.getChannelJoined().getIdLong()); + s.setLong(5, ecq.getMember().getUser().getIdLong()); + break; + case "GuildVoiceMuteEvent": + GuildVoiceMuteEvent ecr = (GuildVoiceMuteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_mute (geid,guild_id,channel_id,muted,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecr.getGuild().getIdLong()); + if(ecr.getVoiceState().getChannel() != null) + s.setLong(3, ecr.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecr.isMuted()); + s.setLong(5, ecr.getMember().getUser().getIdLong()); + break; + case "GuildVoiceRequestToSpeakEvent": + GuildVoiceRequestToSpeakEvent ecs = (GuildVoiceRequestToSpeakEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_request_to_speak (geid,guild_id,channel_id,user_id,old_time,new_time) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, ecs.getGuild().getIdLong()); + if(ecs.getVoiceState().getChannel() != null) + s.setLong(3, ecs.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setLong(4, ecs.getMember().getUser().getIdLong()); + s.setTimestamp(5, timestamp(ecs.getOldTime())); + s.setTimestamp(6, timestamp(ecs.getNewTime())); + break; + case "GuildVoiceSelfDeafenEvent": + GuildVoiceSelfDeafenEvent ect = (GuildVoiceSelfDeafenEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_self_deafen (geid,guild_id,channel_id,self_deafened,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ect.getGuild().getIdLong()); + if(ect.getVoiceState().getChannel() != null) + s.setLong(3, ect.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ect.isSelfDeafened()); + s.setLong(5, ect.getMember().getUser().getIdLong()); + break; + case "GuildVoiceSelfMuteEvent": + GuildVoiceSelfMuteEvent ecu = (GuildVoiceSelfMuteEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_self_mute (geid,guild_id,channel_id,self_muted,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecu.getGuild().getIdLong()); + if(ecu.getVoiceState().getChannel() != null) + s.setLong(3, ecu.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecu.isSelfMuted()); + s.setLong(5, ecu.getMember().getUser().getIdLong()); + break; + case "GuildVoiceStreamEvent": + GuildVoiceStreamEvent ecv = (GuildVoiceStreamEvent)event; + + s = db.prepareStatement("INSERT INTO events.guild_voice_stream (geid,guild_id,channel_id,stream,user_id) VALUES (?,?,?,?,?)"); + s.setLong(2, ecv.getGuild().getIdLong()); + if(ecv.getVoiceState().getChannel() != null) + s.setLong(3, ecv.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecv.isStream()); + s.setLong(5, ecv.getMember().getUser().getIdLong()); + break; + case "GuildVoiceSuppressEvent": + GuildVoiceSuppressEvent ecw = (GuildVoiceSuppressEvent)event; + s = db.prepareStatement("INSERT INTO events.guild_voice_suppress (geid,guild_id,channel_id,suppressed,user_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, ecw.getGuild().getIdLong()); + if(ecw.getVoiceState().getChannel() != null) + s.setLong(3, ecw.getVoiceState().getChannel().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setBoolean(4, ecw.isSuppressed()); + s.setLong(5, ecw.getMember().getUser().getIdLong()); + break; + case "HttpRequestEvent": + HttpRequestEvent ecx = (HttpRequestEvent)event; + s = db.prepareStatement("INSERT INTO events.http_request (geid,http_close_code,response) VALUES (?,?,?)"); + + if(ecx.getResponse() != null) { + Response res = ecx.getResponse(); + s.setInt(2, res.code); + s.setString(3, res.getString()); + res.close(); + } else { + s.setNull(2, Types.INTEGER); + s.setNull(3, Types.VARCHAR); + } + break; + case "MessageBulkDeleteEvent": + MessageBulkDeleteEvent ecy = (MessageBulkDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.message_bulk_delete (geid,guild_id,channel_type,channel_id,deleted_messages_ids) VALUES (?,?,?::channel_type,?,?)"); + + s.setLong(2, ecy.getGuild().getIdLong()); + s.setString(3, ecy.getChannel().getType().name()); + s.setLong(4, ecy.getChannel().getIdLong()); + s.setArray(5, ecy.getMessageIds().stream().map(Long::parseLong).collect(juliaSqlArrayCollector("bigint"))); + break; + case "PermissionOverrideCreateEvent": + PermissionOverrideCreateEvent ecz = (PermissionOverrideCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.permission_override_create " + + "(geid,guild_id,channel_type,channel_id,target_is_role,target_id,perm_allow_raw,perm_deny_raw,perm_inherited_raw)" + + " VALUES (?,?,?::channel_type,?,?,?,?,?,?)"); + + s.setLong(2, ecz.getGuild().getIdLong()); + s.setString(3, ecz.getChannelType().name()); + s.setLong(4, ecz.getChannel().getIdLong()); + s.setBoolean(5, ecz.isRoleOverride()); + if(ecz.getMember() != null) + s.setLong(6, ecz.getMember().getUser().getIdLong()); + else + s.setLong(6, ecz.getRole().getIdLong()); + s.setLong(7, ecz.getPermissionOverride().getAllowedRaw()); + s.setLong(8, ecz.getPermissionOverride().getDeniedRaw()); + s.setLong(9, ecz.getPermissionOverride().getInheritRaw()); + break; - - ////////// Events ////////// - case "DisconnectEvent": - DisconnectEvent e4 = (DisconnectEvent)e2; - s = db.prepareStatement("INSERT INTO disconnectEvent VALUES (?,?,?,?,?,?)"); - s.setBlob(2, new Blob((e4.getClientCloseFrame()==null)?new byte[0]:((e4.getClientCloseFrame().getPayload())== null?new byte[0]:e4.getClientCloseFrame().getPayload()),null)); - s.setString(3, (e4.getCloseCode()==null)?null:e4.getCloseCode().name()); - s.setDate(4, new java.sql.Date(e4.getTimeDisconnected().toEpochSecond())); - s.setBlob(5, new Blob((e4.getServiceCloseFrame().getPayload()==null)?new byte[0]:e4.getServiceCloseFrame().getPayload(),null)); - s.setBoolean(6, e4.isClosedByServer()); - break; + case "PermissionOverrideDeleteEvent": + PermissionOverrideDeleteEvent eda = (PermissionOverrideDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.permission_override_delete " + + "(geid,guild_id,channel_type,channel_id,target_is_role,target_id,perm_allow_raw,perm_deny_raw,perm_inherited_raw) " + + "VALUES (?,?,?::channel_type,?,?,?,?,?,?)"); - case "ExceptionEvent": - ExceptionEvent e5 = (ExceptionEvent)e2; - s = db.prepareStatement("INSERT INTO exceptionEvent VALUES (?,?,?,?,?,?,?)"); - s.setString(2, e5.getCause().getClass().getName()); - s.setString(3, e5.getCause().getMessage()); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (PrintStream ps = new PrintStream(baos, true, "UTF-8")) { - e5.getCause().printStackTrace(ps); - } catch (UnsupportedEncodingException error) { - error.printStackTrace(); - - } - s.setString(4, new String(baos.toByteArray(), StandardCharsets.UTF_8)); - s.setBoolean(5, e5.isLogged()); - break; - - case "ReadyEvent": - ReadyEvent e6 = (ReadyEvent)e2; - s = db.prepareStatement("INSERT INTO readyEvent VALUES (?,?,?)"); - s.setInt(2, e6.getGuildAvailableCount()); - s.setInt(3, e6.getGuildUnavailableCount()); - break; - case "ResumedEvent": - s = db.prepareStatement("INSERT INTO resumedEvent VALUES (?)"); - break; - case "ReconnectedEvent": - s = db.prepareStatement("INSERT INTO reconnectedEvent VALUES (?)"); - break; - case "ShutdownEvent": - ShutdownEvent e7 = (ShutdownEvent)e2; - s = db.prepareStatement("INSERT INTO shutdownEvent VALUES (?,?,?)"); - s.setTimestamp(2, new Timestamp(e7.getTimeShutdown().toEpochSecond())); - s.setString(3, e7.getCloseCode().name()); - break; - case "StatusChangeEvent": - StatusChangeEvent e8 = (StatusChangeEvent)e2; - s = db.prepareStatement("INSERT INTO statusChangeEvent VALUES (?,?,?,?)"); - s.setString(2, e8.getPropertyIdentifier()); - s.setString(3, e8.getOldStatus().name()); - s.setString(4, e8.getNewStatus().name()); - break; - - case "RawGatewayEvent": - RawGatewayEvent e8a = (RawGatewayEvent)e2; - s = db.prepareStatement("INSERT INTO rawGatewayEvent VALUES (?,?,?)"); - s.setString(2, e8a.getType()); - s.setString(3, new String(e8a.getPayload().toJson())); - break; - - case "GatewayPingEvent": - GatewayPingEvent e8b = (GatewayPingEvent)e2; - s = db.prepareStatement("INSERT INTO gatewayPingEvent VALUES (?,?,?,?)"); - s.setString(2, e8b.getPropertyIdentifier()); - s.setLong(3, e8b.getOldPing()); - s.setLong(4, e8b.getNewPing()); - break; - - case "MessageBulkDeleteEvent": - MessageBulkDeleteEvent e8c = (MessageBulkDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO messageBulkDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e8c.getChannel().getIdLong()); - s.setString(3, e8c.getMessageIds().stream().collect(Collectors.joining(","))); - break; - - case "UnavailableGuildJoinedEvent": - UnavailableGuildJoinedEvent e35a = (UnavailableGuildJoinedEvent)e2; - s = db.prepareStatement("INSERT INTO unavailableGuildJoinedEvent VALUES (?,?)"); - s.setLong(2, e35a.getGuildIdLong()); - break; - case "UnavailableGuildLeaveEvent": - UnavailableGuildLeaveEvent e35b = (UnavailableGuildLeaveEvent)e2; - s = db.prepareStatement("INSERT INTO unavailableGuildJoinedEvent VALUES (?,?)"); - s.setLong(2, e35b.getGuildIdLong()); - break; + s.setLong(2, eda.getGuild().getIdLong()); + s.setString(3, eda.getChannelType().name()); + s.setLong(4, eda.getChannel().getIdLong()); + s.setBoolean(5, eda.isRoleOverride()); + if(eda.getMember() != null) + s.setLong(6, eda.getMember().getUser().getIdLong()); + else + s.setLong(6, eda.getRole().getIdLong()); + s.setLong(7, eda.getPermissionOverride().getAllowedRaw()); + s.setLong(8, eda.getPermissionOverride().getDeniedRaw()); + s.setLong(9, eda.getPermissionOverride().getInheritRaw()); + break; + case "PermissionOverrideUpdateEvent": + PermissionOverrideUpdateEvent edb = (PermissionOverrideUpdateEvent)event; + s = db.prepareStatement("INSERT INTO events.permission_override_update " + + "(geid,guild_id,channel_type,channel_id,target_is_role,target_id," + + "old_perm_allow_raw,old_perm_deny_raw,old_perm_inherited_raw," + + "new_perm_allow_raw,new_perm_deny_raw,new_perm_inherited_raw) " + + "VALUES (?,?,?::channel_type,?,?,?,?,?,?,?,?,?)"); - - - ////////// GenericSelfUpdateEvent ////////// - case "SelfUpdateAvatarEvent": - SelfUpdateAvatarEvent e9 = (SelfUpdateAvatarEvent)e2; - s = db.prepareStatement("INSERT INTO selfUpdateAvatarEvent VALUES (?,?,?,?)"); - s.setLong(2, addSelfUser(e9.getSelfUser(), db)); - s.setString(3, e9.getOldAvatarUrl()); - s.setString(4, e9.getNewAvatarUrl()); - break; - case "SelfUpdateDiscriminatorEvent": - SelfUpdateDiscriminatorEvent e10 = (SelfUpdateDiscriminatorEvent)e2; - s = db.prepareStatement("INSERT INTO selfUpdateDiscriminatorEvent VALUES (?,?,?,?)"); - s.setLong(2, addSelfUser(e10.getSelfUser(), db)); - s.setString(3, e10.getOldDiscriminator()); - s.setString(4, e10.getNewDiscriminator()); - break; - case "SelfUpdateMFAEvent": - SelfUpdateMFAEvent e14 = (SelfUpdateMFAEvent)e2; - s = db.prepareStatement("INSERT INTO selfUpdateMFAEvent VALUES (?,?,?)"); - s.setLong(2, addSelfUser(e14.getSelfUser(), db)); - s.setBoolean(3, e14.wasMfaEnabled()); - break; - case "SelfUpdateNameEvent": - SelfUpdateNameEvent e12 = (SelfUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO selfUpdateNameEvent VALUES (?,?,?,?)"); - s.setLong(2, addSelfUser(e12.getSelfUser(), db)); - s.setString(3, e12.getOldName()); - s.setString(4, e12.getNewName()); - break; - case "SelfUpdateVerifiedEvent": - SelfUpdateVerifiedEvent e17 = (SelfUpdateVerifiedEvent)e2; - s = db.prepareStatement("INSERT INTO selfUpdateVerifiedEvent VALUES (?,?,?)"); - s.setLong(2, addSelfUser(e17.getSelfUser(), db)); - s.setBoolean(3, e17.wasVerified()); - break; + s.setLong(2, edb.getGuild().getIdLong()); + s.setString(3, edb.getChannelType().name()); + s.setLong(4, edb.getChannel().getIdLong()); + s.setBoolean(5, edb.isRoleOverride()); + if(edb.getMember() != null) + s.setLong(6, edb.getMember().getUser().getIdLong()); + else + s.setLong(6, edb.getRole().getIdLong()); + s.setLong(7, edb.getOldAllowRaw()); + s.setLong(8, edb.getOldDenyRaw()); + s.setLong(9, edb.getOldInheritedRaw()); + s.setLong(10, edb.getPermissionOverride().getAllowedRaw()); + s.setLong(11, edb.getPermissionOverride().getDeniedRaw()); + s.setLong(12, edb.getPermissionOverride().getInheritRaw()); + break; + case "PrivateMessageDeleteEvent": + PrivateMessageDeleteEvent edc = (PrivateMessageDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_delete (geid,channel_id,message_id) VALUES (?,?,?)"); - - ////////// GenericUserEvent ////////// - case "UserTypingEvent": - UserTypingEvent e18 = (UserTypingEvent)e2; - s = db.prepareStatement("INSERT INTO userTypingEvent VALUES (?,?,?,?)"); - s.setLong(2, e18.getUser().getIdLong()); - s.setLong(3, e18.getGuild().getIdLong()); - s.setLong(4, e18.getChannel().getIdLong()); - break; - case "UserUpdateNameEvent": - UserUpdateNameEvent e19 = (UserUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO userUpdateNameEvent VALUES (?,?,?,?)"); - s.setLong(2, e19.getUser().getIdLong()); - s.setString(3, e19.getOldName()); - s.setString(4, e19.getNewName()); - break; - case "UserUpdateDiscriminatorEvent": - UserUpdateDiscriminatorEvent e20 = (UserUpdateDiscriminatorEvent)e2; - s = db.prepareStatement("INSERT INTO userUpdateDiscriminatorEvent VALUES (?,?,?,?)"); - s.setLong(2, e20.getUser().getIdLong()); - s.setString(3, e20.getOldDiscriminator()); - s.setString(4, e20.getNewDiscriminator()); - break; - case "UserUpdateAvatarEvent": - UserUpdateAvatarEvent e21 = (UserUpdateAvatarEvent)e2; - s = db.prepareStatement("INSERT INTO userUpdateAvatarEvent VALUES (?,?,?,?)"); - s.setLong(2, e21.getUser().getIdLong()); - s.setString(3, e21.getOldAvatarUrl()); - s.setString(4, e21.getNewAvatarUrl()); - break; + s.setLong(2, edc.getChannel().getIdLong()); + s.setLong(3, edc.getMessageIdLong()); + + break; + case "PrivateMessageEmbedEvent": + PrivateMessageEmbedEvent edd = (PrivateMessageEmbedEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_embed (geid,channel_id,message_id,embeds) VALUES (?,?,?,?)"); - case "UserUpdateOnlineStatusEvent": - UserUpdateOnlineStatusEvent e23 = (UserUpdateOnlineStatusEvent)e2; - s = db.prepareStatement("INSERT INTO userUpdateOnlineStatusEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e23.getUser().getIdLong()); - s.setLong(3, e23.getGuild().getIdLong()); - s.setObject(4, e23.getOldOnlineStatus().name()); - s.setObject(5, e23.getNewOnlineStatus().name()); - break; - - case "UserUpdateActivityOrderEvent": - UserUpdateActivityOrderEvent e110= (UserUpdateActivityOrderEvent)e2; - s = db.prepareStatement("INSERT INTO userUpdateActivityOrderEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e110.getUser().getIdLong()); - s.setLong(3, e110.getGuild().getIdLong()); - s.setLong(4, addActivityList(e110.getOldValue(),db)); - s.setLong(5, addActivityList(e110.getNewValue(),db)); - break; - case "UserActivityStartEvent": - UserActivityStartEvent e111= (UserActivityStartEvent)e2; - s = db.prepareStatement("INSERT INTO userActivityStartEvent VALUES (?,?,?,?)"); - s.setLong(2, e111.getUser().getIdLong()); - s.setLong(3, e111.getGuild().getIdLong()); - s.setLong(4, addActivity(e111.getNewActivity(),db)); - break; - case "UserActivityEndEvent": - UserActivityEndEvent e112= (UserActivityEndEvent)e2; - s = db.prepareStatement("INSERT INTO userActivityEndEvent VALUES (?,?,?,?)"); - s.setLong(2, e112.getUser().getIdLong()); - s.setLong(3, e112.getGuild().getIdLong()); - s.setLong(4, addActivity(e112.getOldActivity(),db)); - break; + s.setLong(2, edd.getChannel().getIdLong()); + s.setLong(3, edd.getMessageIdLong()); + s.setArray(4, edd.getMessageEmbeds().stream().map(unex(EcouteurDEvents::storeEmbed)).collect(juliaSqlArrayCollector("bigint"))); + break; + case "PrivateMessageReactionAddEvent": + PrivateMessageReactionAddEvent ede = (PrivateMessageReactionAddEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_reaction_add (geid,channel_id,message_id,user_id,emojimote) VALUES (?,?,?,?,?)"); - - ////////// GenericPrivateMessageEvent ////////// - case "PrivateMessageDeleteEvent": - PrivateMessageDeleteEvent e24 = (PrivateMessageDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO privateMessageDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e24.getChannel().getIdLong()); - s.setLong(3, e24.getMessageIdLong()); - break; - case "PrivateMessageEmbedEvent": - PrivateMessageEmbedEvent e25 = (PrivateMessageEmbedEvent)e2; - addEmbedMessage(geid, e25.getMessageEmbeds(), db); - s = db.prepareStatement("INSERT INTO privateMessageEmbedEvent VALUES (?,?,?)"); - s.setLong(2, e25.getChannel().getIdLong()); - s.setLong(3, e25.getMessageIdLong()); - break; - case "PrivateMessageReceivedEvent": - PrivateMessageReceivedEvent e26 = (PrivateMessageReceivedEvent)e2; - int mID26 = addMessage(e26.getMessage(), db); - s = db.prepareStatement("INSERT INTO privateMessageReceivedEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e26.getAuthor().getIdLong()); - s.setLong(3, e26.getChannel().getIdLong()); - s.setLong(4, e26.getMessageIdLong()); - s.setInt(5, mID26); - break; - case "PrivateMessageUpdateEvent": - PrivateMessageUpdateEvent e27 = (PrivateMessageUpdateEvent)e2; - int mID27 = addMessage(e27.getMessage(), db); - s = db.prepareStatement("INSERT INTO privateMessageUpdateEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e27.getAuthor().getIdLong()); - s.setLong(3, e27.getChannel().getIdLong()); - s.setLong(4, e27.getMessageIdLong()); - s.setInt(5, mID27); - break; - case "PrivateMessageReactionAddEvent": - PrivateMessageReactionAddEvent e28 = (PrivateMessageReactionAddEvent)e2; - int mID28 = addMessageReaction(e28.getReaction(), db); - s = db.prepareStatement("INSERT INTO privateMessageReactionAddEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e28.getChannel().getIdLong()); - s.setLong(3, e28.getMessageIdLong()); - s.setLong(4, e28.getUser().getIdLong()); - s.setInt(5, mID28); - break; - case "PrivateMessageReactionRemoveEvent": - PrivateMessageReactionRemoveEvent e29 = (PrivateMessageReactionRemoveEvent)e2; - int mID29 = addMessageReaction(e29.getReaction(), db); - s = db.prepareStatement("INSERT INTO privateMessageReactionRemoveEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e29.getChannel().getIdLong()); - s.setLong(3, e29.getMessageIdLong()); - s.setLong(4, e29.getUser().getIdLong()); - s.setInt(5, mID29); - break; - - - ////////// GenericGuildEvent ////////// - case "GuildReadyEvent": - GuildReadyEvent e30 = (GuildReadyEvent)e2; - s = db.prepareStatement("INSERT INTO guildReadyEvent VALUES (?,?)"); - s.setLong(2, e30.getGuild().getIdLong()); - break; - case "GuildAvailableEvent": - GuildAvailableEvent e31 = (GuildAvailableEvent)e2; - s = db.prepareStatement("INSERT INTO guildAvailableEvent VALUES (?,?)"); - s.setLong(2, e31.getGuild().getIdLong()); - break; - case "GuildBanEvent": - GuildBanEvent e32 = (GuildBanEvent)e2; - s = db.prepareStatement("INSERT INTO guildBanEvent VALUES (?,?,?)"); - s.setLong(2, e32.getGuild().getIdLong()); - s.setLong(3, e32.getUser().getIdLong()); - break; - case "GuildJoinEvent": - GuildJoinEvent e33 = (GuildJoinEvent)e2; - s = db.prepareStatement("INSERT INTO guildJoinEvent VALUES (?,?)"); - s.setLong(2, e33.getGuild().getIdLong()); - break; - case "GuildLeaveEvent": - GuildLeaveEvent e34 = (GuildLeaveEvent)e2; - s = db.prepareStatement("INSERT INTO guildLeaveEvent VALUES (?,?)"); - s.setLong(2, e34.getGuild().getIdLong()); - break; - case "GuildUnavailableEvent": - GuildUnavailableEvent e35 = (GuildUnavailableEvent)e2; - s = db.prepareStatement("INSERT INTO guildUnavailableEvent VALUES (?,?)"); - s.setLong(2, e35.getGuild().getIdLong()); - break; - case "GuildUnbanEvent": - GuildUnbanEvent e36 = (GuildUnbanEvent)e2; - s = db.prepareStatement("INSERT INTO guildUnanEvent VALUES (?,?,?)"); - s.setLong(2, e36.getGuild().getIdLong()); - s.setLong(3, e36.getUser().getIdLong()); - break; - - case "GuildInviteCreateEvent": - GuildInviteCreateEvent e113 = (GuildInviteCreateEvent)e2; - s = db.prepareStatement("INSERT INTO guildInviteCreateEvent VALUES (?,?,?,?,?,?)"); - s.setLong(2, e113.getGuild().getIdLong()); - s.setString(3, e113.getChannelType().name()); - s.setLong(4, e113.getChannel().getIdLong()); - s.setString(5, e113.getInvite().getCode()); - s.setLong(6, e113.getInvite().getInviter()==null?null:e113.getInvite().getInviter().getIdLong()); - break; - - case "GuildInviteDeleteEvent": - GuildInviteDeleteEvent e114 = (GuildInviteDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO guildInviteDeleteEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e114.getGuild().getIdLong()); - s.setString(3, e114.getChannelType().name()); - s.setLong(4, e114.getChannel().getIdLong()); - s.setString(5, e114.getCode()); - break; + s.setLong(2, ede.getChannel().getIdLong()); + s.setLong(3, ede.getMessageIdLong()); + s.setLong(4, ede.getUserIdLong()); + s.setString(5, messageReaction(ede.getReaction())); + break; + case "PrivateMessageReactionRemoveEvent": + PrivateMessageReactionRemoveEvent edf = (PrivateMessageReactionRemoveEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_reaction_remove (geid,channel_id,message_id,user_id,emojimote) VALUES (?,?,?,?,?)"); - case "GuildMessageDeleteEvent": - GuildMessageDeleteEvent e37 = (GuildMessageDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO guildMessageDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e37.getChannel().getIdLong()); - s.setLong(3, e37.getMessageIdLong()); - break; - case "GuildMessageEmbedEvent": - GuildMessageEmbedEvent e38 = (GuildMessageEmbedEvent)e2; - addEmbedMessage(geid, e38.getMessageEmbeds(), db); - s = db.prepareStatement("INSERT INTO guildMessageEmbedEvent VALUES (?,?,?)"); - s.setLong(2, e38.getChannel().getIdLong()); - s.setLong(3, e38.getMessageIdLong()); - break; - case "GuildMessageReceivedEvent": - GuildMessageReceivedEvent e39 = (GuildMessageReceivedEvent)e2; - int mID39 = addMessage(e39.getMessage(), db); - s = db.prepareStatement("INSERT INTO guildMessageReceivedEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e39.getAuthor().getIdLong()); - s.setLong(3, e39.getChannel().getIdLong()); - s.setLong(4, e39.getMessageIdLong()); - s.setInt(5, mID39); - break; - case "GuildMessageUpdateEvent": - GuildMessageUpdateEvent e40 = (GuildMessageUpdateEvent)e2; - int mID40 = addMessage(e40.getMessage(), db); - s = db.prepareStatement("INSERT INTO guildMessageUpdateEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e40.getAuthor().getIdLong()); - s.setLong(3, e40.getChannel().getIdLong()); - s.setLong(4, e40.getMessageIdLong()); - s.setInt(5, mID40); - break; - case "GuildMessageReactionRemoveAllEvent": - GuildMessageReactionRemoveAllEvent e40b = (GuildMessageReactionRemoveAllEvent)e2; - s = db.prepareStatement("INSERT INTO guildMessageReactionRemoveAllEvent VALUES (?,?,?)"); - s.setLong(2, e40b.getChannel().getIdLong()); - s.setLong(3, e40b.getMessageIdLong()); - break; - case "GuildMessageReactionRemoveEmoteEvent": - GuildMessageReactionRemoveEmoteEvent e40c = (GuildMessageReactionRemoveEmoteEvent)e2; - s = db.prepareStatement("INSERT INTO guildMessageReactionRemoveEmoteEvent VALUES (?,?,?)"); - s.setLong(2, e40c.getChannel().getIdLong()); - s.setLong(3, e40c.getMessageIdLong()); - s.setString(4, rEmote(e40c.getReactionEmote())); - break; + s.setLong(2, edf.getChannel().getIdLong()); + s.setLong(3, edf.getMessageIdLong()); + s.setLong(4, edf.getUserIdLong()); + s.setString(5, messageReaction(edf.getReaction())); + break; + case "PrivateMessageReceivedEvent": + PrivateMessageReceivedEvent edg = (PrivateMessageReceivedEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_received (geid,channel_id,message_id,message_mid) VALUES (?,?,?,?)"); - case "GuildMessageReactionAddEvent": - GuildMessageReactionAddEvent e41 = (GuildMessageReactionAddEvent)e2; - int mID41 = addMessageReaction(e41.getReaction(), db); - s = db.prepareStatement("INSERT INTO guildMessageReactionAddEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e41.getChannel().getIdLong()); - s.setLong(3, e41.getMessageIdLong()); - s.setLong(4, e41.getUser().getIdLong()); - s.setInt(5, mID41); - break; - case "GuildMessageReactionRemoveEvent": - GuildMessageReactionRemoveEvent e42 = (GuildMessageReactionRemoveEvent)e2; - int mID42 = addMessageReaction(e42.getReaction(), db); - s = db.prepareStatement("INSERT INTO guildMessageReactionRemoveEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e42.getChannel().getIdLong()); - s.setLong(3, e42.getMessageIdLong()); - s.setLong(4, e42.getUser().getIdLong()); - s.setInt(5, mID42); - break; + s.setLong(2, edg.getChannel().getIdLong()); + s.setLong(3,edg.getMessageIdLong()); + s.setLong(4, storeMessage(edg.getMessage())); + break; + case "PrivateMessageUpdateEvent": + PrivateMessageUpdateEvent edh = (PrivateMessageUpdateEvent)event; + s = db.prepareStatement("INSERT INTO events.private_message_update (geid,channel_id,message_id,message_mid) VALUES (?,?,?,?)"); - case "GuildUpdateAfkChannelEvent": - GuildUpdateAfkChannelEvent e43 = (GuildUpdateAfkChannelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateAfkChannelEvent VALUES (?,?,?,?)"); - s.setLong(2, e43.getGuild().getIdLong()); - s.setLong(3, e43.getOldAfkChannel().getIdLong()); - s.setLong(4, e43.getNewAfkChannel().getIdLong()); - break; - case "GuildUpdateAfkTimeoutEvent": - GuildUpdateAfkTimeoutEvent e44 = (GuildUpdateAfkTimeoutEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateAfkTimeoutEvent VALUES (?,?,?,?)"); - s.setLong(2, e44.getGuild().getIdLong()); - s.setString(3, e44.getOldAfkTimeout().name()); - s.setString(4, e44.getNewAfkTimeout().name()); - break; - case "GuildUpdateExplicitContentLevelEvent": - GuildUpdateExplicitContentLevelEvent e45 = (GuildUpdateExplicitContentLevelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateExplicitContentLevelEvent VALUES (?,?,?,?)"); - s.setLong(2, e45.getGuild().getIdLong()); - s.setString(3, e45.getOldLevel().name()); - s.setString(4, e45.getNewLevel().name()); - break; - case "GuildUpdateFeaturesEvent": - GuildUpdateFeaturesEvent e46 = (GuildUpdateFeaturesEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateFeaturesEvent VALUES (?,?,?,?)"); - s.setLong(2, e46.getGuild().getIdLong()); - s.setString(3, String.join(",",e46.getOldFeatures())); - s.setString(4, String.join(",",e46.getNewFeatures())); - break; - case "GuildUpdateIconEvent": - GuildUpdateIconEvent e47 = (GuildUpdateIconEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateIconEvent VALUES (?,?,?,?,?,?)"); - s.setLong(2, e47.getGuild().getIdLong()); - s.setString(3, e47.getOldIconUrl()); - s.setString(4, e47.getOldIconId()); - s.setString(5, e47.getNewIconUrl()); - s.setString(6, e47.getNewIconId()); - break; - case "GuildUpdateMFALevelEvent": - GuildUpdateMFALevelEvent e48 = (GuildUpdateMFALevelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateMFALevelEvent VALUES (?,?,?,?)"); - s.setLong(2, e48.getGuild().getIdLong()); - s.setString(3, e48.getOldMFALevel().name()); - s.setString(4, e48.getNewMFALevel().name()); - break; - case "GuildUpdateNameEvent": - GuildUpdateNameEvent e49 = (GuildUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateNameEvent VALUES (?,?,?,?)"); - s.setLong(2, e49.getGuild().getIdLong()); - s.setString(3, e49.getOldName()); - s.setString(4, e49.getNewName()); - break; - case "GuildUpdateNotificationLevelEvent": - GuildUpdateNotificationLevelEvent e50 = (GuildUpdateNotificationLevelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateNotificationLevelEvent VALUES (?,?,?,?)"); - s.setLong(2, e50.getGuild().getIdLong()); - s.setString(3, e50.getOldNotificationLevel().name()); - s.setString(4, e50.getNewNotificationLevel().name()); - break; - case "GuildUpdateOwnerEvent": - GuildUpdateOwnerEvent e51 = (GuildUpdateOwnerEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateOwnerEvent VALUES (?,?,?,?)"); - s.setLong(2, e51.getGuild().getIdLong()); - s.setLong(3, e51.getOldOwner().getUser().getIdLong()); - s.setLong(4, e51.getNewOwner().getUser().getIdLong()); - break; - case "GuildUpdateRegionEvent": - GuildUpdateRegionEvent e52 = (GuildUpdateRegionEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateRegionEvent VALUES (?,?,?,?)"); - s.setLong(2, e52.getGuild().getIdLong()); - s.setString(3, e52.getOldRegion().name()); - s.setString(4, e52.getNewRegion().name()); - break; - case "GuildUpdateSplashEvent": - GuildUpdateSplashEvent e53 = (GuildUpdateSplashEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateSplashEvent VALUES (?,?,?,?)"); - s.setLong(2, e53.getGuild().getIdLong()); - s.setString(3, e53.getOldSplashUrl()); - s.setString(4, e53.getOldSplashId()); - s.setString(5, e53.getNewSplashUrl()); - s.setString(6, e53.getNewSplashId()); - break; - - case "GuildUpdateSystemChannelEvent": - GuildUpdateSystemChannelEvent e54 = (GuildUpdateSystemChannelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateSystemChannelEvent VALUES (?,?,?,?)"); - s.setLong(2, e54.getGuild().getIdLong()); - s.setLong(3, e54.getOldSystemChannel().getIdLong()); - s.setLong(4, e54.getNewSystemChannel().getIdLong()); - break; - case "GuildUpdateBannerEvent": - GuildUpdateBannerEvent e115 = (GuildUpdateBannerEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateBannerEvent VALUES (?,?,?,?)"); - s.setLong(2, e115.getGuild().getIdLong()); - s.setString(3, e115.getOldBannerId()); - s.setString(4, e115.getNewBannerId()); - break; - - case "GuildUpdateBoostCountEvent": - GuildUpdateBoostCountEvent e116 = (GuildUpdateBoostCountEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateBoostCountEvent VALUES (?,?,?,?)"); - s.setLong(2, e116.getGuild().getIdLong()); - s.setInt(3, e116.getOldBoostCount()); - s.setInt(4, e116.getNewBoostCount()); - break; + s.setLong(2, edh.getChannel().getIdLong()); + s.setLong(3,edh.getMessageIdLong()); + s.setLong(4, storeMessage(edh.getMessage())); + break; + case "RawGatewayEvent": + RawGatewayEvent edi = (RawGatewayEvent)event; + s = db.prepareStatement("INSERT INTO events.raw_gateway (geid,type,opcode) VALUES (?,?,?)"); - case "GuildUpdateBoostTierEvent": - GuildUpdateBoostTierEvent e117 = (GuildUpdateBoostTierEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateBoostTierEvent VALUES (?,?,?,?)"); - s.setLong(2, e117.getGuild().getIdLong()); - s.setString(3, e117.getOldBoostTier().name()); - s.setString(4, e117.getNewBoostTier().name()); - break; + s.setString(2, edi.getType()); + s.setInt(3, edi.getPackage().getInt("op"));//XXX C'est sur ça ? + break; + case "ReadyEvent": + ReadyEvent edj = (ReadyEvent)event; + s = db.prepareStatement("INSERT INTO events.ready (geid,guild_available_count,guild_unavailable_count) VALUES (?,?,?)"); - case "GuildUpdateDescriptionEvent": - GuildUpdateDescriptionEvent e118 = (GuildUpdateDescriptionEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateDescriptionEvent VALUES (?,?,?,?)"); - s.setLong(2, e118.getGuild().getIdLong()); - s.setString(3, e118.getOldDescription()); - s.setString(4, e118.getNewDescription()); - break; + s.setInt(2, edj.getGuildAvailableCount()); + s.setInt(3, edj.getGuildUnavailableCount()); + break; + case "ReconnectedEvent": + //ReconnectedEvent edk = (ReconnectedEvent)event; + // L'event fait juste acte de présence + s = db.prepareStatement("INSERT INTO events.reconnected (geid) VALUES (?)"); - case "GuildUpdateMaxMembersEvent": - GuildUpdateMaxMembersEvent e119 = (GuildUpdateMaxMembersEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateMaxMembersEvent VALUES (?,?,?,?)"); - s.setLong(2, e119.getGuild().getIdLong()); - s.setInt(3, e119.getOldMaxMembers()); - s.setInt(4, e119.getNewMaxMembers()); - break; + break; + case "ResumedEvent": + //ResumedEvent edl = (ResumedEvent)event; + // L'eent fait juste acte de présence + s = db.prepareStatement("INSERT INTO events.resumed (geid) VALUES (?)"); - case "GuildUpdateMaxPresencesEvent": - GuildUpdateMaxPresencesEvent e120 = (GuildUpdateMaxPresencesEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateMaxPresencesEvent VALUES (?,?,?,?)"); - s.setLong(2, e120.getGuild().getIdLong()); - s.setInt(3, e120.getOldMaxPresences()); - s.setInt(4, e120.getNewMaxPresences()); - break; + break; + case "RoleCreateEvent": + RoleCreateEvent edm = (RoleCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.role_create (geid,guild_id,role_id,role_mid) VALUES (?,?,?,?)"); - case "GuildUpdateVanityCodeEvent": - GuildUpdateVanityCodeEvent e121 = (GuildUpdateVanityCodeEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateVanityCodeEvent VALUES (?,?,?,?)"); - s.setLong(2, e121.getGuild().getIdLong()); - s.setString(3, e121.getOldVanityCode()); - s.setString(4, e121.getNewVanityCode()); - break; - - case "GuildUpdateVerificationLevelEvent": - GuildUpdateVerificationLevelEvent e55 = (GuildUpdateVerificationLevelEvent)e2; - s = db.prepareStatement("INSERT INTO guildUpdateVerificationLevelEvent VALUES (?,?,?,?)"); - s.setLong(2, e55.getGuild().getIdLong()); - s.setString(3, e55.getOldVerificationLevel().name()); - s.setString(4, e55.getNewVerificationLevel().name()); - break; + s.setLong(2, edm.getGuild().getIdLong()); + s.setLong(3, edm.getRole().getIdLong()); + s.setLong(4, storeRole(edm.getRole())); + break; + case "RoleDeleteEvent": + RoleDeleteEvent edn = (RoleDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.role_delete (geid,guild_id,role_id) VALUES (?,?,?)"); - case "GuildMemberJoinEvent": - GuildMemberJoinEvent e56 = (GuildMemberJoinEvent)e2; - s = db.prepareStatement("INSERT INTO guildMemberJoinEvent VALUES (?,?,?)"); - s.setLong(2, e56.getGuild().getIdLong()); - s.setLong(3, e56.getUser().getIdLong()); - break; - case "GuildMemberUpdateNicknameEvent": - GuildMemberUpdateNicknameEvent e57 = (GuildMemberUpdateNicknameEvent)e2; - s = db.prepareStatement("INSERT INTO guildMemberNickChangeEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e57.getGuild().getIdLong()); - s.setLong(3, e57.getUser().getIdLong()); - s.setString(4, e57.getOldNickname()); - s.setString(5, e57.getNewNickname()); - break; - case "GuildMemberUpdateBoostTimeEvent": - GuildMemberUpdateBoostTimeEvent e123 = (GuildMemberUpdateBoostTimeEvent)e2; - s = db.prepareStatement("INSERT INTO guildMemberUpdateBoostTimeEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e123.getGuild().getIdLong()); - s.setLong(3, e123.getUser().getIdLong()); - s.setDate(4, new Date(e123.getOldTimeBoosted().toEpochSecond())); - s.setDate(5, new Date(e123.getOldTimeBoosted().toEpochSecond())); - break; + s.setLong(2, edn.getGuild().getIdLong()); + s.setLong(3, edn.getRole().getIdLong()); + break; + case "RoleUpdateColorEvent": + RoleUpdateColorEvent edo = (RoleUpdateColorEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_color (geid,guild_id,role_id,old_color_raw,new_color_raw) VALUES (?,?,?,?,?)"); - case "GuildMemberRemoveEvent": - GuildMemberRemoveEvent e58 = (GuildMemberRemoveEvent)e2; - s = db.prepareStatement("INSERT INTO guildMemberLeaveEvent VALUES (?,?,?)"); - s.setLong(2, e58.getGuild().getIdLong()); - s.setLong(3, e58.getUser().getIdLong()); - break; - case "GuildMemberRoleAddEvent": - GuildMemberRoleAddEvent e59 = (GuildMemberRoleAddEvent)e2; - addRoles(geid, e59.getRoles(), db); - s = db.prepareStatement("INSERT INTO guildMemberRoleAddEvent VALUES (?,?,?)"); - s.setLong(2, e59.getGuild().getIdLong()); - s.setLong(3, e59.getUser().getIdLong()); - break; - case "GuildMemberRoleRemoveEvent": - GuildMemberRoleRemoveEvent e60 = (GuildMemberRoleRemoveEvent)e2; - addRoles(geid, e60.getRoles(), db); - s = db.prepareStatement("INSERT INTO guildMemberRoleRemoveEvent VALUES (?,?,?)"); - s.setLong(2, e60.getGuild().getIdLong()); - s.setLong(3, e60.getUser().getIdLong()); - break; + s.setLong(2,edo.getGuild().getIdLong()); + s.setLong(3, edo.getRole().getIdLong()); + s.setInt(4, edo.getOldColorRaw()); + s.setInt(5, edo.getNewColorRaw()); + break; + case "RoleUpdateHoistedEvent": + RoleUpdateHoistedEvent edp = (RoleUpdateHoistedEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_hoisted " + + "(geid,guild_id,role_id,hoisted) VALUES (?,?,?,?)"); - case "GuildVoiceDeafenEvent": - GuildVoiceDeafenEvent e61 = (GuildVoiceDeafenEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceDeafenEvent VALUES (?,?,?,?)"); - s.setLong(2, e61.getGuild().getIdLong()); - s.setLong(3, e61.getMember().getUser().getIdLong()); - s.setBoolean(4, e61.isDeafened()); - break; - case "GuildVoiceGuildDeafenEvent": - GuildVoiceGuildDeafenEvent e62 = (GuildVoiceGuildDeafenEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceGuildDeafenEvent VALUES (?,?,?,?)"); - s.setLong(2, e62.getGuild().getIdLong()); - s.setLong(3, e62.getMember().getUser().getIdLong()); - s.setBoolean(4, e62.isGuildDeafened()); - break; - case "GuildVoiceGuildMuteEvent": - GuildVoiceGuildMuteEvent e63 = (GuildVoiceGuildMuteEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceGuildMuteEvent VALUES (?,?,?,?)"); - s.setLong(2, e63.getGuild().getIdLong()); - s.setLong(3, e63.getMember().getUser().getIdLong()); - s.setBoolean(4, e63.isGuildMuted()); - break; - case "GuildVoiceMuteEvent": - GuildVoiceMuteEvent e64 = (GuildVoiceMuteEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceMuteEvent VALUES (?,?,?,?)"); - s.setLong(2, e64.getGuild().getIdLong()); - s.setLong(3, e64.getMember().getUser().getIdLong()); - s.setBoolean(4, e64.isMuted()); - break; - case "GuildVoiceSelfDeafenEvent": - GuildVoiceSelfDeafenEvent e64b = (GuildVoiceSelfDeafenEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceSelfDeafenEvent VALUES (?,?,?,?)"); - s.setLong(2, e64b.getGuild().getIdLong()); - s.setLong(3, e64b.getMember().getUser().getIdLong()); - s.setBoolean(4, e64b.isSelfDeafened()); - break; + s.setLong(2,edp.getGuild().getIdLong()); + s.setLong(3, edp.getRole().getIdLong()); + s.setBoolean(4, edp.wasHoisted()); + break; + case "RoleUpdateMentionableEvent": + RoleUpdateMentionableEvent edq = (RoleUpdateMentionableEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_mentionable " + + "(geid,guild_id,role_id,mentionable) VALUES (?,?,?,?)"); - case "GuildVoiceStreamEvent": - GuildVoiceStreamEvent e124 = (GuildVoiceStreamEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceStreamEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e124.getGuild().getIdLong()); - s.setLong(3, e124.getMember().getUser().getIdLong()); - s.setLong(4, e124.getVoiceState().getChannel().getIdLong()); - s.setBoolean(5, e124.isStream()); - break; + s.setLong(2,edq.getGuild().getIdLong()); + s.setLong(3, edq.getRole().getIdLong()); + s.setBoolean(4, edq.wasMentionable()); + break; + case "RoleUpdateNameEvent": + RoleUpdateNameEvent edr = (RoleUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_name (geid,guild_id,role_id,old_name,new_name) VALUES (?,?,?,?,?)"); - case "GuildVoiceSelfMuteEvent": - GuildVoiceSelfMuteEvent e65 = (GuildVoiceSelfMuteEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceSelfMuteEvent VALUES (?,?,?,?)"); - s.setLong(2, e65.getGuild().getIdLong()); - s.setLong(3, e65.getMember().getUser().getIdLong()); - s.setBoolean(4, e65.isSelfMuted()); - break; - case "GuildVoiceSuppressEvent": - GuildVoiceSuppressEvent e66 = (GuildVoiceSuppressEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceSuppressEvent VALUES (?,?,?,?)"); - s.setLong(2, e66.getGuild().getIdLong()); - s.setLong(3, e66.getMember().getUser().getIdLong()); - s.setBoolean(4, e66.isSuppressed()); - break; - case "GuildVoiceJoinEvent": - GuildVoiceJoinEvent e67 = (GuildVoiceJoinEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceJoinEvent VALUES (?,?,?,?)"); - s.setLong(2, e67.getGuild().getIdLong()); - s.setLong(3, e67.getMember().getUser().getIdLong()); - s.setLong(4, e67.getChannelJoined().getIdLong()); - break; - case "GuildVoiceLeaveEvent": - GuildVoiceLeaveEvent e68 = (GuildVoiceLeaveEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceLeaveEvent VALUES (?,?,?,?)"); - s.setLong(2, e68.getGuild().getIdLong()); - s.setLong(3, e68.getMember().getUser().getIdLong()); - s.setLong(4, e68.getChannelLeft().getIdLong()); - break; - case "GuildVoiceMoveEvent": - GuildVoiceMoveEvent e69 = (GuildVoiceMoveEvent)e2; - s = db.prepareStatement("INSERT INTO guildVoiceMoveEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e69.getGuild().getIdLong()); - s.setLong(3, e69.getMember().getUser().getIdLong()); - s.setLong(4, e69.getChannelLeft().getIdLong()); - s.setLong(5, e69.getChannelJoined().getIdLong()); - break; - - - ////////// GenericPermissionOverrideEvent ////////// - - case "PermissionOverrideCreateEvent": - PermissionOverrideCreateEvent e73 = (PermissionOverrideCreateEvent)e2; - s = db.prepareStatement("INSERT INTO permissionOverrideCreateEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e73.getGuild().getIdLong()); - s.setLong(3, e73.getChannel().getIdLong()); - IPermissionHolder holder = e73.getPermissionHolder(); - s.setString(4, (holder.getClass().equals(Member.class))?"MEMBER":"ROLE"); - s.setLong(5, (holder.getClass().equals(Member.class))?((Member)holder).getUser().getIdLong():((Role)holder).getIdLong()); - s.setString(6, e73.getPermissionOverride().getAllowed().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(7, e73.getPermissionOverride().getDenied().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(8, e73.getPermissionOverride().getInherit().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - break; - - case "PermissionOverrideDeleteEvent": - PermissionOverrideDeleteEvent e73a = (PermissionOverrideDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO permissionOverrideDeleteEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e73a.getGuild().getIdLong()); - s.setLong(3, e73a.getChannel().getIdLong()); - IPermissionHolder holdera = e73a.getPermissionHolder(); - s.setString(4, (holdera.getClass().equals(Member.class))?"MEMBER":"ROLE"); - s.setLong(5, (holdera.getClass().equals(Member.class))?((Member)holdera).getUser().getIdLong():((Role)holdera).getIdLong()); - s.setString(6, e73a.getPermissionOverride().getAllowed().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(7, e73a.getPermissionOverride().getDenied().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(8, e73a.getPermissionOverride().getInherit().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - break; - - case "PermissionOverrideUpdateEvent": - PermissionOverrideUpdateEvent e73b = (PermissionOverrideUpdateEvent)e2; - s = db.prepareStatement("INSERT INTO permissionOverrideDeleteEvent VALUES (?,?,?,?,?,?)"); - s.setLong(2, e73b.getGuild().getIdLong()); - s.setLong(3, e73b.getChannel().getIdLong()); - IPermissionHolder holderb = e73b.getPermissionHolder(); - s.setString(4, (holderb.getClass().equals(Member.class))?"MEMBER":"ROLE"); - s.setLong(5, (holderb.getClass().equals(Member.class))?((Member)holderb).getUser().getIdLong():((Role)holderb).getIdLong()); - s.setString(6, e73b.getOldAllow().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(7, e73b.getOldDeny().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(8, e73b.getOldInherited().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(9, e73b.getPermissionOverride().getAllowed().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(10, e73b.getPermissionOverride().getDenied().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - s.setString(11, e73b.getPermissionOverride().getInherit().stream().map(perm->perm.name()).collect(Collectors.joining(","))); - break; - + s.setLong(2,edr.getGuild().getIdLong()); + s.setLong(3, edr.getRole().getIdLong()); + s.setString(4, edr.getOldName()); + s.setString(5, edr.getNewName()); + break; + case "RoleUpdatePermissionsEvent": + RoleUpdatePermissionsEvent eds = (RoleUpdatePermissionsEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_permissions (geid,guild_id,role_id,old_perms_raw,new_perms_raw) VALUES (?,?,?,?,?)"); + s.setLong(2,eds.getGuild().getIdLong()); + s.setLong(3, eds.getRole().getIdLong()); + s.setLong(4, eds.getOldPermissionsRaw()); + s.setLong(5, eds.getNewPermissionsRaw()); + break; + case "RoleUpdatePositionEvent": + RoleUpdatePositionEvent edt = (RoleUpdatePositionEvent)event; + s = db.prepareStatement("INSERT INTO events.role_update_position " + + "(geid,guild_id,role_id,old_position,new_position) VALUES (?,?,?,?,?)"); - ////////// GenericTextChannelEvent ////////// - case "TextChannelCreateEvent": - TextChannelCreateEvent e71 = (TextChannelCreateEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelCreateEvent VALUES (?,?,?)"); - s.setLong(2, e71.getGuild().getIdLong()); - s.setLong(3, e71.getChannel().getIdLong()); - break; - case "TextChannelDeleteEvent": - TextChannelDeleteEvent e72 = (TextChannelDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e72.getGuild().getIdLong()); - s.setLong(3, e72.getChannel().getIdLong()); - break; - case "TextChannelUpdateNameEvent": - TextChannelUpdateNameEvent e74 = (TextChannelUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdateNameEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e74.getGuild().getIdLong()); - s.setLong(3, e74.getChannel().getIdLong()); - s.setString(4, e74.getOldName()); - s.setString(5, e74.getNewName()); - break; - case "TextChannelUpdateNSFWEvent": - TextChannelUpdateNSFWEvent e75 = (TextChannelUpdateNSFWEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdateNSFWEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e75.getGuild().getIdLong()); - s.setLong(3, e75.getChannel().getIdLong()); - s.setBoolean(4, e75.getOldNSFW()); - break; - case "TextChannelUpdateParentEvent": - TextChannelUpdateParentEvent e76 = (TextChannelUpdateParentEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdateParentEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e76.getGuild().getIdLong()); - s.setLong(3, e76.getChannel().getIdLong()); - s.setLong(4, e76.getOldParent().getIdLong()); - s.setLong(5, e76.getNewParent().getIdLong()); - break; - case "TextChannelUpdatePositionEvent": - TextChannelUpdatePositionEvent e77 = (TextChannelUpdatePositionEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdatePositionEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e77.getGuild().getIdLong()); - s.setLong(3, e77.getChannel().getIdLong()); - s.setInt(4, e77.getOldPosition()); - s.setInt(5, e77.getNewPosition()); - break; - - case "TextChannelUpdateSlowmodeEvent": - TextChannelUpdateSlowmodeEvent e125 = (TextChannelUpdateSlowmodeEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdateSlowmodeEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e125.getGuild().getIdLong()); - s.setLong(3, e125.getChannel().getIdLong()); - s.setInt(4, e125.getOldSlowmode()); - s.setInt(5, e125.getNewSlowmode()); - break; - - case "TextChannelUpdateTopicEvent": - TextChannelUpdateTopicEvent e78 = (TextChannelUpdateTopicEvent)e2; - s = db.prepareStatement("INSERT INTO textChannelUpdateTopicEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e78.getGuild().getIdLong()); - s.setLong(3, e78.getChannel().getIdLong()); - s.setString(4, e78.getOldTopic()); - s.setString(5, e78.getNewTopic()); - break; + s.setLong(2,edt.getGuild().getIdLong()); + s.setLong(3, edt.getRole().getIdLong()); + s.setInt(4, edt.getOldPosition()); + s.setInt(5, edt.getNewPosition()); + break; + case "SelectionMenuEvent": + SelectionMenuEvent edu = (SelectionMenuEvent)event; + s = db.prepareStatement("INSERT INTO events.selection_menu_event " + + "(geid,guild_id,channel_type,channel_id,interaction_id,interaction_token,user_id,component_id,message_id,values) " + + "VALUES (?,?,?::channel_type,?,?,?,?,?,?,?)"); - - ////////// GenericTextChannelEvent ////////// - case "VoiceChannelCreateEvent": - VoiceChannelCreateEvent e79 = (VoiceChannelCreateEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelCreateEvent VALUES (?,?,?)"); - s.setLong(2, e79.getGuild().getIdLong()); - s.setLong(3, e79.getChannel().getIdLong()); - break; - case "VoiceChannelDeleteEvent": - VoiceChannelDeleteEvent e80 = (VoiceChannelDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e80.getGuild().getIdLong()); - s.setLong(3, e80.getChannel().getIdLong()); - break; - case "VoiceChannelUpdateBitrateEvent": - VoiceChannelUpdateBitrateEvent e82 = (VoiceChannelUpdateBitrateEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelUpdateBitrateEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e82.getGuild().getIdLong()); - s.setLong(3, e82.getChannel().getIdLong()); - s.setInt(4, e82.getOldBitrate()); - s.setInt(5, e82.getNewBitrate()); - break; - case "VoiceChannelUpdateNameEvent": - VoiceChannelUpdateNameEvent e83 = (VoiceChannelUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelUpdateNameEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e83.getGuild().getIdLong()); - s.setLong(3, e83.getChannel().getIdLong()); - s.setString(4, e83.getOldName()); - s.setString(5, e83.getNewName()); - break; - case "VoiceChannelUpdateParentEvent": - VoiceChannelUpdateParentEvent e84 = (VoiceChannelUpdateParentEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelUpdateParentEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e84.getGuild().getIdLong()); - s.setLong(3, e84.getChannel().getIdLong()); - s.setLong(4, e84.getOldParent().getIdLong()); - s.setLong(5, e84.getNewParent().getIdLong()); - break; - case "VoiceChannelUpdatePositionEvent": - VoiceChannelUpdatePositionEvent e85 = (VoiceChannelUpdatePositionEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelUpdatePositionEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e85.getGuild().getIdLong()); - s.setLong(3, e85.getChannel().getIdLong()); - s.setInt(4, e85.getOldPosition()); - s.setInt(5, e85.getNewPosition()); - break; - case "VoiceChannelUpdateUserLimitEvent": - VoiceChannelUpdateUserLimitEvent e86 = (VoiceChannelUpdateUserLimitEvent)e2; - s = db.prepareStatement("INSERT INTO voiceChannelUpdateUserLimitEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e86.getGuild().getIdLong()); - s.setLong(3, e86.getChannel().getIdLong()); - s.setInt(4, e86.getOldUserLimit()); - s.setInt(5, e86.getNewUserLimit()); - break; - + if(edu.getGuild() != null) + s.setLong(2, edu.getGuild().getIdLong()); + else + s.setNull(2, Types.BIGINT); + s.setString(3, edu.getChannelType().name()); + s.setLong(4, edu.getChannel().getIdLong()); + s.setLong(5, edu.getInteraction().getIdLong()); + s.setString(6, edu.getInteraction().getToken()); + s.setLong(7, edu.getUser().getIdLong()); + s.setString(8, edu.getComponentId()); + s.setLong(9, edu.getMessageIdLong()); + s.setArray(10, edu.getValues().stream().collect(juliaSqlArrayCollector("character varying"))); + break; + case "SelfUpdateAvatarEvent": + SelfUpdateAvatarEvent edv = (SelfUpdateAvatarEvent)event; + s = db.prepareStatement("INSERT INTO events.self_update_avatar " + + "(geid,old_avatar_id,old_avatar_url,new_avatar_id,new_avatar_url) VALUES (?,?,?,?,?)"); - ////////// GenericCategoryEvent ////////// - case "CategoryCreateEvent": - CategoryCreateEvent e87 = (CategoryCreateEvent)e2; - s = db.prepareStatement("INSERT INTO categoryCreateEvent VALUES (?,?,?)"); - s.setLong(2, e87.getGuild().getIdLong()); - s.setLong(3, e87.getCategory().getIdLong()); - break; - case "CategoryDeleteEvent": - CategoryDeleteEvent e88 = (CategoryDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO categoryDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e88.getGuild().getIdLong()); - s.setLong(3, e88.getCategory().getIdLong()); - break; - case "CategoryUpdateNameEvent": - CategoryUpdateNameEvent e90 = (CategoryUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO categoryUpdateNameEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e90.getGuild().getIdLong()); - s.setLong(3, e90.getCategory().getIdLong()); - s.setString(4, e90.getOldName()); - s.setString(5, e90.getNewName()); - break; - case "CategoryUpdatePositionEvent": - CategoryUpdatePositionEvent e91 = (CategoryUpdatePositionEvent)e2; - s = db.prepareStatement("INSERT INTO categoryUpdatePositionEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e91.getGuild().getIdLong()); - s.setLong(3, e91.getCategory().getIdLong()); - s.setInt(4, e91.getOldPosition()); - s.setInt(5, e91.getNewPosition()); - break; - - - ////////// GenericStoreChannelEvent ////////// - - case "StoreChannelCreateEvent": - StoreChannelCreateEvent e129 = (StoreChannelCreateEvent)e2; - s = db.prepareStatement("INSERT INTO storeChannelCreateEvent VALUES (?,?,?)"); - s.setLong(2, e129.getChannel().getGuild().getIdLong()); - s.setLong(3, e129.getChannel().getIdLong()); - break; - case "StoreChannelDeleteEvent": - StoreChannelDeleteEvent e126 = (StoreChannelDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO storeChannelDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e126.getChannel().getGuild().getIdLong()); - s.setLong(3, e126.getChannel().getIdLong()); - break; - case "StoreChannelUpdateNameEvent": - StoreChannelUpdateNameEvent e127 = (StoreChannelUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO storeChannelUpdateNameEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e127.getChannel().getGuild().getIdLong()); - s.setLong(3, e127.getChannel().getIdLong()); - s.setString(4, e127.getOldName()); - s.setString(5, e127.getNewName()); - break; - case "StoreChannelUpdatePositionEvent": - StoreChannelUpdatePositionEvent e128 = (StoreChannelUpdatePositionEvent)e2; - s = db.prepareStatement("INSERT INTO storeChannelUpdatePositionEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e128.getChannel().getGuild().getIdLong()); - s.setLong(3, e128.getChannel().getIdLong()); - s.setInt(4, e128.getOldPosition()); - s.setInt(5, e128.getNewPosition()); - break; + s.setString(2, edv.getOldAvatarId()); + s.setString(3, edv.getOldAvatarUrl()); + s.setString(4, edv.getNewAvatarId()); + s.setString(5, edv.getNewAvatarId()); + break; + case "SelfUpdateDiscriminatorEvent": + SelfUpdateDiscriminatorEvent edw = (SelfUpdateDiscriminatorEvent)event; + s = db.prepareStatement("INSERT INTO events.self_update_discriminator (geid,old_discriminator,new_discriminator) VALUES (?,?,?)"); - ////////// GenericPrivateChannelEvent ////////// - case "PrivateChannelCreateEvent": - PrivateChannelCreateEvent e92 = (PrivateChannelCreateEvent)e2; - s = db.prepareStatement("INSERT INTO privateChannelCreateEvent VALUES (?,?,?)"); - s.setLong(2, e92.getUser().getIdLong()); - s.setLong(3, e92.getChannel().getIdLong()); - break; - case "PrivateChannelDeleteEvent": - PrivateChannelDeleteEvent e93 = (PrivateChannelDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO privateChannelDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e93.getUser().getIdLong()); - s.setLong(3, e93.getChannel().getIdLong()); - break; + s.setString(2, edw.getOldDiscriminator()); + s.setString(3, edw.getNewDiscriminator()); + break; + case "SelfUpdateMFAEvent": + SelfUpdateMFAEvent edx = (SelfUpdateMFAEvent)event; + s = db.prepareStatement("INSERT INTO events.self_update_mfa (geid,mfa_enabled) VALUES (?,?)"); - - ////////// GenericRoleEvent ////////// - case "RoleCreateEvent": - RoleCreateEvent e94 = (RoleCreateEvent)e2; - s = db.prepareStatement("INSERT INTO roleCreateEvent VALUES (?,?,?)"); - s.setLong(2, e94.getGuild().getIdLong()); - s.setLong(3, e94.getRole().getIdLong()); - break; - case "RoleDeleteEvent": - RoleDeleteEvent e95 = (RoleDeleteEvent)e2; - s = db.prepareStatement("INSERT INTO roleDeleteEvent VALUES (?,?,?)"); - s.setLong(2, e95.getGuild().getIdLong()); - s.setLong(3, e95.getRole().getIdLong()); - break; - case "RoleUpdateColorEvent": - RoleUpdateColorEvent e97 = (RoleUpdateColorEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdateColorEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e97.getGuild().getIdLong()); - s.setLong(3, e97.getRole().getIdLong()); - s.setInt(4, e97.getOldColorRaw()); - s.setInt(5, e97.getNewColorRaw()); - break; - case "RoleUpdateHoistedEvent": - RoleUpdateHoistedEvent e98 = (RoleUpdateHoistedEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdateHoistedEvent VALUES (?,?,?,?)"); - s.setLong(2, e98.getGuild().getIdLong()); - s.setLong(3, e98.getRole().getIdLong()); - s.setBoolean(4, e98.wasHoisted()); - break; - case "RoleUpdateMentionableEvent": - RoleUpdateMentionableEvent e101 = (RoleUpdateMentionableEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdateMentionableEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e101.getGuild().getIdLong()); - s.setLong(3, e101.getRole().getIdLong()); - s.setBoolean(4, e101.wasMentionable()); - break; - case "RoleUpdateNameEvent": - RoleUpdateNameEvent e99 = (RoleUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdateNameEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e99.getGuild().getIdLong()); - s.setLong(3, e99.getRole().getIdLong()); - s.setString(4, e99.getOldName()); - s.setString(5, e99.getNewName()); - break; - case "RoleUpdatePermissionsEvent": - RoleUpdatePermissionsEvent e96 = (RoleUpdatePermissionsEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdatePermissionsEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e96.getGuild().getIdLong()); - s.setLong(3, e96.getRole().getIdLong()); - s.setString(4, e96.getOldPermissions().stream().map(perm -> perm.name()).collect(Collectors.joining(","))); - s.setString(5, e96.getNewPermissions().stream().map(perm -> perm.name()).collect(Collectors.joining(","))); - break; - case "RoleUpdatePositionEvent": - RoleUpdatePositionEvent e100 = (RoleUpdatePositionEvent)e2; - s = db.prepareStatement("INSERT INTO roleUpdatePositionEvent VALUES (?,?,?,?,?)"); - s.setLong(2, e100.getGuild().getIdLong()); - s.setLong(3, e100.getRole().getIdLong()); - s.setInt(4, e100.getOldPosition()); - s.setInt(5, e100.getNewPosition()); - break; + s.setBoolean(2, edx.wasMfaEnabled()); + break; + case "SelfUpdateNameEvent": + SelfUpdateNameEvent edy = (SelfUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.self_update_name (geid,old_name,new_name) VALUES (?,?,?)"); + s.setString(2, edy.getOldName()); + s.setString(3, edy.getNewName()); + break; + case "SelfUpdateVerifiedEvent": + SelfUpdateVerifiedEvent edz = (SelfUpdateVerifiedEvent)event; + s = db.prepareStatement("INSERT INTO events.self_update_verified (geid,verified) VALUES (?,?)"); - ////////// GenericEmote ////////// - case "EmoteAddedEvent": - EmoteAddedEvent e102 = (EmoteAddedEvent)e2; - s = db.prepareStatement("INSERT INTO emoteAddedEvent VALUES (?,?,?,?)"); - s.setLong(2, e102.getGuild().getIdLong()); - s.setLong(3, e102.getEmote().getIdLong()); - s.setBoolean(4, e102.isManaged()); - break; - case "EmoteRemovedEvent": - EmoteRemovedEvent e103 = (EmoteRemovedEvent)e2; - s = db.prepareStatement("INSERT INTO emoteRemovedEvent VALUES (?,?,?,?)"); - s.setLong(2, e103.getGuild().getIdLong()); - s.setLong(3, e103.getEmote().getIdLong()); - s.setBoolean(4, e103.isManaged()); - break; - case "EmoteUpdateNameEvent": - EmoteUpdateNameEvent e104 = (EmoteUpdateNameEvent)e2; - s = db.prepareStatement("INSERT INTO emoteUpdateNameEvent VALUES (?,?,?,?,?,?)"); - s.setLong(2, e104.getGuild().getIdLong()); - s.setLong(3, e104.getEmote().getIdLong()); - s.setBoolean(4, e104.isManaged()); - s.setString(5, e104.getOldName()); - s.setString(6, e104.getNewName()); - break; - case "EmoteUpdateRolesEvent": - EmoteUpdateRolesEvent e105 = (EmoteUpdateRolesEvent)e2; - s = db.prepareStatement("INSERT INTO emoteUpdateRolesEvent VALUES (?,?,?,?,?,?)"); - s.setLong(2, e105.getGuild().getIdLong()); - s.setLong(3, e105.getEmote().getIdLong()); - s.setBoolean(4, e105.isManaged()); - s.setString(5, e105.getOldRoles().stream().map(r -> r.getId()).collect(Collectors.joining(","))); - s.setString(6, e105.getNewRoles().stream().map(r -> r.getId()).collect(Collectors.joining(","))); - break; + s.setBoolean(2, edz.wasVerified()); + break; + case "ShutdownEvent": + ShutdownEvent eea = (ShutdownEvent)event; + s = db.prepareStatement("INSERT INTO events.shutdown (geid,close_code,shutdown_time) VALUES (?,?::close_code,?)"); + + if(eea.getCloseCode() != null) + s.setString(2, eea.getCloseCode().name()); + else + s.setNull(2, Types.VARCHAR); + s.setTimestamp(3, timestamp(eea.getTimeShutdown())); + break; + case "SlashCommandEvent": + SlashCommandEvent eeb = (SlashCommandEvent)event; + s = db.prepareStatement("INSERT INTO events.slash_command " + + "(geid,guild_id,channel_type,channel_id,interaction_id,interaction_type_raw," + + "interaction_token,user_id,command_id,command_name,command_subcommandgroup,command_subcommand,options) " + + "VALUES (?,?,?::channel_type,?,?,?,?,?,?,?,?,?,?)"); + + if(eeb.getGuild() != null) + s.setLong(2, eeb.getGuild().getIdLong()); + else + s.setNull(2, Types.VARCHAR); + s.setString(3, eeb.getChannelType().name()); + s.setLong(4, eeb.getChannel().getIdLong()); + s.setLong(5, eeb.getInteraction().getIdLong()); + s.setInt(6, eeb.getTypeRaw()); + s.setString(7, eeb.getInteraction().getToken()); + s.setLong(8, eeb.getUser().getIdLong()); + s.setLong(9, eeb.getCommandIdLong()); + s.setString(10, eeb.getName()); + s.setString(11, eeb.getSubcommandGroup()); + s.setString(12, eeb.getSubcommandName()); + s.setArray(13, eeb.getOptions().stream() + .map(unex(om -> db.createStruct("option_mapping",new String[] {om.getType().name(),om.getAsString()}))) + .collect(juliaSqlArrayCollector("option_mapping"))); + //XXX: Si peu sûr de celle-là ... + + break; + case "StageInstanceCreateEvent": + StageInstanceCreateEvent eec = (StageInstanceCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.stage_instance_create (geid,guild_id,instance_id,channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, eec.getGuild().getIdLong()); + s.setLong(3, eec.getInstance().getIdLong()); + s.setLong(4, eec.getChannel().getIdLong()); + break; + case "StageInstanceDeleteEvent": + StageInstanceDeleteEvent eed = (StageInstanceDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.stage_instance_delete (geid,guild_id,instance_id,channel_id) VALUES (?,?,?,?)"); + + s.setLong(2, eed.getGuild().getIdLong()); + s.setLong(3, eed.getInstance().getIdLong()); + s.setLong(4, eed.getChannel().getIdLong()); + break; + case "StageInstanceUpdatePrivacyLevelEvent": + StageInstanceUpdatePrivacyLevelEvent eee = (StageInstanceUpdatePrivacyLevelEvent)event; + s = db.prepareStatement("INSERT INTO events.stage_instance_update_privacy_level (geid,guild_id,instance_id,channel_id,old_level,new_level) " + + "VALUES (?,?,?,?,?::privacy_level,?::privacy_level)"); + + s.setLong(2, eee.getGuild().getIdLong()); + s.setLong(3, eee.getInstance().getIdLong()); + s.setLong(4, eee.getChannel().getIdLong()); + s.setString(5, eee.getOldValue().name()); + s.setString(6, eee.getNewValue().name()); + break; + case "StageInstanceUpdateTopicEvent": + StageInstanceUpdateTopicEvent eef = (StageInstanceUpdateTopicEvent)event; + s = db.prepareStatement("INSERT INTO events.stage_instance_update_topic (geid,guild_id,instance_id,channel_id,old_topic,new_topic) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, eef.getGuild().getIdLong()); + s.setLong(3, eef.getInstance().getIdLong()); + s.setLong(4, eef.getChannel().getIdLong()); + s.setString(5, eef.getOldValue()); + s.setString(6, eef.getNewValue()); + break; + case "StatusChangeEvent": + StatusChangeEvent eeg = (StatusChangeEvent)event; + s = db.prepareStatement("INSERT INTO events.status_change (geid,old_status,new_status) VALUES (?,?::jda_status,?::jda_status)"); + + s.setObject(2, eeg.getOldStatus().name(),Types.OTHER); + s.setObject(3, eeg.getNewStatus().name(),Types.OTHER); + break; + case "StoreChannelCreateEvent": + StoreChannelCreateEvent eeh = (StoreChannelCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.store_channel_create (geid,guild_id,channel_id) VALUES (?,?,?)"); + + s.setLong(2, eeh.getChannel().getGuild().getIdLong()); + s.setLong(3, eeh.getChannel().getIdLong()); + break; + case "StoreChannelDeleteEvent": + StoreChannelDeleteEvent eei = (StoreChannelDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.store_channel_delete (geid,guild_id,channel_id) VALUES (?,?,?)"); + + s.setLong(2, eei.getChannel().getGuild().getIdLong()); + s.setLong(3, eei.getChannel().getIdLong()); + break; + case "StoreChannelUpdateNameEvent": + StoreChannelUpdateNameEvent eej = (StoreChannelUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.store_channel_update_name (geid,guild_id,channel_id,old_name,new_name) VALUES (?,?,?,?,?)"); + + s.setLong(2, eej.getChannel().getGuild().getIdLong()); + s.setLong(3, eej.getChannel().getIdLong()); + s.setString(4, eej.getOldName()); + s.setString(5, eej.getNewName()); + break; + case "StoreChannelUpdatePositionEvent": + StoreChannelUpdatePositionEvent eek = (StoreChannelUpdatePositionEvent)event; + s = db.prepareStatement("INSERT INTO events.store_channel_update_position " + + "(geid,guild_id,channel_id,old_position,new_position) VALUES (?,?,?,?,?)"); + + s.setLong(2, eek.getChannel().getGuild().getIdLong()); + s.setLong(3, eek.getChannel().getIdLong()); + s.setInt(4, eek.getOldPosition()); + s.setInt(5, eek.getNewPosition()); + break; + case "TextChannelCreateEvent": + TextChannelCreateEvent eel = (TextChannelCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_create (geid,guild_id,channel_id) VALUES (?,?,?)"); + + s.setLong(2, eel.getChannel().getGuild().getIdLong()); + s.setLong(3, eel.getChannel().getIdLong()); + break; + case "TextChannelDeleteEvent": + TextChannelDeleteEvent eem = (TextChannelDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_delete (geid,guild_id,channel_id) VALUES (?,?,?)"); + + s.setLong(2, eem.getChannel().getGuild().getIdLong()); + s.setLong(3, eem.getChannel().getIdLong()); + break; + case "TextChannelUpdateNameEvent": + TextChannelUpdateNameEvent een = (TextChannelUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_name (geid,guild_id,channel_id,old_name,new_name) VALUES (?,?,?,?,?)"); + + s.setLong(2, een.getChannel().getGuild().getIdLong()); + s.setLong(3, een.getChannel().getIdLong()); + s.setString(4, een.getOldName()); + s.setString(5, een.getNewName()); + break; + case "TextChannelUpdateNewsEvent": + TextChannelUpdateNewsEvent eeo = (TextChannelUpdateNewsEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_news (geid,guild_id,channel_id,news) VALUES (?,?,?,?)"); + + s.setLong(2, eeo.getChannel().getGuild().getIdLong()); + s.setLong(3, eeo.getChannel().getIdLong()); + s.setBoolean(4, eeo.getNewValue()); + break; + case "TextChannelUpdateNSFWEvent": + TextChannelUpdateNSFWEvent eep = (TextChannelUpdateNSFWEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_nsfw (geid,guild_id,channel_id,nsfw) VALUES (?,?,?,?)"); + + s.setLong(2, eep.getChannel().getGuild().getIdLong()); + s.setLong(3, eep.getChannel().getIdLong()); + if(eep.getOldValue() != null) + s.setBoolean(4, eep.getOldValue()); + else + s.setNull(4, Types.BOOLEAN); + break; + case "TextChannelUpdateParentEvent": + TextChannelUpdateParentEvent eeq = (TextChannelUpdateParentEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_parent " + + "(geid,guild_id,channel_id,old_category_id,new_category_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, eeq.getChannel().getGuild().getIdLong()); + s.setLong(3, eeq.getChannel().getIdLong()); + if(eeq.getOldParent() != null) + s.setLong(4, eeq.getOldParent().getIdLong()); + else + s.setNull(4, Types.BIGINT); + if(eeq.getNewParent() != null) + s.setLong(5, eeq.getNewParent().getIdLong()); + else + s.setNull(5, Types.BIGINT); + break; + case "TextChannelUpdatePositionEvent": + TextChannelUpdatePositionEvent eer = (TextChannelUpdatePositionEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_position (geid,guild_id,channel_id,old_position,new_position) VALUES (?,?,?,?,?)"); + + s.setLong(2, eer.getChannel().getGuild().getIdLong()); + s.setLong(3, eer.getChannel().getIdLong()); + s.setInt(4, eer.getOldPosition()); + s.setInt(5, eer.getNewPosition()); + break; + case "TextChannelUpdateSlowmodeEvent": + TextChannelUpdateSlowmodeEvent ees = (TextChannelUpdateSlowmodeEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_slowmode (geid,guild_id,channel_id,old_slowmode,new_slowmode) VALUES (?,?,?,?,?)"); + + s.setLong(2, ees.getChannel().getGuild().getIdLong()); + s.setLong(3, ees.getChannel().getIdLong()); + s.setInt(4, ees.getOldSlowmode()); + s.setInt(5, ees.getNewSlowmode()); + break; + case "TextChannelUpdateTopicEvent": + TextChannelUpdateTopicEvent eet = (TextChannelUpdateTopicEvent)event; + s = db.prepareStatement("INSERT INTO events.text_channel_update_topic (geid,guild_id,channel_id,old_topic,new_topic) VALUES (?,?,?,?,?)"); + + s.setLong(2, eet.getChannel().getGuild().getIdLong()); + s.setLong(3, eet.getChannel().getIdLong()); + s.setString(4, eet.getOldTopic()); + s.setString(5, eet.getNewTopic()); + break; + case "UnavailableGuildJoinedEvent": + UnavailableGuildJoinedEvent eeu = (UnavailableGuildJoinedEvent)event; + s = db.prepareStatement("INSERT INTO events.unavailable_guild_joined (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, eeu.getGuildIdLong()); + break; + case "UnavailableGuildLeaveEvent": + UnavailableGuildLeaveEvent eev = (UnavailableGuildLeaveEvent)event; + s = db.prepareStatement("INSERT INTO events.unavailable_guild_leave (geid,guild_id) VALUES (?,?)"); + + s.setLong(2, eev.getGuildIdLong()); + break; + case "UserActivityEndEvent": + UserActivityEndEvent eew = (UserActivityEndEvent)event; + s = db.prepareStatement("INSERT INTO events.user_activity_end (geid,user_id,guild_id,activity_mid) VALUES (?,?,?,?)"); + + s.setLong(2, eew.getUser().getIdLong()); + s.setLong(3, eew.getGuild().getIdLong()); + s.setLong(4, storeActivity(eew.getOldActivity())); + break; + case "UserActivityStartEvent": + UserActivityStartEvent eex = (UserActivityStartEvent)event; + s = db.prepareStatement("INSERT INTO events.user_activity_start (geid,user_id,guild_id,activity_mid) VALUES (?,?,?,?)"); + + s.setLong(2, eex.getUser().getIdLong()); + s.setLong(3, eex.getGuild().getIdLong()); + s.setLong(4, storeActivity(eex.getNewActivity())); + break; + case "UserTypingEvent": + UserTypingEvent eey = (UserTypingEvent)event; + s = db.prepareStatement("INSERT INTO events.user_typing (geid,user_id,channel_type,channel_id,guild_id,type_date) VALUES (?,?,?::channel_type,?,?,?)"); + + s.setLong(2, eey.getUser().getIdLong()); + s.setString(3, eey.getChannel().getType().name()); + s.setLong(4, eey.getChannel().getIdLong()); + if(eey.getGuild() != null) + s.setLong(5, eey.getGuild().getIdLong()); + else + s.setNull(5, Types.BIGINT); + s.setTimestamp(6, timestamp(eey.getTimestamp())); + break; + case "UserUpdateActivitiesEvent": + UserUpdateActivitiesEvent eez = (UserUpdateActivitiesEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_activities (geid,user_id,guild_id,new_activities_mids) VALUES (?,?,?,?)"); + + s.setLong(2, eez.getUser().getIdLong()); + s.setLong(3, eez.getGuild().getIdLong()); + if(eez.getNewValue() != null) + s.setArray(4, eez.getNewValue().stream().map(unex(EcouteurDEvents::storeActivity)).collect(juliaSqlArrayCollector("bigint"))); + else + s.setNull(4, Types.ARRAY); + break; + case "UserUpdateActivityOrderEvent": + UserUpdateActivityOrderEvent efa = (UserUpdateActivityOrderEvent)event; + //TODO: On peut stoquer moins d'infos (recycler les mids ?) + s = db.prepareStatement("INSERT INTO events.user_update_activity_order (geid,user_id,guild_id,new_activities_mids) VALUES (?,?,?,?)"); + + s.setLong(2, efa.getUser().getIdLong()); + s.setLong(3, efa.getGuild().getIdLong()); + s.setArray(4, efa.getNewValue().stream().map(unex(EcouteurDEvents::storeActivity)).collect(juliaSqlArrayCollector("bigint"))); + break; + case "UserUpdateAvatarEvent": + UserUpdateAvatarEvent efb = (UserUpdateAvatarEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_avatar (geid,user_id,old_avatar_id,old_avatar_url,new_avatar_id,new_avatar_url) VALUES (?,?,?,?,?,?)"); + + s.setLong(2, efb.getUser().getIdLong()); + s.setString(3, efb.getOldAvatarId()); + s.setString(4, efb.getOldAvatarUrl()); + s.setString(5, efb.getNewAvatarId()); + s.setString(6, efb.getNewAvatarUrl()); + break; + case "UserUpdateDiscriminatorEvent": + UserUpdateDiscriminatorEvent efc = (UserUpdateDiscriminatorEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_discriminator (geid,user_id,old_discriminator,new_discriminator) VALUES (?,?,?,?)"); + + s.setLong(2, efc.getUser().getIdLong()); + s.setString(3, efc.getOldDiscriminator()); + s.setString(4, efc.getNewDiscriminator()); + break; + case "UserUpdateFlagsEvent": + UserUpdateFlagsEvent efd = (UserUpdateFlagsEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_flags (geid,user_id,old_flags_raw,new_flags_raw) VALUES (?,?,?,?)"); + + s.setLong(2, efd.getUser().getIdLong()); + s.setInt(3, efd.getOldFlagsRaw()); + s.setInt(4, efd.getNewFlagsRaw()); + break; + case "UserUpdateNameEvent": + UserUpdateNameEvent efe = (UserUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_name (geid,user_id,old_name,new_name) VALUES (?,?,?,?)"); + + s.setLong(2, efe.getUser().getIdLong()); + s.setString(3, efe.getOldName()); + s.setString(4, efe.getNewName()); + break; + case "UserUpdateOnlineStatusEvent": + UserUpdateOnlineStatusEvent eff = (UserUpdateOnlineStatusEvent)event; + s = db.prepareStatement("INSERT INTO events.user_update_online_status " + + "(geid, user_id,guild_id,old_online_status,new_online_status) VALUES (?,?,?,?::online_status,?::online_status)"); + + s.setLong(2, eff.getUser().getIdLong()); + s.setLong(3, eff.getGuild().getIdLong()); + s.setString(4, eff.getOldOnlineStatus().name()); + s.setString(5, eff.getNewOnlineStatus().name()); + break; + case "VoiceChannelCreateEvent": + VoiceChannelCreateEvent efg = (VoiceChannelCreateEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_create (geid,guild_id,channel_id,channel_name) VALUES (?,?,?,?)"); + + s.setLong(2, efg.getGuild().getIdLong()); + s.setLong(3, efg.getChannel().getIdLong()); + s.setString(4, efg.getChannel().getName()); + break; + case "VoiceChannelDeleteEvent": + VoiceChannelDeleteEvent efh = (VoiceChannelDeleteEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_delete (geid,guild_id,channel_id) VALUES (?,?,?)"); + + s.setLong(2, efh.getGuild().getIdLong()); + s.setLong(3, efh.getChannel().getIdLong()); + break; + case "VoiceChannelUpdateBitrateEvent": + VoiceChannelUpdateBitrateEvent efi = (VoiceChannelUpdateBitrateEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_bitrate " + + "(geid,guild_id,channel_id,old_bitrate,new_bitrate) VALUES (?,?,?,?,?)"); + + s.setLong(2, efi.getGuild().getIdLong()); + s.setLong(3, efi.getChannel().getIdLong()); + s.setInt(4, efi.getOldBitrate()); + s.setInt(5, efi.getNewBitrate()); + break; + case "VoiceChannelUpdateNameEvent": + VoiceChannelUpdateNameEvent efj = (VoiceChannelUpdateNameEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_name " + + "(geid,guild_id,channel_id,old_name,new_name) VALUES (?,?,?,?,?)"); + + s.setLong(2, efj.getGuild().getIdLong()); + s.setLong(3, efj.getChannel().getIdLong()); + s.setString(4, efj.getOldName()); + s.setString(5, efj.getNewName()); + break; + case "VoiceChannelUpdateParentEvent": + VoiceChannelUpdateParentEvent efk = (VoiceChannelUpdateParentEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_parent " + + "(geid,guild_id,channel_id,old_category_id,new_category_id) VALUES (?,?,?,?,?)"); + + s.setLong(2, efk.getGuild().getIdLong()); + s.setLong(3, efk.getChannel().getIdLong()); + if(efk.getOldParent() != null) + s.setLong(4, efk.getOldParent().getIdLong()); + else + s.setNull(4, Types.BIGINT); + if(efk.getNewParent() != null) + s.setLong(5, efk.getNewParent().getIdLong()); + else + s.setNull(5, Types.BIGINT); + break; + case "VoiceChannelUpdatePositionEvent": + VoiceChannelUpdatePositionEvent efl = (VoiceChannelUpdatePositionEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_position " + + "(geid,guild_id,channel_id,old_position,new_position) VALUES (?,?,?,?,?)"); + + s.setLong(2, efl.getGuild().getIdLong()); + s.setLong(3, efl.getChannel().getIdLong()); + s.setInt(4, efl.getOldPosition()); + s.setInt(5, efl.getNewPosition()); + break; + case "VoiceChannelUpdateRegionEvent": + VoiceChannelUpdateRegionEvent efm = (VoiceChannelUpdateRegionEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_region " + + "(geid,guild_id,channel_id,old_region_key,new_region_key) VALUES (?,?,?,?,?)"); + + s.setLong(2, efm.getGuild().getIdLong()); + s.setLong(3, efm.getChannel().getIdLong()); + s.setString(4, efm.getOldRegionRaw()); + s.setString(5, efm.getNewRegionRaw()); + break; + case "VoiceChannelUpdateUserLimitEvent": + VoiceChannelUpdateUserLimitEvent efn = (VoiceChannelUpdateUserLimitEvent)event; + s = db.prepareStatement("INSERT INTO events.voice_channel_update_userlimit " + + "(geid,guild_id,channel_id,old_limit,new_limit) VALUES (?,?,?,?,?)"); + + s.setLong(2, efn.getGuild().getIdLong()); + s.setLong(3, efn.getChannel().getIdLong()); + s.setInt(4, efn.getOldUserLimit()); + s.setInt(5, efn.getNewUserLimit()); + break; + + case "GuildMemberLeaveEvent": + case "TextChannelUpdatePermissionsEvent": + case "StoreChannelUpdatePermissionsEvent": + case "VoiceChannelUpdatePermissionsEvent": + // Event déprécié qu'un autre remplace + + return; - - - - - - - - case "HttpRequestEvent": - //TODO System.err.println("EN attente d'un dev assez motivé pour coder ce foutu HttpRequestEvent !!!"); - return; default: - throw new IllegalStateException("Cette méthode n'est pas a jour avec le JDA ... je gère pas "+e2.getClass().getName()); + throw new IllegalStateException("Cette méthode n'est pas a jour avec le JDA ... je gère pas "+event.getClass().getName()); } s.setLong(1, geid);//Le GEID s.executeUpdate(); - } catch (SQLException e1) { - System.err.println("Mysql pas content ......"); - e1.printStackTrace(); - } catch(IllegalStateException e) { - System.err.println("Je continue quand même a récupérer les évents"); - e.printStackTrace(); + } catch (SQLException e) { + erreur("Sql pas content avec un event "+event.getClass().getSimpleName(),e); } catch(NumberFormatException e) { - System.err.println("Y a un truc qui a éssayé de rentrer dans la BDD mais qui a pas réussi"); - e.printStackTrace(); + erreur("Y a un truc qui a éssayé de rentrer dans la BDD mais qui a pas réussi",e); } catch(Exception e) { - System.err.println("Snif, je suis mal codée, c'est parce que vous m'aimez pas, hein ?"); - e.printStackTrace(); + erreur("Snif, je suis mal codée, c'est parce que vous m'aimez pas, hein ?",e); } } } + ////////////////////DB UTILS V2//////////////////// + public static long genId(String generator) throws SQLException { + PreparedStatement genSt = Julia.theJulia.juliaBDD.prepareStatement("SELECT nextval(?) AS theid"); + genSt.setString(1,generator); + ResultSet res = genSt.executeQuery(); + res.next(); + return res.getLong("theid"); + } + + public static long storeCommand(Command commande) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.command_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.command " + + "(mid,command_id,application_id,name,description,default_enabled)" + + " VALUES (?,?,?,?,?,?)"); + + s.setLong (1, mid); + s.setLong (2, commande.getIdLong()); + s.setLong (3, commande.getApplicationIdLong()); + s.setString (4, commande.getName()); + s.setString (5, commande.getDescription()); + s.setBoolean(6, commande.isDefaultEnabled()); + + s.executeUpdate(); + return mid; + + } + public static long storeCommandOption(Command.Option commande, long commandeMid, boolean isSubcommand) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.command_option_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.command_option " + + "(mid,name,description,type,required,is_subcommand,command_mid)" + + " VALUES (?,?,?,?::option_type,?,?,?)"); + + s.setLong (1, mid); + s.setString (2, commande.getName()); + s.setString (3, commande.getDescription()); + s.setString (4, commande.getType().name()); + s.setBoolean(5, commande.isRequired()); + s.setBoolean(6, isSubcommand); + s.setLong (7, commandeMid); + + s.executeUpdate(); + return mid; + + } + public static long storeCommandChoice(Command.Choice commande, long commandOptionMid) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.command_choice_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.command_choice " + + "(mid,name,value,command_option_mid)" + + " VALUES (?,?,?,?)"); + + s.setLong (1, mid); + s.setString(2, commande.getName()); + s.setString(3, commande.getAsString()); + s.setLong (4, commandOptionMid); + + s.executeUpdate(); + return mid; + + } + public static long storeSubCommand(Subcommand subcommande, long commandMid, Long subcommandGroupMid) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.command_subcommand_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.command_subcommand " + + "(mid,name,description,command_mid,subcommand_group_mid)" + + " VALUES (?,?,?,?,?)"); + + s.setLong (1 , mid); + s.setString (2 , subcommande.getName()); + s.setString (3 , subcommande.getDescription()); + s.setLong (4 , commandMid); + if(subcommandGroupMid!=null) + s.setLong (5 , subcommandGroupMid); + else + s.setNull (5, Types.BIGINT); + + s.executeUpdate(); + return mid; + + } + public static long storeSubCommandGroup(SubcommandGroup subcommandGroup, long commandMid) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.subcommand_group_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.subcommand_group " + + "(mid,name,description,command_mid)" + + " VALUES (?,?,?,?)"); + + s.setLong (1 , mid); + s.setString (2 , subcommandGroup.getName()); + s.setString (3 , subcommandGroup.getDescription()); + s.setLong (4 , commandMid); + + s.executeUpdate(); + return mid; + + } + public static long storeMessage(Message msg) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.message_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.message " + + "(mid,author_id,channel_type,channel_id,content_raw,flags,time_created,time_edit,pinned,suppressed_embeds," + + "tts,webhook,mentions_everyone,embeds_mids,attachements_mids,message_activity_mid," + + "action_rows,emotes_mids,referenced_message_mid,mentionned_users_ids," + + "mentionned_channels_ids,mentionned_roles_ids,stickers_mids,reactions)" + + " VALUES (?,?,?::channel_type,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); + + s.setLong (1 , mid); + s.setLong (2 , msg.getAuthor().getIdLong()); + s.setString (3 , msg.getChannelType().name()); + s.setLong (4 , msg.getChannel().getIdLong()); + s.setString (5 , msg.getContentRaw()); + s.setInt (6 , MessageFlag.toBitField(msg.getFlags())); + s.setTimestamp(7 , timestamp(msg.getTimeCreated())); + if(msg.getTimeEdited()!=null) + s.setTimestamp(8 , timestamp(msg.getTimeEdited())); + else + s.setNull(8, Types.TIMESTAMP); + s.setBoolean (9 , msg.isPinned()); + s.setBoolean (10, msg.isSuppressedEmbeds()); + s.setBoolean (11, msg.isTTS()); + s.setBoolean (12, msg.isWebhookMessage()); + s.setBoolean (13, msg.mentionsEveryone()); + s.setArray (14, msg.getEmbeds().stream().map(unex(EcouteurDEvents::storeEmbed)).collect(juliaSqlArrayCollector("bigint"))); + s.setArray (15, msg.getAttachments().stream().map(unex(a -> storeAttachment(a, mid))).collect(juliaSqlArrayCollector("bigint"))); + if(msg.getActivity()!=null) + s.setLong (16, storeMessageActivity(msg.getActivity())); + else + s.setNull(16, Types.BIGINT); + s.setArray (17, msg.getActionRows().stream().map(a -> a.toData().toJson()).collect(juliaSqlArrayCollector("json"))); + s.setArray (18, msg.getEmotes().stream().map(unex(EcouteurDEvents::storeEmote)).collect(juliaSqlArrayCollector("bigint"))); + if(msg.getReferencedMessage()!=null) + s.setLong (19, msg.getReferencedMessage().getIdLong()); + else + s.setNull(19, Types.BIGINT); + s.setArray (20, msg.getMentionedUsers().stream().map(User::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + s.setArray (21, msg.getMentionedChannels().stream().map(TextChannel::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + s.setArray (22, msg.getMentionedRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + s.setArray (23, msg.getStickers().stream().map(unex(EcouteurDEvents::storeMessageSticker)).collect(juliaSqlArrayCollector("bigint"))); + s.setArray (24, msg.getReactions().stream().map(EcouteurDEvents::messageReaction).collect(juliaSqlArrayCollector("varchar"))); + + + s.executeUpdate(); + return mid; + + } + public static long storeAttachment(Message.Attachment ma, long messageMid) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.message_attachment_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.message_attachment " + + "(mid,discord_id,content_type,extension,filename,width,height,url,proxy_url,size,message_mid)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?)"); + + s.setLong (1, mid); + s.setLong (2, ma.getIdLong()); + if(ma.getContentType() != null) + s.setString(3, ma.getContentType()); + else + s.setNull(3, Types.VARCHAR); + if(ma.getFileExtension() != null) + s.setString(4, ma.getFileExtension()); + else + s.setNull(4, Types.VARCHAR); + s.setString(5, ma.getFileName()); + s.setInt (6, ma.getWidth()); + s.setInt (7, ma.getHeight()); + s.setString(8, ma.getUrl()); + s.setString(9, ma.getProxyUrl()); + s.setInt (10, ma.getSize()); + s.setLong (11, messageMid); + + s.executeUpdate(); + return mid; + + } + public static long storeMessageActivity(MessageActivity ma) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.message_activity_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.message_activity " + + "(mid,type,party_id,cover_id,cover_url,description,icon_id,icon_url,name,application_id,time_created)" + + " VALUES (?,?::message_activity_type,?,?,?,?,?,?,?,?,?)"); + + s.setLong(1, mid); + s.setString(2, ma.getType().name()); + s.setString(3, ma.getPartyId()); + if(ma.getApplication()!= null) { + s.setString(4, ma.getApplication().getCoverId()); + s.setString(5, ma.getApplication().getCoverUrl()); + s.setString(6, ma.getApplication().getDescription()); + s.setString(7, ma.getApplication().getIconId()); + s.setString(8, ma.getApplication().getIconUrl()); + s.setString(9, ma.getApplication().getName()); + s.setLong(10, ma.getApplication().getIdLong()); + s.setTimestamp(11, timestamp(ma.getApplication().getTimeCreated())); + }else { + s.setNull(4, Types.VARCHAR); + s.setNull(5, Types.VARCHAR); + s.setNull(6, Types.VARCHAR); + s.setNull(7, Types.VARCHAR); + s.setNull(8, Types.VARCHAR); + s.setNull(9, Types.VARCHAR); + s.setNull(10, Types.BIGINT); + s.setNull(11, Types.TIMESTAMP); + } + s.executeUpdate(); + return mid; + + } + public static long storeMessageSticker(MessageSticker ms) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.message_sticker_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.message_sticker " + + "(mid,discord_id,name,format,description,icon_url,pack_id,tags)" + + " VALUES (?,?,?,?::sticker_format,?,?,?,?)"); + + s.setLong(1, mid); + s.setLong(2, ms.getIdLong()); + s.setString(3, ms.getName()); + s.setString(4, ms.getFormatType().name()); + s.setString(5, ms.getDescription()); + s.setString(6, ms.getIconUrl()); + s.setLong(7, ms.getPackIdLong()); + s.setArray(8, ms.getTags().stream().collect(juliaSqlArrayCollector("character varying"))); + + s.executeUpdate(); + return mid; + + } + public static long storeActivity(Activity activity) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.activity_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.activity " + + "(mid,name,type,url,emoji,start_time,end_time,rich_mid)" + + " VALUES (?,?,?::activity_type,?,?,?,?,?)"); + + s.setLong(1, mid); + s.setString(2, activity.getName()); + s.setString(3, activity.getType().name()); + s.setString(4, activity.getUrl()); + s.setString(5, emoji(activity.getEmoji())); + if(activity.getTimestamps() != null) { + s.setTimestamp(6, timestamp(activity.getTimestamps().getStart())); + s.setTimestamp(7, timestamp(activity.getTimestamps().getEnd())); + } else { + s.setNull(6, Types.TIMESTAMP); + s.setNull(7, Types.TIMESTAMP); + } + if(activity.isRich()) { + s.setLong(8, storeRichPresence(activity.asRichPresence())); + }else { + s.setNull(8, Types.BIGINT); + } + + s.executeUpdate(); + return mid; + + } + public static long storeEmbed(MessageEmbed embed) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.embed_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.embed " + + "(mid,author_icon_url,author_icon_url_proxied,author_name,author_url,color_raw,description,footer_icon_url," + + "footer_icon_url_proxied,footer_text,image_height,image_width,image_url,image_url_proxied,length,provider_name," + + "provider_url,thumbnail_height,thumbnail_width,thumbnail_url,thumbnail_url_proxied,timestamp,title," + + "type,url,empty,sendable,video_height,video_width,video_url)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?::embed_type,?,?,?,?,?,?)"); + + s.setLong (1 , mid); + if(embed.getAuthor() != null) { + s.setString (2 , embed.getAuthor().getIconUrl()); + s.setString (3 , embed.getAuthor().getProxyIconUrl()); + s.setString (4 , embed.getAuthor().getName()); + s.setString (5 , embed.getAuthor().getUrl()); + }else { + s.setNull(2, Types.VARCHAR); + s.setNull(3, Types.VARCHAR); + s.setNull(4, Types.VARCHAR); + s.setNull(5, Types.VARCHAR); + } + s.setInt (6 , embed.getColorRaw()); + s.setString (7 , embed.getDescription()); + if(embed.getFooter() != null) { + s.setString (8 , embed.getFooter().getIconUrl()); + s.setString (9 , embed.getFooter().getProxyIconUrl()); + s.setString (10, embed.getFooter().getText()); + }else { + s.setNull(8, Types.VARCHAR); + s.setNull(9, Types.VARCHAR); + s.setNull(10, Types.VARCHAR); + } + if(embed.getImage() != null) { + s.setInt (11, embed.getImage().getHeight()); + s.setInt (12, embed.getImage().getWidth()); + s.setString (13, embed.getImage().getUrl()); + s.setString (14, embed.getImage().getProxyUrl()); + }else { + s.setNull(11, Types.INTEGER); + s.setNull(12, Types.INTEGER); + s.setNull(13, Types.VARCHAR); + s.setNull(14, Types.VARCHAR); + } + s.setInt (15, embed.getLength()); + if(embed.getSiteProvider() != null) { + s.setString (16, embed.getSiteProvider().getName()); + s.setString (17, embed.getSiteProvider().getUrl()); + }else { + s.setNull(16, Types.VARCHAR); + s.setNull(17, Types.VARCHAR); + } + if(embed.getThumbnail() != null) { + s.setInt (18, embed.getThumbnail().getHeight()); + s.setInt (19, embed.getThumbnail().getWidth()); + s.setString (20, embed.getThumbnail().getUrl()); + s.setString (21, embed.getThumbnail().getProxyUrl()); + }else { + s.setNull(18, Types.INTEGER); + s.setNull(19, Types.INTEGER); + s.setNull(20, Types.VARCHAR); + s.setNull(21, Types.VARCHAR); + } + s.setTimestamp(22, timestamp(embed.getTimestamp())); + s.setString (23, embed.getTitle()); + s.setString (24, embed.getType().name()); + s.setString (25, embed.getUrl()); + s.setBoolean (26, embed.isEmpty()); + s.setBoolean (27, embed.isSendable()); + if(embed.getVideoInfo() != null) { + s.setInt (28, embed.getVideoInfo().getHeight()); + s.setInt (29, embed.getVideoInfo().getWidth()); + s.setString (30, embed.getVideoInfo().getUrl()); + } else { + s.setNull(28, Types.INTEGER); + s.setNull(29, Types.INTEGER); + s.setNull(30, Types.VARCHAR); + } + for (int i = 0; i < embed.getFields().size(); i++) + storeEmbedField(embed.getFields().get(i), mid, i); + + + s.executeUpdate(); + return mid; + + } + public static long storeEmbedField(MessageEmbed.Field field, long embed_mid, int position) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.embed_field_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.embed_field " + + "(mid,name,value,inline,position,embed_mid)" + + " VALUES (?,?,?,?,?,?)"); + + s.setLong(1, mid); + s.setString(2, field.getName()); + s.setString(3, field.getValue()); + s.setBoolean(4, field.isInline()); + s.setInt(5, position); + s.setLong(6, embed_mid); + + s.executeUpdate(); + return mid; + } + public static long storeEmote(Emote emote) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.emote_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.emote " + + "(mid,discord_id,guild_id,name,image_url,animated,available,managed,roles_ids)" + + " VALUES (?,?,?,?,?,?,?,?,?)"); + + s.setLong(1, mid); + s.setLong(2, emote.getIdLong()); + if(emote.getGuild()!=null) + s.setLong(3, emote.getGuild().getIdLong()); + else + s.setNull(3, Types.BIGINT); + s.setString(4, emote.getName()); + s.setString(5, emote.getImageUrl()); + s.setBoolean(6, emote.isAnimated()); + s.setBoolean(7, emote.isAvailable()); + s.setBoolean(8, emote.isManaged()); + s.setArray(9, emote.getRoles().stream().map(Role::getIdLong).collect(juliaSqlArrayCollector("bigint"))); + + s.executeUpdate(); + + return mid; + } + public static long storeRichPresence(RichPresence rp) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.rich_presence_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.rich_presence " + + "(mid,app_id,session_id,state,details,flags,sync_id,party_id,party_max,party_size,small_img_key,small_img_text,large_img_key,large_img_text)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); + s.setLong(1, mid); + s.setLong(2, rp.getApplicationIdLong()); + if(rp.getSessionId() != null) + s.setString(3, rp.getSessionId()); + else + s.setNull(3, Types.VARCHAR); + if(rp.getState() != null) + s.setString(4, rp.getState()); + else + s.setNull(4, Types.VARCHAR); + if(rp.getDetails() != null) + s.setString(5, rp.getDetails()); + else + s.setNull(5, Types.VARCHAR); + s.setInt(6, rp.getFlags()); + if(rp.getSyncId() != null) + s.setString(7, rp.getSyncId()); + else + s.setNull(7, Types.VARCHAR); + if(rp.getParty() != null) { + s.setString(8, rp.getParty().getId()); + s.setLong(9, rp.getParty().getMax()); + s.setLong(10, rp.getParty().getSize()); + } else { + s.setNull(8, Types.VARCHAR); + s.setNull(9, Types.BIGINT); + s.setNull(10, Types.BIGINT); + } + if(rp.getSmallImage() != null) { + s.setString(11, rp.getSmallImage().getKey()); + s.setString(12, rp.getSmallImage().getText()); + } else { + s.setNull(11, Types.VARCHAR); + s.setNull(12, Types.VARCHAR); + } + if(rp.getLargeImage() != null) { + s.setString(13, rp.getLargeImage().getKey()); + s.setString(14, rp.getLargeImage().getText()); + } else { + s.setNull(13, Types.VARCHAR); + s.setNull(14, Types.VARCHAR); + } + s.executeUpdate(); + return mid; + } + public static long storeRole(Role r) throws SQLException { + // Récupération du futur mid + long mid = genId("objets.role_mid"); + + // Stoquage des données + PreparedStatement s = Julia.theJulia.juliaBDD + .prepareStatement("INSERT INTO objets.role " + + "(mid,guild_id,role_id,name,color_raw,perms_raw,position,hoisted,mentionable,managed,public_role,boost,bot_id,integration_id)" + + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); + s.setLong(1, mid); + s.setLong(2, r.getGuild().getIdLong()); + s.setLong(3, r.getIdLong()); + s.setString(4, r.getName()); + s.setInt(5, r.getColorRaw()); + s.setLong(6, r.getPermissionsRaw()); + s.setInt(7, r.getPosition()); + s.setBoolean(8, r.isHoisted()); + s.setBoolean(9, r.isMentionable()); + s.setBoolean(10, r.isManaged()); + s.setBoolean(11, r.isPublicRole()); + s.setBoolean(12, r.getTags().isBoost()); + s.setLong(13, r.getTags().getBotIdLong()); + s.setLong(14, r.getTags().getIntegrationIdLong()); + + s.executeUpdate(); + + return mid; + } + + public static final Timestamp timestamp(long tstmp) { + return Timestamp.from(Instant.ofEpochSecond(tstmp)); + } + + public static final Timestamp timestamp(OffsetDateTime odt) { + if (odt != null) + return Timestamp.valueOf(odt.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime()); + else + return null; + + } + + public static final String emoji(Emoji odt) { + if(odt==null) + return "null"; + if(odt.isEmoji()) + return odt.getAsCodepoints(); + if(odt.isEmote()) + return Long.toString(odt.getIdLong()); + return null; + } + + public static final String reactionEmote(ReactionEmote odt) { + if(odt==null) + return "null"; + if(odt.isEmoji()) + return odt.getAsCodepoints(); + if(odt.isEmote()) + return Long.toString(odt.getIdLong()); + return null; + } + + public static final String messageReaction(MessageReaction mr) { + if(mr==null) return null; + if(mr.hasCount()) + return mr.getCount()+reactionEmote(mr.getReactionEmote()); + else + return reactionEmote(mr.getReactionEmote()); + } + + public static final Collector, Array> juliaSqlArrayCollector(String dataType){ + return new Collector, Array>(){ + + @Override + public BiConsumer, T> accumulator() { + return List::add; + } + + @Override + public Set characteristics() { + return Set.of(); + } + + @Override + public BinaryOperator> combiner() { + return (l,r)->{l.addAll(r);return l;}; + } + + @Override + public Function, Array> finisher() { + return lst -> { + Object[] arr = new Object[lst.size()]; + lst.toArray(arr); + try { + return Julia.theJulia.juliaBDD.createArrayOf(dataType,arr); + } catch (SQLException e) { + erreur("SQL pas content en essayant de créer un tableau ...", e); + } + return null; + }; + } + + @Override + public Supplier> supplier() { + return ArrayList::new; + } + + }; + + } + + @FunctionalInterface + public static interface FunctionWithException { + + R apply(T t) throws E; + } + private static + Function unex(FunctionWithException fe) { + return arg -> { + try { + return fe.apply(arg); + } catch (Exception e) { + throw new RuntimeException(e); + } + }; + } ////////////////////DB UTILS//////////////////// + //TODO: La javadoc de tout ca, à refaire quand le postgresql sera refait. public static void addPermissionHolders(long geid,List holders, Connection db) throws SQLException { for(IPermissionHolder holder : holders) { - PreparedStatement s = db.prepareStatement("INSERT INTO permissionUpdateHolders VALUES (NULL,?,?,?,?)"); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.permissionUpdateHolders VALUES (DEFAULT,?,?,?,?)"); s.setLong(1, geid); s.setString(2, (holder.getClass().equals(Member.class))?"MEMBER":"ROLE"); s.setLong(3, (holder.getClass().equals(Member.class))?((Member)holder).getUser().getIdLong():((Role)holder).getIdLong()); @@ -1348,7 +2481,7 @@ public class EcouteurDEvents implements EventListener{ } } public static void addPermissionHolder(long geid,IPermissionHolder holder, Connection db) throws SQLException { - PreparedStatement s = db.prepareStatement("INSERT INTO permissionUpdateHolders VALUES (NULL,?,?,?,?)"); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.permissionUpdateHolders VALUES (DEFAULT,?,?,?,?)"); s.setLong(1, geid); s.setString(2, (holder.getClass().equals(Member.class))?"MEMBER":"ROLE"); s.setLong(3, (holder.getClass().equals(Member.class))?((Member)holder).getUser().getIdLong():((Role)holder).getIdLong()); @@ -1358,7 +2491,7 @@ public class EcouteurDEvents implements EventListener{ } public static void addRoles(long geid,List roles, Connection db) throws SQLException { for(Role r : roles) { - PreparedStatement s = db.prepareStatement("INSERT INTO role VALUES (NULL,?,?)"); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.role VALUES (DEFAULT,?,?)"); s.setLong(1, geid); s.setLong(2, r.getIdLong()); s.executeUpdate(); @@ -1366,7 +2499,7 @@ public class EcouteurDEvents implements EventListener{ } public static void addEmbedMessage(long geid,List messages, Connection db) throws SQLException { for(MessageEmbed m : messages) { - PreparedStatement s = db.prepareStatement("INSERT INTO embedMessage VALUES (NULL,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.embedMessage VALUES (DEFAULT,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); s.setLong(1, geid); if(m.getAuthor()==null) { s.setObject(2, null); @@ -1418,7 +2551,7 @@ public class EcouteurDEvents implements EventListener{ int embedID = rs.getInt(1); for(MessageEmbed.Field f : m.getFields()) { - PreparedStatement ss = db.prepareStatement("INSERT INTO embedMessageField VALUES (NULL,?,?,?,?)"); + PreparedStatement ss = db.prepareStatement("INSERT INTO juliaEvents.embedMessageField VALUES (DEFAULT,?,?,?,?)"); ss.setInt(1, embedID); ss.setString(2, f.getName()); ss.setString(3, f.getValue()); @@ -1429,7 +2562,7 @@ public class EcouteurDEvents implements EventListener{ } } public static int addMessage(Message m, Connection db) throws SQLException { - PreparedStatement s = db.prepareStatement("INSERT INTO message VALUES (NULL,?,?,?,?,?,?,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.message VALUES (DEFAULT,?,?,?,?,?,?,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); s.setLong(1, m.getIdLong()); s.setLong(2, m.getAuthor().getIdLong()); s.setLong(3, m.getChannel().getIdLong()); @@ -1449,7 +2582,7 @@ public class EcouteurDEvents implements EventListener{ return mID; } public static int addMessageReaction(MessageReaction r, Connection db) throws SQLException { - PreparedStatement s = db.prepareStatement("INSERT INTO messageReaction VALUES (NULL,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.messageReaction VALUES (DEFAULT,?,?,?,?)",Statement.RETURN_GENERATED_KEYS); s.setInt(1, r.getCount()); s.setLong(2, r.getMessageIdLong()); s.setString(3, r.getReactionEmote().getName()); @@ -1464,7 +2597,7 @@ public class EcouteurDEvents implements EventListener{ } public static long addSelfUser(SelfUser user, Connection db) throws SQLException { long hash = hash(""+user.getAllowedFileSize()+user.isVerified()+user.isMfaEnabled()); - PreparedStatement s = db.prepareStatement("INSERT INTO selfUser VALUES (?,?,?,?,?)"); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.selfUser VALUES (?,?,?,?,?)"); s.setLong(1, hash); s.setLong(2, user.getAllowedFileSize()); List tags = new ArrayList<>(); @@ -1489,7 +2622,7 @@ public class EcouteurDEvents implements EventListener{ long id = s.getResultSet().getLong("mid")+1; for (int i = 0; i < la.size(); i++) { long aid = addActivity(la.get(i), db); - PreparedStatement s2 = db.prepareStatement("INSERT INTO activityListsItems VALUES (NULL,?,?)"); + PreparedStatement s2 = db.prepareStatement("INSERT INTO juliaEvents.activityListsItems VALUES (DEFAULT,?,?)"); s2.setLong(1, id); s2.setLong(2, aid); s2.executeUpdate(); @@ -1502,7 +2635,7 @@ public class EcouteurDEvents implements EventListener{ public static Long addActivity(Activity g, Connection db) throws SQLException { if(g==null)return null; String h = ""; - PreparedStatement s = db.prepareStatement("INSERT INTO activities VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,UNHEX(?),?,?,?,?)"); + PreparedStatement s = db.prepareStatement("INSERT INTO juliaEvents.activities VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,UNHEX(?),?,?,?,?)"); s.setString(2, g.getType().name());h+=g.getType().name(); s.setString(3, g.getName());h+=g.getName(); s.setString(4, g.getUrl());h+=g.getUrl(); @@ -1554,6 +2687,13 @@ public class EcouteurDEvents implements EventListener{ return h; } + public static String bitvarying(byte[] arr) { + StringBuilder sb = new StringBuilder(); + for(byte b : arr) + sb.append(Integer.toBinaryString((int)b)); + return sb.toString(); + } + @SafeVarargs public static T c(T... p) { for(T t : p) @@ -1589,11 +2729,6 @@ public class EcouteurDEvents implements EventListener{ return new String(c); } - public static String emoji(Emoji e) { - if(e==null)return "null"; - if(e.isEmoji())return e.getAsCodepoints(); - else return e.getId(); - } public static String rEmote(ReactionEmote e) { if(e==null)return "null"; if(e.isEmoji())return e.getAsCodepoints(); diff --git a/src/main/java/com/bernard/juliabot/Julia.java b/src/main/java/com/bernard/juliabot/Julia.java index 42cf0f1..a7a1db3 100644 --- a/src/main/java/com/bernard/juliabot/Julia.java +++ b/src/main/java/com/bernard/juliabot/Julia.java @@ -1,5 +1,8 @@ package com.bernard.juliabot; +import static com.bernard.juliabot.api.Julia.erreur; +import static com.bernard.juliabot.api.Julia.status; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -16,123 +19,228 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Properties; import java.util.Scanner; import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import java.util.function.Predicate; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; import org.apache.commons.io.output.TeeOutputStream; -import com.bernard.juliabot.JuliaAddon.JarWithMultipleAddonsException; +import com.bernard.juliabot.JuliaAddon.JarAuxMultiplesAddonsException; import com.bernard.juliabot.JuliaAddon.JuliaClassLoader; import com.bernard.juliabot.api.CCommande; -import com.bernard.juliabot.api.Command; -import com.bernard.juliabot.api.Discord; +import com.bernard.juliabot.api.Commande; +import com.bernard.juliabot.api.EventDiscord; import com.thedeanda.lorem.LoremIpsum; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.events.Event; +import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.events.GenericEvent; +import net.dv8tion.jda.api.requests.GatewayIntent; +/** + * Classe principale de JuL'IA, qui contient notamment toutes les données liées à l'execution. + * @author mysaa + * + */ public class Julia { - public static final String juliaddonsFolder = "/home/julia/juliaddons/"; - - public static final String sysinPipe = "/home/julia/entree"; - - public static final String CONNECTION_DATA_FILEPATH = "/var/julia/julia.conn"; + /** + * Le dossier dans lequel chercher les juliaddons + */ + public static final String dossierJuliaddons = "/srv/julia/juliaddons/"; + /** + * Le pipe linux qui sert de sysin, plutot que le sysin normal, car julia doit être lancée comme un démon. + */ + public static final String sysinPipe = "/srv/julia/entree"; + /** + * Le fichier qui contient toutes les informations de connection. + */ + public static final String fichierDeConnection = "/srv/julia/julia.conn"; + /** + * Le pkg de l'internaddon afin de forcer son chargement. + */ + public static final String internaddonPkg = "com.bernard.juliabot.internaddon"; + /** + * L'unique instance de julia créee pendant tout le programme. + */ static Julia theJulia; + /** + * L'instance de JDA reliée à ce programme. + */ JDA jda; - Map avalivableAddons;// pkg+version->addon - Map laboratoriesIdentifieurs;//Store channels IDs ... + /** + * Liste des addons disponibles. + * L'addon pkg est disponible ssi addonsDispos.containsKey(pkg). + * L'addon pkg est disponible dans sa version ver ssi addonsDispos.get(pkg).containsKey(ver). + * + * L'addon est alors addonsDispos.get(pkg).get(ver). + */ + Map> addonsDispos; // addons.(pkg).(version)->addon - Map laboratoires; + /** + * Liste tous les identifiants de laboratoire afin de pouvoir savoir dans quel laboratoire + * une commande/event doit être lancée. + * + * Les clés sont des identifiants discord de guilde, channel, user, catégorie etc... + * TODO: Stoquage dynamique dans la base de données. + */ + Map identifieursDeLabo; //Store channels IDs ... - Map fileTrack;// + /** + * Liste de tous les laboratoires disponibles, indéxés selon leur identifiant (chaine de caractères) + */ + Map laboratoires; + /** + * Le laboratoire par défaut, qui recoit les commandes et les évents dans le cas où on ne peux pas + * détecter le laboratoire source. + */ + Laboratoire laboParDefaut; + /** + * Liste des timestamps de dernière modifications des fichiers dans le dossier juliaddons afin d'éviter + * une relecture de fichiers non-modifiée afin de ne pas punir une mise à jour de la + * liste des addons répétitive. + */ + Map traqueFichiers;// + + /** + * L'écouteur d'events qui est liée à la Jda associée à cette instance de Julia. + */ EcouteurDEvents lecouteur; - ReadLoop sysinator; - Connection eventDatabase; - Connection juliaDatabase; + /** + * Le Runnable qui lit le canal d'entré spécifié dans *sysinPipe*, afin de pouvoir le + * contrôller. + */ + BoucleSysin sysinator; - JuliaErrPrintStream syserr; + /** + * Connection SQL vers la base de données de Julia. + */ + Connection juliaBDD; + /** + * Un printstream qui est dirigé vers le salon keskivapa de Discord. + */ + PrintStreamDiscord syserr; + /** + * Une référence au syserr original du programme, car il aura été remplacé par un printstream + * affichant dans le vrai syserr mais aussi dans keskivapa. + * + * Il doit être accessible afin de pouvoir écrire différement des informations dans le syserr + * et dans le canal discord. + */ + PrintStream vraiSyserr = System.err; + /** + * Un lien vers le textChannel status du discord. + */ + TextChannel statusTextChannel; + + public static void main(String[] args) { + theJulia = new Julia(); + theJulia.startup(); + } + + /** + * Crée toutes les tables, vides. + */ public Julia() { - avalivableAddons = new HashMap<>(); - laboratoriesIdentifieurs = new HashMap<>(); + addonsDispos = new HashMap<>(); + identifieursDeLabo = new HashMap<>(); laboratoires = new HashMap<>(); - - fileTrack = new HashMap<>(); + traqueFichiers = new HashMap<>(); } + /** + * Lance le programme Julia + */ public synchronized void startup() { BufferedReader bis; try { - bis = new BufferedReader(new FileReader(CONNECTION_DATA_FILEPATH)); + // Lecture de la configuration + bis = new BufferedReader(new FileReader(fichierDeConnection)); String token = bis.readLine(); + String sqlUser = bis.readLine(); + String sqlPassword = bis.readLine(); + String urlAndPort = bis.readLine(); + long guildHello = Long.parseLong(bis.readLine()); + long textChannelHello = Long.parseLong(bis.readLine()); + long guildErr = Long.parseLong(bis.readLine()); + long textChannelErr = Long.parseLong(bis.readLine()); + long guildStatus = Long.parseLong(bis.readLine()); + long textChannelStatus = Long.parseLong(bis.readLine()); + bis.close(); - //Set up mysql cnnections (events & data) + + //Set up sql connections (events & data) Properties connectionProps = new Properties(); - connectionProps.put("user", bis.readLine()); - connectionProps.put("password", bis.readLine()); - connectionProps.put("serverTimezone", "UTC"); + connectionProps.put("user", sqlUser); + connectionProps.put("password", sqlPassword); + connectionProps.put("serverTimezone", "UTC"); connectionProps.put("verifyServerCertificate", "false"); connectionProps.put("useSSL", "true"); connectionProps.put("requireSSL", "true"); - String urlAndPort = bis.readLine(); try { - eventDatabase = DriverManager.getConnection("jdbc:mysql://"+urlAndPort+"/juliaEvents", connectionProps); - juliaDatabase = DriverManager.getConnection("jdbc:mysql://"+urlAndPort+"/julia", connectionProps); + juliaBDD = DriverManager.getConnection("jdbc:postgresql://"+urlAndPort+"/julia", connectionProps); } catch (SQLException e) { System.err.println("Impossible de se connecter a la BDD, ca ne sers a rien de lancer JuL'IA du coup ... Bonne nuit"); e.printStackTrace(); - syserr.flush(); - bis.close(); return; } - System.out.println("La BDD est chargée" + eventDatabase+","+juliaDatabase); - + System.out.println("La BDD est chargée !"); // Démarrage de JDA et du Bot try { lecouteur = new EcouteurDEvents(this); - jda = JDABuilder.createDefault(token).addEventListeners(getLecouteur()).build(); + jda = JDABuilder.create(token,EnumSet.allOf(GatewayIntent.class)).addEventListeners(getLecouteur()).build(); getJda().awaitReady(); } catch(Exception e) { System.err.println("Impossible de démarrer JuL'IA"); e.printStackTrace(); - syserr.flush(); - bis.close(); return; } - long guildHello = Long.parseLong(bis.readLine()); - long textChannelHello = Long.parseLong(bis.readLine()); + System.out.println("Le JDA est chargé !"); + + statusTextChannel = getJda().getGuildById(guildStatus).getTextChannelById(textChannelStatus); + + status("------------------------------------------------------------------------"); + status("Canal status chargé"); + + sysinator = new BoucleSysin(); + Thread sysinThread = new Thread(sysinator, "sysin-reader"); + sysinThread.start(); + status("Sysin chargé"); + + + // Envoi du bonjour getJda().getGuildById(guildHello).getTextChannelById(textChannelHello).sendMessage(LoremIpsum.getInstance().getWords(10, 15)).complete(); - long guildErr = Long.parseLong(bis.readLine()); - long textChannelErr = Long.parseLong(bis.readLine()); - - syserr = new JuliaErrPrintStream(getJda().getGuildById(guildErr).getTextChannelById(textChannelErr)); + // Mise en place du syserr + syserr = new PrintStreamDiscord(getJda().getGuildById(guildErr).getTextChannelById(textChannelErr)); TeeOutputStream tos = new TeeOutputStream(System.err, syserr.printStream()); + vraiSyserr = System.err; System.setErr(new PrintStream(tos)); Timer syserrtimer = new Timer("Syserr-refresh", true); @@ -140,239 +248,371 @@ public class Julia { @Override public void run() {Julia.theJulia().syserr.flushMessage();} } , 0, 1000); - - bis.close(); + + + + status("Syserr chargé"); + + + + + + } catch (FileNotFoundException e1) { - System.err.println("Euhhhhh je n'ai pas trouvé le fichier "+CONNECTION_DATA_FILEPATH+" et je ne peux donc pas lire ma carte d'identitée"); + System.err.println("Euhhhhh je n'ai pas trouvé le fichier "+fichierDeConnection+" et je ne peux donc pas lire ma carte d'identitée"); e1.printStackTrace(); + System.exit(13); } catch (IOException e1) { - System.err.println("Euhhhhh je n'ai pas réussi à lire le fichier "+CONNECTION_DATA_FILEPATH+" et je ne peux donc pas lire ma carte d'identitée"); + System.err.println("Euhhhhh je n'ai pas réussi à lire le fichier "+fichierDeConnection+" et je ne peux donc pas lire ma carte d'identitée"); e1.printStackTrace(); + System.exit(14); } //Launch update to see every addon in juliaddon/ - update();//Va remplir la map avalivableAddons + addonsMaj();//Va remplir la map avalivableAddons + // On récupère et instancie tous les laboratoires - - //Démarrage du sysin - sysinator = new ReadLoop(); - Thread sysinThread = new Thread(sysinator, "sysin-reader"); - sysinThread.start(); - - System.out.println("Sont disponibles :"+avalivableAddons); - //Loader l'internalddon (hard-coded) - //laboratoires.get('#').loadAddon("com.bernard.juliabot.internaddon", "beta", false);//Pas besoin d'update, il viens d'etre fait - - //Load addons in # and in $ (récupere ce qu'il faut dans la BDD) - Set toLoad = new HashSet<>(); try { - Statement statement = juliaDatabase.createStatement(); - ResultSet result = statement.executeQuery("SELECT * FROM loadedJuliaddons"); + status("Chargement des laboratoires"); + Statement sttm = juliaBDD.createStatement(); + ResultSet rslt = sttm.executeQuery("SELECT labid FROM julia.laboratoires"); + while(rslt.next()) { + String labid = rslt.getString("labid"); + laboratoires.put(labid, new Laboratoire(labid)); + } + laboParDefaut = laboratoires.get("defaut"); + } catch (SQLException e1) { + erreur("Impossible de charger les laboratoires",e1); + } + + + + // Maintenant on charge les addons d'après la base de données. + status("Récupération de la liste des addons à charger"); + Map> toLoad = new HashMap<>(); // labId,addons + try { + Statement statement = juliaBDD.createStatement(); + ResultSet result = statement.executeQuery("SELECT laboratoire,pkg,version FROM julia.addonscharges"); while(result.next()) { - char laboratory = result.getString("laboratory").charAt(0); + String laboratory = result.getString("laboratoire"); String pkg = result.getString("pkg"); String version = result.getString("version"); - toLoad.add(laboratory+pkg+":"+version); + toLoad.putIfAbsent(laboratory, new HashSet<>()); + toLoad.get(laboratory).add(pkg+":"+version); } } catch (SQLException e) { - System.err.println("Impossible de charger les plugins, vous aurez tout a faire a la main !"); - e.printStackTrace(); - syserr.flush(); + erreur("Impossible de lister les plugins à charger, vous aurez tout a faire a la main !", e); } System.out.println("Les addons à charger : "+toLoad); try { - juliaDatabase.createStatement().executeUpdate("DELETE FROM loadedJuliaddons"); + // On vide la table, puisque tout vâ être rechargé. + juliaBDD.createStatement().executeUpdate("DELETE FROM julia.addonscharges"); } catch (SQLException e) { - System.err.println("Je n'ai pas pu vider la table ... atention aux doublons !"); - e.printStackTrace(); - syserr.flush(); + erreur("Je n'ai pas pu vider la table ... attention aux doublons !",e); } - for(String l : toLoad) { - if(!getLaboratoires().containsKey(l.charAt(0))) - getLaboratoires().put(l.charAt(0), new Laboratory(l.charAt(0))); - Laboratory labo = getLaboratoires().get(l.charAt(0)); - labo.loadAddon(l.substring(1, l.lastIndexOf(":")), l.substring(l.lastIndexOf(":")+1), false);//Pas besoin d'update, il viens d'etre fait - + status("Chargement des addons demandés"); + for(String lab : toLoad.keySet()) { + for(String l : toLoad.get(lab)) { + if(!laboratoires.containsKey(lab)) + erreur("Le laboratoire "+lab+" contenait des addons mais n'est pas référencé."); + else { + try { + Laboratoire labo = laboratoires.get(lab); + labo.loadAddon(l.substring(0, l.lastIndexOf(":")), + l.substring(l.lastIndexOf(":")+1), false); // Pas besoin d'update, cela vient d'etre fait + } catch (IllegalStateException | IllegalArgumentException e) { + erreur("Impossible de charger l'addon "+l+" dans le laboratoire "+lab,e); + } + } + + } + } + status("Chargement forcé des internaddons"); + for(Laboratoire lab : laboratoires.values()) { + if(!lab.estCharge(internaddonPkg)) + lab.loadAddon(internaddonPkg,null); } + status("C'est bon, j'ai démarré ! Amusez-vous bien !"); } - public synchronized void update() { - Map avalivableAddons = new HashMap<>(); - File juliaddonFolder = new File(juliaddonsFolder); + /** + * Met à jour la liste des addons en s'appuyant sur la traque des fichiers afin d'éviter une relecture trop fréquente. + */ + public synchronized void addonsMaj() { + status("Mise à jour de la liste des addons disponibles"); + Map> addonsDispos = new HashMap<>(); + File juliaddonFolder = new File(dossierJuliaddons); + Set unchanged = new HashSet<>(); for(File f : juliaddonFolder.listFiles((parent,name)->name.toLowerCase().endsWith(".jar"))){ - if(fileTrack.containsKey(f.getName()) && fileTrack.get(f.getName()) == f.lastModified()) + if(traqueFichiers.containsKey(f.getName()) && traqueFichiers.get(f.getName()) == f.lastModified()) { + unchanged.add(f.getAbsolutePath()); continue;//Le fichier n'a pas bougé, pas besoin de le relire - fileTrack.put(f.getName(), f.lastModified()); + } + traqueFichiers.put(f.getName(), f.lastModified()); try { JarFile jar = new JarFile(f); try { JuliaAddon addon = new JuliaAddon(jar); - String id = addon.pkg+":"+addon.version; - if(avalivableAddons.containsKey(id)) - System.err.println("L'addon "+id+" a déjà été chargée dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxi������me !"); - avalivableAddons.put(id, addon); - }catch(JarWithMultipleAddonsException e) { - Set> addonsEntries = e.getAddonsEntries(); + if(addonsDispos.containsKey(addon.pkg) + && addonsDispos.get(addon.pkg).containsKey(addon.version)) + erreur("L'addon "+addon.pkg+" en version "+addon.version+" a déjà" + + " été chargée dans les fichiers " + + addonsDispos.get(addon.pkg).get(addon.version).fichierJar.getName() + + " et "+jar.getName()+", je garde que le deuxième !"); + addonsDispos.putIfAbsent(addon.pkg, new HashMap<>()); + addonsDispos.get(addon.pkg).put(addon.version, addon); + } catch(JarAuxMultiplesAddonsException e) { + Set> addonsEntries = e.entreesDeLAddon(); for (Set entry : addonsEntries) { try { JuliaAddon addon = new JuliaAddon(jar, entry); String id = addon.pkg+":"+addon.version; - if(avalivableAddons.containsKey(id)) - System.err.println("L'addon "+id+" a déjà été chargée dans les fichiers "+avalivableAddons.get(id).jarFile.getName()+" et "+jar.getName()+", je garde que le deuxi������me !"); - avalivableAddons.put(id, addon); - } catch (JarWithMultipleAddonsException e1) { - System.err.println("THIS SHOULD NOT HAPPEN"); - System.err.println("TOUT EST CASSÉ ALERTE ROUGE !"); - System.err.println("C'est problematique, j'éteint tout, c'est mieux"); - syserr.flush(); + if(addonsDispos.containsKey(id)) + erreur("L'addon "+addon.pkg+" en version "+addon.version+" a déjà" + + " été chargée dans les fichiers " + + addonsDispos.get(addon.pkg).get(addon.version).fichierJar.getName() + + " et "+jar.getName()+", je garde que le deuxième !"); + addonsDispos.putIfAbsent(addon.pkg,new HashMap<>()); + addonsDispos.get(addon.pkg).put(addon.version, addon); + } catch (JarAuxMultiplesAddonsException e1) { + erreur("THIS SHOULD NOT HAPPEN"); + erreur("TOUT EST CASSÉ ALERTE ROUGE !"); + erreur("C'est problematique, j'éteint tout, c'est mieux"); System.exit(31415926); } } - }catch(IllegalStateException e) { - System.err.println(e.getMessage()); - syserr.flush(); } - } catch (IOException e) { - System.err.println("Impossible de lire le fichier jar "+f.getName()); - e.printStackTrace(); - syserr.flush(); + } catch (IllegalStateException | IOException e) { + erreur("Impossible de lire le fichier jar "+f.getName(),e); } - syserr.flush(); } - this.avalivableAddons = avalivableAddons; + this.addonsDispos.forEach((s,m) -> m.forEach((ss,a) -> + { + if(unchanged.contains(a.fichierJar.getName())){ + addonsDispos.putIfAbsent(a.pkg, new HashMap<>()); + addonsDispos.get(a.pkg).put(a.version, a); + } + })); + this.addonsDispos = addonsDispos; + status("Addons disponibles: "+this.addonsDispos);//TODO: Afficher cette liste en jolie liste discord. } - - public Connection getJuliaDatabase() { - return juliaDatabase; - } - - - - public class ReadLoop implements Runnable{ + /** + * Classe implémentant une simple boucle sur le sysin qui permet d'envoyer des commandes à julia + * depuis le serveur. + * @author mysaa + * + */ + public class BoucleSysin implements Runnable{ - boolean running = false; + boolean enCours = false; @Override public void run() { - running = true; + enCours = true; try { Scanner sc = new Scanner(new File(sysinPipe)); - while(running) { - String request = sc.nextLine(); - - System.out.println("Je suis censée avoir lu la commande "+request); - //TODO réagir ... - - + while(enCours) { + if(sc.hasNextLine()) { + String request = sc.nextLine(); + + System.out.println("Je suis censée avoir lu la commande "+request); + //TODO réagir ... + + } } sc.close(); } catch (FileNotFoundException e) { - System.err.println("Erreur de lecture du sysin, je deviens sourd"); - e.printStackTrace(); - syserr.flush(); - running=false; + erreur("Le fichier du sysin est introuvable !",e); + syserr.flush(); + enCours=false; } } } - - public class Laboratory{ - char laboratory; - Map loadedAddons;// : les addons chargés dans ce laboratoire - Map loadedCommands;// : les commandes chargées - Map,Object> callerObjects; // : Les objets instanciés dans ce laboratoire - Map aliases;// - Map,Set> loadedEvents;// Les méthodes à appeler quand un event de cette classe est lancé - Map clazzTrack;// + /** + * Ces objets représentent des laboratoires chargés par julia. Il stoque toutes les références de ce qui est chargé + * au sein même du laboratoire. + * @author mysaa + * + */ + public class Laboratoire{ + + /** + * La chaine de caractères identifiant de manière unique le laboratoire. + */ + String labId; + /** + * Ensemble des addons chargés dans ce laboratoire. + */ + Set addonsCharges; + /** + * Liste des commandes enregistrées, avec pour clé le nom unique de la commande (pas d'alias). + */ + Map commandesEnregistrees; + /** + * Stoque les objets qui ont été instanciés dans le laboratoire, normalement un objet par classe au plus. + */ + Map,Object> objetsDAppel; + /** + * Map permettant la récupération rapide du nom réel d'une commande à partir de son alias. + * alias.(str) -> nom unique de la commande associée à alias. + */ + Map alias; + /** + * Ensemble des events enregistres, rangés par classe dans une map. + * + * Attention, cette map ne stoque pas une méthode associée à une classe d'event aux sous-classes de cet + * event, la recherche doit donc être faite manuelement ou bien dans un autre mapping. + */ + Map,Set> eventsEnregistres; + /** + * Stoque les JuliaClassLoader qui ont servis à charger chaque classe de l'addon, afin d'avoir une recherche plus rapide. + * + * classesTraque.(className) -> classLoader ayant chargé la classe de nom className. + */ + Map classesTraque; - - public Laboratory(char laboratory) { - this.laboratory = laboratory; - loadedAddons = new HashMap<>(); - loadedCommands = new HashMap<>(); - aliases = new HashMap<>(); - loadedEvents = new HashMap<>(); - clazzTrack = new HashMap<>(); - callerObjects = new HashMap<>(); - } - - public JuliaClassLoader findClassLoader(String className) { - return clazzTrack.get(className); + /** + * Instancie un laboratoire d'identifiant spécifié et n'ayant aucun addon de chargé. + * @param labId L'identifiant du laboratoire. + */ + public Laboratoire(String labId) { + this.labId= labId; + addonsCharges = new HashSet<>(); + commandesEnregistrees = new HashMap<>(); + alias = new HashMap<>(); + eventsEnregistres = new HashMap<>(); + classesTraque = new HashMap<>(); + objetsDAppel = new HashMap<>(); } - public void reloadAddon(String pkg,String version) { - unloadAddon(pkg); + /** + * Renvoie le classLoader ayant chargé la classe dont le nom est donné. + * @param className Le nom de la classe + */ + public JuliaClassLoader trouveLeClassLoader(String className) { + return classesTraque.get(className); + } + + /** + * Demande à l'addon pkg de se décharger, puis de se recharger dans la version spécifiée. + * Si version est null, alors une version + * @param pkg Le pkg de l'addon demandé. + * @param version La version demandée de l'addon, null sinon. + * + * @throws IllegalArgumentException Si l'addon est indisponible tel que spécifié. + */ + public void rechargeAddon(String pkg,String version) { + //TODO version null -> même version. + dechargerAddon(pkg); + if(version==null) + version = addonsDispos.get(pkg).keySet().stream().findAny().get(); loadAddon(pkg, version); } + /** + * Charge un addon dans ce laboratoire. + * @param pkg Le pkg de l'addon + * @param version La version dans laquelle charger l'addon. + * + * @throws IllegalArgumentException Si l'addon est indisponible tel que spécifié. + * @throws IllegalStateException Si l'addon est déga chargé dans ce laboratoire. + */ public void loadAddon(String pkg,String version) { - this.loadAddon(pkg, version, true); + this.loadAddon(pkg, version, false); } + /** + * Charge un addon dans ce laboratoire. + * @param pkg Le pkg de l'addon + * @param version La version dans laquelle charger l'addon. + * @param update Faut-il recharger la liste des addons disponibles avant de charger. + * + * @throws IllegalArgumentException Si l'addon est indisponible tel que spécifié. + * @throws IllegalStateException Si l'addon est déga chargé dans ce laboratoire. + */ public synchronized void loadAddon(String pkg,String version,boolean update) { - if(update)Julia.this.update(); - if(loadedAddons.containsKey(pkg)) - throw new IllegalStateException("Impossible de charger le juliaddon "+pkg+" dans le laboratoire "+laboratory+", il est d������j������ charg������"); + if(update)Julia.this.addonsMaj(); + JuliaAddon addon = Julia.this.addonsDispos.getOrDefault(pkg,new HashMap<>()).getOrDefault(version,null); + if(addon == null) { + System.err.println(Julia.this.addonsDispos); + throw new IllegalArgumentException("L'addon "+pkg+" n'est pas disponible dans sa version "+version); + } + if(estCharge(pkg)) + throw new IllegalStateException("Impossible de charger le juliaddon "+pkg+" dans le laboratoire "+labId+", il est déjà chargé"); + + + status(labId + ": +"+pkg+":"+version); + try { - PreparedStatement s = juliaDatabase.prepareStatement("INSERT INTO loadedJuliaddons (ID,laboratory,pkg,version) VALUES (NULL,?,?,?)"); - s.setString(1, Character.toString(laboratory)); + PreparedStatement s = juliaBDD.prepareStatement("INSERT INTO julia.addonscharges (ID,laboratoire,pkg,version) VALUES (DEFAULT,?,?,?)"); + s.setString(1, labId); s.setString(2, pkg); s.setString(3, version); s.executeUpdate(); } catch (SQLException e) { - System.err.println("Je ne peux pas notifier la BDD que je load le plugin, je le load pas du coup ..."); - e.printStackTrace(); - syserr.flush(); - return; + erreur("Je ne peux pas notifier la BDD que je load le plugin, il ne sera pas chargé automatiquement au prochain démarrage.",e); } - JuliaAddon addon = Julia.this.avalivableAddons.get(pkg+":"+version); - if(addon == null) - throw new IllegalArgumentException("L'addon "+pkg+" n'est pas disponible dans sa version "+version); - JuliaClassLoader classLoader = addon.newClassLoader(this); - classLoader.registerCommandsAndEvents(); - loadedAddons.put(pkg, addon); + JuliaClassLoader classLoader = addon.nouveauClassLoader(this); + classLoader.enregistrerCommadesEtEvents(); + addonsCharges.add(addon); + } - public synchronized void unloadAddon(String pkg) { - if(!loadedAddons.containsKey(pkg)) - return;//SI l'addon n'est pas chargé, on a rien besoin de faire + /** + * Décharge l'addon du laboratoire spécifié + * + * Ne fait rien si l'addon n'était déjà pas chargé. + * @param pkg le pkg de l'addon à décharger. + */ + public synchronized void dechargerAddon(String pkg) { + if(!addonsCharges.stream().anyMatch(addon -> addon.pkg.equals(pkg))) + return;//Si l'addon n'est pas chargé, on a rien besoin de faire + + status(labId + ": -"+pkg); + try { - PreparedStatement s = juliaDatabase.prepareStatement("DELETE FROM juliaddons WHERE laboratory=? AND pkg=?"); - s.setString(1, Character.toString(laboratory)); + PreparedStatement s = juliaBDD.prepareStatement("DELETE FROM julia.addonscharges WHERE laboratoire=? AND pkg=?"); + s.setString(1, labId); s.setString(2, pkg); if(s.executeUpdate() != 1) { System.err.println("Ce juliaddon n'était pas chargé dans la BDD ... très bizzare"); } } catch (SQLException e) { - System.err.println("Je ne peux pas notifier la BDD que je unload le plugin, je l'unload mais vous risquez d'avoir des problemes ..."); - e.printStackTrace(); - syserr.flush(); - return; + erreur("Je ne peux pas notifier la BDD que je unload le plugin, je l'unload mais il risque de se recharger au prochain démarrage.",e); } - JuliaAddon addon = loadedAddons.get(pkg); - addon.classLoaders.get(this.laboratory).unregisterCommandsAndEvents(); - loadedAddons.remove(pkg); + JuliaAddon addon = addonsCharges.stream().filter(a -> a.pkg.equals(pkg)).findAny().get(); + addon.classLoaders.get(this).desenregistrerCommandesEtEvents(); + addonsCharges.remove(addon); } - public synchronized void registerCommand(Method m,Command c) { - if(!loadedCommands.containsKey(c.name())) - loadedCommands.put(c.name(), new CommandeSurchargee(c)); + /** + * Enregistre une commande dans ce laboratoire. + * @param m La méthode à lancer lors de la réception de la commande. + * @param c L'annotation associée à cette methode décrivant la commande. + */ + public synchronized void enregistrerCommande(Method m,Commande c) { + if(!commandesEnregistrees.containsKey(c.name())) + commandesEnregistrees.put(c.name(), new CommandeSurchargee(c)); //Verify that commands asks for good argument - if(!Arrays.stream(m.getParameterTypes()).map(CCommande.class::isAssignableFrom).reduce(Boolean::logicalAnd).get()) + if(!Arrays.stream(m.getParameterTypes()) + .map(CCommande.class::isAssignableFrom) + .reduce(Boolean::logicalAnd) + .orElse(true) /* Si aucune valeur, paramètres vides, ce qui est valide (!true) */) throw new IllegalArgumentException("Les paramètres d'une commande doivent tous implémenter CCommande"); try { @@ -382,59 +622,86 @@ public class Julia { } // Argument OK - //Register aliases + // print un message d'erreur si un alias a déjà été enregistré pour une autre commande - Arrays.stream(c.aliases()) - .filter(aliases::containsKey).filter(alias -> !aliases.get(alias).equals(c.name())) - .forEach(alias -> System.err.println("Faut remplacer l'alias "+alias+", plus de deux addons l'utilisent")); - Arrays.stream(c.aliases()) - .filter(a -> !aliases.containsKey(a)).forEach(alias -> aliases.put(alias, c.name())); + Arrays.stream(c.alias()) + .filter(alias::containsKey) + .filter(als -> !alias.get(als).equals(c.name())) + .forEach(als -> erreur("Faut remplacer l'alias "+als+", plus de deux addons l'utilisent")); + + //Register aliases + Arrays.stream(c.alias()) + .filter(Predicate.not(alias::containsKey)).forEach(als -> alias.put(als, c.name())); //Création de l'objet si ca n'a pas été fait - checkObject(m.getDeclaringClass()); + assureObjet(m.getDeclaringClass()); //Enregistre la nouvelle surcharge - loadedCommands.get(c.name()).surcharger(Arrays.stream(m.getParameterTypes()).collect(Collectors.toSet()), m); + commandesEnregistrees.get(c.name()).surcharger(Arrays.stream(m.getParameterTypes()).collect(Collectors.toSet()), m); } - @SuppressWarnings("unchecked")//It is, in reallity checked - public synchronized void registerEvent(Method m, Discord d) { + /** + * Enregistre un event dans ce laboratoire + * @param m La méthode à executer dans le cas d'un event adéquat + * @param d L'annotation d'event associée. + */ + @SuppressWarnings("unchecked") //It is, in reality checked + public synchronized void enregistrerEvent(Method m, EventDiscord d) { Class[] parameters = m.getParameterTypes(); if(parameters.length != 1) throw new IllegalArgumentException("Les catcheurs d'events ne doivent avoir qu'un seul paramétre, extends Event, la méthode fautive étant "+m.toGenericString()); - if(!Event.class.isAssignableFrom(parameters[0])) + if(!GenericEvent.class.isAssignableFrom(parameters[0])) throw new IllegalArgumentException("Les catcheur d'events ne doivent avoir qu'un paramètre, qui doit extends Event, la méthode fautive étant "+m.toGenericString()); //La méthode est vérifiée - if(!loadedEvents.containsKey(parameters[0])) - loadedEvents.put((Class) parameters[0], new HashSet<>()); - checkObject(m.getDeclaringClass()); - loadedEvents.get(parameters[0]).add(m); - } - - public synchronized void unregisterCommand(Method m,Command c) { - if(loadedCommands.containsKey(c.name())) - throw new IllegalStateException("Une commade "+c.name()+" a déjà été enregistrée !"); - //Unregister aliases - for(String alias:c.aliases()) - aliases.remove(alias, c.name());//Evite de supprimer les alias d'autres commandes qui auraient overwrite - loadedCommands.remove(c.name()); + eventsEnregistres.putIfAbsent((Class) parameters[0], new HashSet<>()); + assureObjet(m.getDeclaringClass()); + eventsEnregistres.get(parameters[0]).add(m); } + /** + * Désenregistre la commande associée à cette annotation de commande. + * @param commande L'annotation de la commande à enlever, nécessaire afin de désenregistrer les alias. + */ + public synchronized void desenregistrerCommande(Commande commande) { + if(!commandesEnregistrees.containsKey(commande.name())) + throw new IllegalStateException("La commande "+commande.name()+" n'est pas enregistrée."); + + //Unregister aliases + for(String als:commande.alias()) + alias.remove(als, commande.name());//Evite de supprimer les alias d'autres commandes qui auraient overwrite. + + commandesEnregistrees.remove(commande.name()); + } + + /** + * Désenregistre l'event associé à cette méthode et cette tannotation. + * @param m La méthode associée à l'event à désenregistrer. + */ @SuppressWarnings("unchecked")//Pour un truc qui n'ets pas censé arriver, donc bon ... - public synchronized void unregisterEvent(Method m, Discord d) { + public synchronized void desenregistrerEvent(Method m) { Class[] parameters = m.getParameterTypes(); - if(!loadedEvents.containsKey(parameters[0]))//N'est pas censé arriver, si l'event a été load, cette HashSet devrai exister - loadedEvents.put((Class) parameters[0], new HashSet<>()); - loadedEvents.get(parameters[0]).remove(m); + + //N'est pas censé arriver, si l'event a été load, cette HashSet devrait exister + eventsEnregistres.putIfAbsent((Class) parameters[0], new HashSet<>()); + + eventsEnregistres.get(parameters[0]).remove(m); } - public void checkObject(Class clazz) { - if(!callerObjects.containsKey(clazz)) { + /** + * Assure qu'un objet de la classe spécifiée a été instancié et est disponible + * dans la liste objetsDAppel. + * + * Si il ne l'est pas, l'instancie. + * @param clazz la classe de l'objet. + */ + public void assureObjet(Class clazz) { + if(!objetsDAppel.containsKey(clazz)) { //Chercher un bon constructeur + Map,Throwable> mauvaisConstructeurs = null; Object o = null; constLoop : for(Constructor constructor : clazz.getConstructors()) { try { @@ -442,11 +709,11 @@ public class Julia { Object[] params = new Object[paramsTypes.length]; for (int i = 0; i < params.length; i++) { switch(paramsTypes[i].getName()) { - case "java.lang.Character": - params[i] = this.laboratory; + case "java.lang.String": + params[i] = this.labId; break; case "java.sql.Connection": - params[i] = Julia.this.juliaDatabase; + params[i] = Julia.this.juliaBDD; break; case "net.dv8tion.jda.core.JDA": params[i] = Julia.this.getJda(); @@ -459,62 +726,96 @@ public class Julia { } o = constructor.newInstance(params); } catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - //Tant pis, constructeur suivant + //Tant pis, constructeur suivant, on enregistre l'erreur au cas où. + if(mauvaisConstructeurs==null)mauvaisConstructeurs = new HashMap<>(); + mauvaisConstructeurs.put(constructor,e); continue constLoop; } if(o != null)break;//Sortir de la boucle, on a notre joli objet } if(o == null) { - System.err.println("Je ne peux pas créer l'objet, faudait mettre un costructeur valide (en mon sens :P)"); - System.err.println("Je fais tout planter du coup, votrez addon sera pas chargé !"); + erreur("Je ne peux pas créer l'objet, faudait mettre un constructeur valide (en mon sens :P)"); + erreur("Je fais tout planter du coup, votrez addon sera pas chargé !"); + if(mauvaisConstructeurs.size()>0) { + erreur("Voici les différentes raisons de mon non-chargement: "); + for(Constructor c : mauvaisConstructeurs.keySet()) { + erreur("Constructeur "+c.toString(),mauvaisConstructeurs.get(c)); + } + } throw new IllegalStateException("Pas de constructeur valable"); } - callerObjects.put(clazz, o); + objetsDAppel.put(clazz, o); } } - - public void trigger(GenericEvent event) { - Class eventClass = event.getClass(); - Set toCall = loadedEvents.get(eventClass); + + /** + * Fonction récursive qui déclenche l'event event de la classe spécifiée et s'appelle sur les parents + * de la classe, afin que les methodes ayant un parmètre GenericEvent déclenche tous les events. + * + * @param event l'objet associé à l'event. + * @param clazz la classe en tant que tel qu'il faille considérer l'event, afin faire progresser la recursion. + */ + @SuppressWarnings("unchecked")// Tout est testé ! + private void declencherSuper(GenericEvent event, Class clazz) { + Set toCall = eventsEnregistres.getOrDefault(clazz,Set.of()); for(Method m : toCall) { - Object callable = callerObjects.get(m.getDeclaringClass()); + Object callable = objetsDAppel.get(m.getDeclaringClass()); try { + // Les erreurs n'ont pour responsable que l'addon, donc on traite quand même les autres. m.invoke(callable, event); } catch (IllegalAccessException e) { - System.err.println("C'est pas joli joli, je suis censé lancer une méthode à laquelle je n'ai pas accès : "+m.toGenericString()); - throw new IllegalStateException(e); + erreur("C'est pas joli joli, je suis censé lancer une méthode à laquelle je n'ai pas accès : "+m.toGenericString(),e); } catch (IllegalArgumentException e) { - System.err.println("La méthode n'est pas censée recevoir de tels erreurs, je devrai avoir chécké la méthode, mais elle ne veut pas de mes arguments ... : "+m.toGenericString()); - throw new IllegalStateException(e); + erreur("La méthode n'est pas censée recevoir de tels erreurs, je devrai avoir checké la méthode," + + " mais elle ne veut pas de mes arguments: "+m.toGenericString(),e); } catch (InvocationTargetException e) { - System.err.println("La méthode à lancé cette exception ... je la relance derrière du coup : "+m.toGenericString()); - e.printStackTrace(); - syserr.flush(); - throw new IllegalStateException(e); + erreur("La méthode à lancé cette exception ... je la relance derrière du coup : "+m.toGenericString(),e); } } + // Appel récursif + Class superClass = clazz.getSuperclass(); + if(superClass != null && GenericEvent.class.isAssignableFrom(superClass)) + declencherSuper(event, (Class) superClass); + for(Class clz : clazz.getInterfaces()) + if(GenericEvent.class.isAssignableFrom(clz)) + declencherSuper(event, (Class) clz); } - public CommandCalled executeCommand(String name, CCommande content) { + /** + * Déclenche l'evenement dans ce laboratoire. + * + * @see declencherSuper + * @param event + */ + public void declencher(GenericEvent event) { + Class eventClass = event.getClass(); + // Cette récursion permet que les @Discord demandant un Generic???????Event soient bien déclenchés. + //TODO: Essayer de stoquer cette récursion afin d'éviter d'appeler la réfléctivité à chaque évent. + declencherSuper(event, eventClass); + } + + /** + * Execute la commande indiquée dans ce laboratoire. + * @param name Le nom de la commande appelé, probablement derrière un alias. + * @param content Le contenu du message. + * @return Un appel à commande permetant de suivre la progression de la dite commande. + */ + public AppelACommande executer(String name, CCommande content) { - String cname = name; + CommandeSurchargee scommande = commandeAssociee(name); - if(aliases.containsKey(name)) - cname = aliases.get(name); - if(!loadedCommands.containsKey(cname)) - throw new IllegalArgumentException("Je ne connais ni la commande, ni l'alias "+cname); + if(scommande==null) + throw new IllegalArgumentException("Je ne connais ni la commande, ni l'alias "+name); - - CommandeSurchargee scommande = loadedCommands.get(cname); - Method m = scommande.getExecutor(content); + Method m = scommande.getExecuteur(content); if(m==null) - throw new IllegalArgumentException("La commande "+cname+" alias "+name+" n'est pas prévue pour s'éxecuter avec un "+content.getClass().getCanonicalName()); + throw new IllegalArgumentException("La commande "+scommande.nom+" alias "+name+" n'est pas prévue pour s'éxecuter avec un "+content.getClass().getCanonicalName()); final Object[] parameters = new Object[m.getParameterCount()]; Arrays.fill(parameters, content); - final Object caller = callerObjects.get(m.getDeclaringClass()); + final Object caller = objetsDAppel.get(m.getDeclaringClass()); - final CommandCalled called = new CommandCalled(m, content, name, cname, caller); + final AppelACommande called = new AppelACommande(m, content, name, scommande.nom, caller); Thread t = new Thread(() -> { @@ -524,25 +825,19 @@ public class Julia { m.invoke(caller, parameters); } catch (IllegalAccessException e) { - System.err.println("Problème d'accès à la méthode "+m.toGenericString()+" ... c'est embêtant"); - e.printStackTrace(); - syserr.flush(); + erreur("Problème d'accès à la méthode "+m.toGenericString()+" ... c'est embêtant",e); called.setExitValue(e.getCause()); } catch (IllegalArgumentException e) { - System.err.println("Étrange, je pensais avoir check les arguments"); - e.printStackTrace(); - syserr.flush(); + erreur("Étrange, je pensais avoir check les arguments",e); called.setExitValue(e.getCause()); } catch (InvocationTargetException e) { //Lui a planté + erreur("L'appel a la commande a planté ...",e.getCause()); called.setExitValue(e.getCause()); - System.err.println("L'appel a la commande a planté ..."); - e.getCause().printStackTrace(); } - syserr.flush(); - called.ended(); + called.termine(); - }, "commande-"+cname+".aka."+name+"-"+System.nanoTime()); + }, "commande-"+scommande.nom+".aka."+name+"-"+System.nanoTime()); called.setThread(t); @@ -550,26 +845,66 @@ public class Julia { return called; } + + /** + * Renvoie la commande associée au nom spécifié, c'est à dire la commande qui + * devrait être lancée si un utilisateur souhaite executer une chaine + * de caractères dont le premier nom est l'entrée. + * @param nom Le mot d'entrée de l'utilisateur + * @return La commande chargée par l'utilisateur, null sinon. + */ + public CommandeSurchargee commandeAssociee(String nom) { + if(commandesEnregistrees.containsKey(nom)) + return commandesEnregistrees.get(nom); // C'est une commande bien nommée ! + if(alias.containsKey(nom)) + return commandesEnregistrees.getOrDefault(alias.get(nom),null); // Or -> alias mal fait + return null; + } + + /** + * Teste si un addon est chargé dans ce laboratoire. + * @param pkg Le pkg de l'addon à tester. + * @return true ssi l'addon est chargé + */ + public boolean estCharge(String pkg) { + return addonsCharges.stream().anyMatch(ad -> ad.pkg.equals(pkg)); + } - public Map getLoadedAddons() { - return loadedAddons; + ////////////////// INTERFACES ////////////////// + /** + * Récupère la liste des addons chargés dans ce laboratoire. + */ + public Set getAddonsCharges() { + return addonsCharges; } - public Map getLoadedCommands() { - return loadedCommands; + /** + * Récupère la liste des commandes enregistrées dans cet addon. + */ + public Map getCommandesEnregistrees() { + return commandesEnregistrees; + } + + /** + * Récupère la liste des aliases enregistrés. + */ + public Map getAlias() { + return alias; } - public Map getAliases() { - return aliases; + /** + * Récupère la liste des events enregistrés dans ce tableau. + */ + public Map, Set> getEventsEnregistres() { + return eventsEnregistres; } - public Map, Set> getLoadedEvents() { - return loadedEvents; - } - - public char getL() { - return laboratory; + /** + * Renvoie l'identifiant de ce laboratoire. + */ + public String getL() { + return labId; } @@ -577,28 +912,99 @@ public class Julia { } - - - - public static void main(String[] args) { - theJulia = new Julia(); - theJulia.startup(); - } - + ///////////// INTERFACES ///////////// + /** + * Renvoie l'unique instance de Julia du programme. + */ public static Julia theJulia() { return theJulia; } + /** + * Renvoie la connection à la base de données de julia. + */ + public Connection getJuliaBDD() { + return juliaBDD; + } + + /** + * Renvoie la JDA utilisée par ce programme. + */ public JDA getJda() { return jda; } - public Map getLaboratoires() { + /** + * Renvoie la liste des laboratoires disponibles dans l'instance. + */ + public Map getLaboratoires() { return laboratoires; } + /** + * Renvoie l'écouteur d'events de cette instance de julia. + */ public EcouteurDEvents getLecouteur() { return lecouteur; } + /** + * Renvoie le syserr original du programme. + */ + public PrintStream realErr() { + return vraiSyserr; + } + + /** + * Renvoie le canal d'erreur envoyant sur le canal keskivapa du discord + */ + public PrintStreamDiscord getSyserr() { + return syserr; + } + + /** + * Renvoie le canal discord où publier les mises à jour de status de julia. + */ + public TextChannel statusTextChannel() { + return statusTextChannel; + } + + public Set pkgSet() { + return addonsDispos.keySet(); + } + + /** + * Renvoie vrai si l'addon spécifié est disponible dans la version spécifiée. + * @param addonPkg Le pkg de l'addon + * @param version La version de l'addon + */ + public boolean checkVersion(String addonPkg, String version) { + return addonsDispos.containsKey(addonPkg) && addonsDispos.get(addonPkg).containsKey(version); + } + + /** + * Renvoie la version disponible la plus récente, au vu de la date de dernière modification du fichier. + * @param addonPkg l'addon à lire, qui doit être disponnible dans au moins une version. + */ + public String latest(String addonPkg) { + Map map = addonsDispos.get(addonPkg); + + System.out.println(addonsDispos); + System.out.println(addonPkg); + if(map==null) + return null; + + // On cherche le plus récent du coup. + String version = null; + long last = 0L; + + for (Entry e : map.entrySet()) + if(e.getValue().derniereModif>last) { + last = e.getValue().derniereModif; + version = e.getKey(); + } + + return version; + } + } diff --git a/src/main/java/com/bernard/juliabot/JuliaAddon.java b/src/main/java/com/bernard/juliabot/JuliaAddon.java index 99daf04..d312631 100644 --- a/src/main/java/com/bernard/juliabot/JuliaAddon.java +++ b/src/main/java/com/bernard/juliabot/JuliaAddon.java @@ -1,5 +1,7 @@ package com.bernard.juliabot; +import static com.bernard.juliabot.api.Julia.erreur; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -16,38 +18,88 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import com.bernard.juliabot.Julia.Laboratory; -import com.bernard.juliabot.api.Command; -import com.bernard.juliabot.api.Discord; -import com.bernard.juliabot.api.JuLIAddon; +import com.bernard.juliabot.Julia.Laboratoire; +import com.bernard.juliabot.api.Commande; +import com.bernard.juliabot.api.EventDiscord; +import com.bernard.juliabot.api.Juliaddon; +/** + * Un objet de cette classe représente un juliaddon, hors contexte de chargement. + * @author mysaa + * + */ public class JuliaAddon { + /** + * Un pattern qui permettre d'extraire le paquet dans lequel est un fichier .class + */ private static final Pattern pkgFromClassName = Pattern.compile("^(\\w+(\\.\\w+){2,})\\.\\w+(\\$\\w+)*$"); + /* + * Un pattern permettant d'extraire la version d'un juliaddon d'un fichier. + */ private static final Pattern jarNameParser = Pattern.compile("^([^_]+)_([^_]+)(_(.+))?.jar$"); - + /** + * Le pkg de l'addon. + */ String pkg; + /** + * La version de l'addon. + */ String version; - JarFile jarFile; - long lastModified; - Set loaderEntries; + /** + * Le fichier jar duquel a été chargé cet addon + */ + JarFile fichierJar; + /** + * Le timestamp de dernière modification du fichier jar au chargement de l'addon, afin de pouvoir tester + * plus rapidement si il est à jour avec le fichier jar associé. + */ + long derniereModif; + /** + * Liste des entrées du fichier jar à contenant l'addon, trèèèèès utile dans le cas d'un jar avec plusieurs addons. + */ + Set entreesDuLoader; - Map classLoaders; - JuliaClassLoader unassignedClassLoader = null; + /** + * Liste les classloaders associés à chaque laboratoire dans lequel est chargé cet addon. + */ + Map classLoaders; + /** + * Un classloader non assigné, qui est créé afin de récupérer des informations sur l'addon à sa création, et qui + * peut être réutilisé pour un laboratoire. + */ + JuliaClassLoader classLoaderNonAssigne = null; - JuLIAddon addon; + /** + * L'annotation à l'origine de l'addon. + */ + Juliaddon addon; + /** + * La classe de cet annotation. + */ Class addonClass; - public JuliaAddon(JarFile jar) throws JarWithMultipleAddonsException { + /** + * Crée un addon à partir de toutes les entrées d'un fichier jar. + * @param jar Le fichier jar à lire. + * @throws JarAuxMultiplesAddonsException Si plusieurs addons sont présents dans le fichier jar. + */ + public JuliaAddon(JarFile jar) throws JarAuxMultiplesAddonsException { this(jar,jar.stream().collect(Collectors.toSet())); } - public JuliaAddon(JarFile jar,Set entriesToRead) throws JarWithMultipleAddonsException { - jarFile = jar; - loaderEntries = entriesToRead; - lastModified = new File(jar.getName()).lastModified(); + /** + * Crée un addon à partir des entrées jar spécifiées. + * @param jar Le fichier à lire. + * @param entreesALire Les entrées à lire. + * @throws JarAuxMultiplesAddonsException Si plusieurs addons sont dans ces entrées. + */ + public JuliaAddon(JarFile jar,Set entreesALire) throws JarAuxMultiplesAddonsException { + fichierJar = jar; + entreesDuLoader = entreesALire; + derniereModif = new File(jar.getName()).lastModified(); classLoaders = new HashMap<>(); //Parsing du nom du fichier @@ -61,59 +113,117 @@ public class JuliaAddon { //Sets addon,pkg,version(si redefini) et addonClass - unassignedClassLoader = new JuliaClassLoader(jar, entriesToRead,new DummyLaboratory()); + classLoaderNonAssigne = new JuliaClassLoader(jar, entreesALire,new LaboFactice()); } - public synchronized JuliaClassLoader newClassLoader(Laboratory laboratory) { - if(unassignedClassLoader==null) + /** + * Crée un classloader pour le laboratoire donné. + * @param laboratoire le laboratoire qui sera associé au classloader. + * @return Un classloader qui peut charger ce Juliaddon. + */ + public synchronized JuliaClassLoader nouveauClassLoader(Laboratoire laboratoire) { + if(classLoaderNonAssigne==null) try { - JuliaClassLoader cl = new JuliaClassLoader(jarFile, loaderEntries,laboratory); - classLoaders.put(laboratory.laboratory, cl); + JuliaClassLoader cl = new JuliaClassLoader(fichierJar, entreesDuLoader,laboratoire); + classLoaders.put(laboratoire, cl); return cl; - } catch (JarWithMultipleAddonsException e) { - System.err.println("Cette erreur n'est pas censée arriver, alerte rouge"); + } catch (JarAuxMultiplesAddonsException e) { + erreur("Cette erreur n'est pas censée arriver, alerte rouge"); System.exit(685533990); } - JuliaClassLoader cl = unassignedClassLoader; - unassignedClassLoader = null; - cl.laboratory = laboratory; - classLoaders.put(laboratory.laboratory, cl); + JuliaClassLoader cl = classLoaderNonAssigne; + classLoaderNonAssigne = null; + cl.laboratoire = laboratoire; + classLoaders.put(laboratoire, cl); return cl; } - - public String getName() { - return addon.name(); + /** + * Récupère le nom de cet addon, tel que spécifié par le développeur. + */ + public String getNom() { + return addon.nom(); } + /** + * Renvoie la version de cet addon. + */ public String getVersion() { return version; } + /** + * Renvoie le pkg de cet addon (qu'on peut voir comme son ID) + */ + public String getPkg() { + return pkg; + } + + public JarFile getFichierJar() { + return fichierJar; + } + + public long getDerniereModif() { + return derniereModif; + } + + public JuliaClassLoader getLoader(Laboratoire labo) { + return classLoaders.get(labo); + } + /** + * Un classloader prévu pour lire des Juliaddons depuis des entrées de fichier jar. + * @author mysaa + * + */ public class JuliaClassLoader extends ClassLoader { - Map> loadedClasses; - Set entries; + /** + * Enregistres les classes déjà chargées pour un chargement plus rapide. + */ + Map> classesChargees; + /** + * L'ensemble des entrées que ce classloader à «le droit» de lire. + */ + Set entrees; + /** + * Le fichier jar associé à ce classloader. + */ JarFile jar; - Laboratory laboratory = null; + /** + * Le laboratoire associé à ce classloader. + */ + Laboratoire laboratoire = null; - HashSet registeredCommands; - HashSet registeredEvents; + /** + * Liste les commandes enregistrées par ce classloader. + */ + Set commandesEnregistrees; + /** + * Liste les events enregistrées par ce classloader. + */ + Set eventsEnregistrees; - public JuliaClassLoader(JarFile jar,Set entriesToRead,Laboratory labo) throws JarWithMultipleAddonsException { + /** + * Crée un classloader pour un certain jeu d'entrées jar dans un laboratoire. + * @param jar le fichier jar duquel lire les entrées. + * @param entreesALire Les entrées à lire pour ce classloader + * @param labo Le laboratoire dans lequel est plongé ce classloader. + * @throws JarAuxMultiplesAddonsException Si plusieurs addons sont trouvés dans le jar. Un classloader, un addon. + */ + public JuliaClassLoader(JarFile jar,Set entreesALire,Laboratoire labo) throws JarAuxMultiplesAddonsException { super(); - entries = entriesToRead; + entrees = entreesALire; this.jar = jar; - loadedClasses = new HashMap<>(); - this.laboratory = labo; + classesChargees = new HashMap<>(); + this.laboratoire = labo; Set> readClasses = new HashSet<>(); Map juliaddons = new HashMap<>(); - for(JarEntry entry : entriesToRead) { + for(JarEntry entry : entreesALire) { if(entry.isDirectory()) continue; if(!entry.getName().endsWith(".class")) @@ -130,37 +240,37 @@ public class JuliaAddon { readClasses.add(clazz); //Instantiated class - if(clazz.isAnnotationPresent(JuLIAddon.class)) { + if(clazz.isAnnotationPresent(Juliaddon.class)) { //Declare package and new addon Matcher m = pkgFromClassName.matcher(clazz.getName()); if(!m.matches()) throw new IllegalArgumentException("Le nom de la classe est invalide pour un Juliaddon (il faut au moins trois de profondeur dans le package) : "+clazz.getName()); String pkg = m.group(1); + if(pkg==null) + throw new IllegalArgumentException("Imposible de récupérer le pkg."); if(juliaddons.containsKey(pkg)) - throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , d��placez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName()); + throw new IllegalArgumentException("Il existe deja un juliaddon dans le package "+pkg+" , déplacez "+clazz.getName()+" ou "+juliaddons.get(pkg).getName()); juliaddons.put(pkg, entry); //If overwritten, will JarWithMultipleAddonsException - JuliaAddon.this.addon = clazz.getAnnotation(JuLIAddon.class); + JuliaAddon.this.addon = clazz.getAnnotation(Juliaddon.class); JuliaAddon.this.pkg = pkg; JuliaAddon.this.version = addon.version().isEmpty()?version:addon.version(); JuliaAddon.this.addonClass = clazz; } }catch (ClassFormatError e) { - System.err.println("Impossible de lire cette classe, son format est incorrect ... veuillez recompiler le jar"); - e.printStackTrace(); + erreur("Impossible de lire cette classe, son format est incorrect ... veuillez recompiler le jar",e); continue; }catch(SecurityException e) { - System.err.println("Vous essayez de mettre cette classe dans un package interdit ! Honte a vous"); - e.printStackTrace(); + erreur("Vous essayez de mettre cette classe dans un package interdit ! Honte a vous",e); continue; } catch (IllegalArgumentException e) { - System.err.println("Le fichier "+entry.getName()+" ne d��cris pas un Juliaddon valide, il n'a donc pas ��t�� charg��, mais faites attention !"); - e.printStackTrace(); + erreur("Le fichier "+entry.getName()+" ne décris pas un Juliaddon valide, il n'a donc pas été chargé, mais faites attention !",e); continue; } } - + if(juliaddons.size()<1) + throw new IllegalStateException("Aucun addon présent dans le fichier !"); //Toutes les classes du Jar ont été lues : Si plusieurs addons, on rentre //dans le if pour lever l'exception, sinon, on initialise le JuliaClassLoader if(juliaddons.size() > 1) { @@ -170,7 +280,7 @@ public class JuliaAddon { for (String pkg : juliaddons.keySet()) addonsEntriesVector.put(pkg, new HashSet<>()); - eLoop : for(JarEntry entry : entriesToRead) { + eLoop : for(JarEntry entry : entreesALire) { if(entry.isDirectory()) continue; if(!entry.getName().endsWith(".class")) @@ -187,26 +297,28 @@ public class JuliaAddon { } } //Si le code atteint ici, le JarEntry n'appartient a aucun pkg valide - System.err.println("Ce jar contiens plusieurs juliaddons. Nichtsdestotroz le fichier "+entry.getName()+" n'a pas de Juliaddon dans son package ou au dessus ... je ne charge donc pas la classe (attention, ca peux ammener a des ClassNotFoundException !!!)"); + erreur("Ce jar contiens plusieurs juliaddons. " + + "Nichtsdestotroz le fichier "+entry.getName()+" n'a pas de Juliaddon dans son package ou au dessus." + + "je ne charge donc pas la classe (attention, ça peux ammener a des ClassNotFoundException !)"); continue; } addonsEntries = new HashSet<>(addonsEntriesVector.values()); - throw new JarWithMultipleAddonsException(addonsEntries); + throw new JarAuxMultiplesAddonsException(addonsEntries); } - //Initialisation du JuliaClassloader - //Les parametres addon, pkg,version et addonCLass ont d��j�� ��t�� initialis��s lors de l'it��ration des fichiers du jar + // Initialisation du JuliaClassloader + // Les paramètres addon, pkg,version et addonCLass ont déjà été initialisés lors de l'itération des fichiers du jar } @Override public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - if(loadedClasses.containsKey(name)) - return loadedClasses.get(name); + if(classesChargees.containsKey(name)) + return classesChargees.get(name); ///Recherche d'une entry qui collerai String fileName = name.replaceAll("\\.", "/")+".class"; - Optional oentry = entries.stream().filter(je -> je.getName().equals(fileName)).findAny(); + Optional oentry = entrees.stream().filter(je -> je.getName().equals(fileName)).findAny(); if(oentry.isPresent()) { try { JarEntry entry = oentry.get(); @@ -215,19 +327,18 @@ public class JuliaAddon { reader.read(classData); reader.close(); Class clazz = defineClass(name,classData,0,(int) entry.getSize()); - loadedClasses.put(name, clazz); + classesChargees.put(name, clazz); return clazz; } catch (IOException e) { - System.err.println("Impossible de lire les donn��es du fichier "+oentry.get().getName()+" dans le jar "+jar.getName()+" je peux vous dire adieu je pense"); - e.printStackTrace(); + erreur("Impossible de lire les données du fichier "+oentry.get().getName()+" dans le jar "+jar.getName()+" je peux vous dire adieu je pense",e); } } - JuliaClassLoader cl = laboratory.findClassLoader(name); + JuliaClassLoader cl = laboratoire.trouveLeClassLoader(name); if(cl != null) try { return cl.loadClass(name, resolve); }catch(ClassNotFoundException e) { - throw new ClassNotFoundException("J'ai délégué le chargement de la classe mais j'aurais pas du ... cette classe ne doit pas exister dans l'addon "+cl.getAddon().getName(),e); + throw new ClassNotFoundException("J'ai délégué le chargement de la classe mais j'aurais pas du ... cette classe ne doit pas exister dans l'addon "+cl.getAddon().getNom(),e); } else try { @@ -238,73 +349,113 @@ public class JuliaAddon { } - public void registerCommandsAndEvents() { - registeredCommands = new HashSet<>(); - registeredEvents = new HashSet<>(); + /** + * Enregistre dans le laboratoire toutes les commandes et + * les events présents dans les classes de ce classloader + */ + public void enregistrerCommadesEtEvents() { + commandesEnregistrees = new HashSet<>(); + eventsEnregistrees = new HashSet<>(); Set toWatch = new HashSet<>(); Collections.addAll(toWatch, JuliaAddon.this.addonClass.getMethods()); - for (Class clazz : JuliaAddon.this.addon.searchPath()) + for (Class clazz : JuliaAddon.this.addon.filles()) try { Collections.addAll(toWatch, loadClass(clazz.getName()).getMethods());//loadClass(clazz.getName()) poir eviter les references cassees par les classloaders } catch (SecurityException | ClassNotFoundException e) { - e.printStackTrace(); - System.err.println("L'addon "+JuliaAddon.this.addonClass.getName()+" spécifie la classe "+clazz.getName()); + erreur("L'addon "+JuliaAddon.this.addonClass.getName()+" spécifie la classe "+clazz.getName(),e); } for(Method m : toWatch) { - Command c = m.getAnnotation(Command.class); - Discord d = m.getAnnotation(Discord.class); + Commande c = m.getAnnotation(Commande.class); + EventDiscord d = m.getAnnotation(EventDiscord.class); if(c != null) { - registeredCommands.add(m); - laboratory.registerCommand(m, c); + commandesEnregistrees.add(m); + laboratoire.enregistrerCommande(m, c); }else if(d != null) { - registeredEvents.add(m); - laboratory.registerEvent(m, d); + eventsEnregistrees.add(m); + laboratoire.enregistrerEvent(m, d); } } } - public void unregisterCommandsAndEvents() { - for(Method m : registeredCommands) { - Command c = m.getAnnotation(Command.class); - registeredCommands.add(m); - laboratory.unregisterCommand(m, c); + /** + * Désenregistre du laboratoire associé toutes les commandes et les + * events présents dans les classes de ce classloader. + */ + public void desenregistrerCommandesEtEvents() { + for(Method m : commandesEnregistrees) { + Commande c = m.getAnnotation(Commande.class); + commandesEnregistrees.add(m); + laboratoire.desenregistrerCommande(c); } - for(Method m : registeredEvents) { - Discord d = m.getAnnotation(Discord.class); - registeredEvents.add(m); - laboratory.unregisterEvent(m, d); + for(Method m : eventsEnregistrees) { + eventsEnregistrees.add(m); + laboratoire.desenregistrerEvent(m); } - registeredCommands.clear(); - registeredEvents.clear(); + commandesEnregistrees.clear(); + eventsEnregistrees.clear(); } + /** + * Récupère l'addon pour lequel est créé ce classloader. + */ public JuliaAddon getAddon() { return JuliaAddon.this; } + + public Set getCommandesEnregistrees() { + return commandesEnregistrees; + } + + public Set getEventsEnregistrees() { + return eventsEnregistrees; + } } - public static final class JarWithMultipleAddonsException extends Exception{ + /** + * Une exception trahissant plusieurs addons dans un jeu d'entrées jar. + * + * L'exception contient des données qui devraient suffire à sélectionner de manière + * plus judicieuse les entrées afin d'eviter le problème. + * @author mysaa + * + */ + public static final class JarAuxMultiplesAddonsException extends Exception{ private static final long serialVersionUID = -7557959851687207287L; + /** + * Partition des entrées qui devrait séparer correctement les addons + */ Set> addonsEntries; - public JarWithMultipleAddonsException(Set> addonsEntries) { + public JarAuxMultiplesAddonsException(Set> addonsEntries) { this.addonsEntries = addonsEntries; } - public Set> getAddonsEntries() { + public Set> entreesDeLAddon() { return addonsEntries; } } - public static final class DummyLaboratory extends Julia.Laboratory{ + /** + * Un laboratoire factice prévu pour observer les fichier jar sans les enregistrer nul part. + * @author mysaa + * + */ + public static final class LaboFactice extends Julia.Laboratoire{ - public DummyLaboratory() { - Julia.theJulia().super(Character.MIN_VALUE); + public LaboFactice() { + Julia.theJulia().super(""); } } + + @Override + public String toString() { + return pkg + ":" + version; + } + + } diff --git a/src/main/java/com/bernard/juliabot/JuliaErrPrintStream.java b/src/main/java/com/bernard/juliabot/JuliaErrPrintStream.java deleted file mode 100644 index cc3e722..0000000 --- a/src/main/java/com/bernard/juliabot/JuliaErrPrintStream.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.bernard.juliabot; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import net.dv8tion.jda.api.MessageBuilder; -import net.dv8tion.jda.api.entities.MessageChannel; - -public class JuliaErrPrintStream extends OutputStream { - - StringBuilder tas = new StringBuilder(2000);// Les 2000 caractères de Discord - - Lock cadenas; - - MessageChannel logChannel; - - public static final int maxlength = 1900; - - public JuliaErrPrintStream(MessageChannel logChan) { - this.cadenas = new ReentrantLock(); - this.logChannel = logChan; - } - - @Override - public void write(int i) throws IOException { - tas.append((char)(i)); - } - - - @Override - public void flush() { - } - - - - public void flushMessage() { - if(tas.length()==0)return; - this.cadenas.lock(); - String str = tas.toString(); - for(int i = 0; i*maxlength < tas.length();i++) { - MessageBuilder builder = new MessageBuilder(); - builder.appendCodeBlock(str.substring(i*maxlength, Math.min((i+1)*maxlength,tas.length())), ""); - logChannel.sendMessage(builder.build()).queue(); - } - tas = new StringBuilder(); - this.cadenas.unlock(); - - } - - PrintStream ps = null; - public PrintStream printStream() { - if(ps == null) - ps = new PrintStream(this); - return ps; - } - -} diff --git a/src/main/java/com/bernard/juliabot/PrintStreamDiscord.java b/src/main/java/com/bernard/juliabot/PrintStreamDiscord.java new file mode 100644 index 0000000..a03877a --- /dev/null +++ b/src/main/java/com/bernard/juliabot/PrintStreamDiscord.java @@ -0,0 +1,184 @@ +package com.bernard.juliabot; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.MessageChannel; + +/** + * Stream de caractères dirigé vers un canal discord. + * + * Les utilisateurs doivent appller flushMessage() afin que soit envoyé le message. + * @author mysaa + * + */ +public class PrintStreamDiscord extends OutputStream { + + /** + * Un buffer stoquant les prochains caractères à afficher. + */ + StringBuilder tas = new StringBuilder(2000);// Les 2000 caractères de Discord + + /** + * Cadenas bloquant le write pendant la création du message discord. + */ + Lock cadenas; + + /** + * Le channel dans lequel envoyer tous les caractères. + */ + MessageChannel logChannel; + + /** + * La longueur maximale d'un message sur discord. + */ + public static final int maxlength = 1900; + + /** + * Crée un canal dirigé vers le canal spécifié. + * @param logChan Un channel discord pour lequel julia à un accès en écriture. + */ + public PrintStreamDiscord(MessageChannel logChan) { + this.cadenas = new ReentrantLock(); + this.logChannel = logChan; + } + + @Override + public void write(int i) throws IOException { + cadenas.lock(); + try { + tas.append((char)(i)); + } finally {cadenas.unlock();} + } + + + @Override + public void flush() { + } + + + /** + * Envoie le buffer dans le salon discord. + */ + public synchronized void flushMessage() { + if(tas.length()==0)return; + this.cadenas.lock(); + String str = tas.toString(); + for(int i = 0; i*maxlength < tas.length();i++) { + MessageBuilder builder = new MessageBuilder(); + builder.appendCodeBlock(str.substring(i*maxlength, Math.min((i+1)*maxlength,tas.length())), ""); + logChannel.sendMessage(builder.build()).queue(); + } + tas = new StringBuilder(); + this.cadenas.unlock(); + + } + + /** + * Une instance de printstream sauvegardée. + */ + PrintStream ps = null; + /** + * Crée si besoin une seule fois un PrintStream écrivant dans cet OutputStream. + */ + public PrintStream printStream() { + if(ps == null) + ps = new PrintStream(this); + return ps; + } + + /** + * Envoie un message découpé en blocs dans le canal spécifié. + * Le message sera découpé en élements d'à peu près la taille max de message. + * @param message Le message à écrire, potentiellement long. + * @param logChannel Le canal de sortie. + */ + public static void logErrMessage(String message, MessageChannel logChannel) { + for(int i = 0; i*maxlength < message.length();i++) { + MessageBuilder builder = new MessageBuilder(); + builder.appendCodeLine(message.substring(i*maxlength, Math.min((i+1)*maxlength,message.length()))); + logChannel.sendMessage(builder.build()).queue(); + builder = new MessageBuilder(); + } + } + /** + * Envoie le message découpé en blocs dans le canal d'erreur de ce PrintStream. + * @param message Le message, potentiellement long, à afficher. + */ + public void errMessage(String message) { + logErrMessage(message, logChannel); + } + + /** + * Log l'erreur d'entrée dans le canal spécifié. Le message est affiché en premier en texte + * brut, puis le Throwable est ensuite affiché dans un ou plusieurs blocs suivant sa taille. + * @param message Le message décrivant le contexte de l'erreur + * @param error L'erreur en elle-même + * @param logChannel Le canal dans lequel afficher l'erreur. + */ + public static void logErrMessageAndThrowable(String message, Throwable error, MessageChannel logChannel) { + StringWriter sw = new StringWriter(); + error.printStackTrace(new PrintWriter(sw)); + String errMessage = sw.toString(); + + if(errMessage.length()+message.length()+1=maxlength) { + // On envoie maintenant + builder.appendCodeBlock(reste.toString(), ""); + logChannel.sendMessage(builder.build()).queue(); + builder = new MessageBuilder(); + reste = new StringBuilder(); + depassement = 0; + } + if(nm.length() >= maxlength) { // Reste est nécessairement vide + // Pas le choix que d'envoyer avec découpage dégueulasse. + for(int i = 0; i*maxlength < nm.length();i++) { + builder.appendCodeBlock(nm.substring(i*maxlength, Math.min((i+1)*maxlength,nm.length())), ""); + logChannel.sendMessage(builder.build()).queue(); + builder = new MessageBuilder(); + } + }else { + reste.append(nm+"\n"); + depassement += nm.length(); + } + } + builder.appendCodeBlock(reste.toString(), ""); + logChannel.sendMessage(builder.build()).queue(); + + } + } + + /** + * Log l'erreur d'entrée dans le canal de ce PrintStream. Le message est affiché en premier en texte + * brut, puis le Throwable est ensuite affiché dans un ou plusieurs blocs suivant sa taille. + * @param message Le message décrivant le contexte de l'erreur. + * @param error L'erreur en elle-même. + */ + public void errMessageAndThrowable(String message, Throwable error) { + logErrMessageAndThrowable(message, error, logChannel); + } + +} diff --git a/src/main/java/com/bernard/juliabot/api/ArgumentsComplexes.java b/src/main/java/com/bernard/juliabot/api/ArgumentsComplexes.java new file mode 100644 index 0000000..85fd19e --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/ArgumentsComplexes.java @@ -0,0 +1,93 @@ +package com.bernard.juliabot.api; + +import java.util.*; + +/** + * Décrit des arguments bash d'une commande type bash. + * + * La commande est séparée en nommes, arguments et flags, ces deux derniers étant + * indépendant de leur position. + * + * Exemple: commande nomme1 nomme2 --flag1 --flag2 --arg1=val1 nomme3 --arg2=val2 --flag3 + * @author mysaa + * + */ +public class ArgumentsComplexes { + + List nommes; + Map arguments; + Set flags; + + /** + * Initialise cet argument avec les paramètres indiqués. + * @param nommes Les nommes, ordonnés de la commande + * @param arguments Map qui à chaque argument associe sa valeur. + * @param flags Ensemble non ordonné des flags. + */ + public ArgumentsComplexes(List nommes, Map arguments, Set flags) { + this.nommes = nommes; + this.arguments = arguments; + this.flags = flags; + } + + /** + * Renvoie la liste ordonnée des nommes. + * @return Liste des nommes. + */ + public List getNommes() { + return Collections.unmodifiableList(nommes); + } + + /** + * Renvoie une map qui à chaque argument spécifié associe sa valeur. + * @return La map des arguments. + */ + public Map getArguments() { + return Collections.unmodifiableMap(arguments); + } + + /** + * Renvoie l'ensemble des flags spécifiés. + * @return L'ensemble des flags. + */ + public Set getFlags() { + return Collections.unmodifiableSet(flags); + } + + /** + * Renvoie true si et seulement si le flag donné en paramètre a été spécifié. + * @param flag le flag a tester + * @return true ssi flag est spécifié. + */ + public boolean hasFlag(String flag) { + return flags.contains(flag); + } + + /** + * Renvoie la valeur associée à l'argument «name», et null si l'argument n'a pas été spécifié. + * @param name le nom de l'argument. + * @return La valeur de l'argument ou null. + */ + public String getArgument(String name) { + return arguments.get(name); + } + + /** + * Renvoie le n-ième nomme de la commande, le 0ème nomme correspondant typiquement au nom + * de la commande elle-même. + * @param pos L'indice du nomme. + * @return La valeur du nomme. + */ + public String getNomme(int pos) { + return nommes.get(pos); + } + + /** + * Renvoie le nombre de nommes de la commande, utile pour tester si tous ont été spécifiés. + * @return Le nombre de nommes. + */ + public int getNommeCount() { + return nommes.size(); + } + +} diff --git a/src/main/java/com/bernard/juliabot/api/CCommande.java b/src/main/java/com/bernard/juliabot/api/CCommande.java index 8739d98..0d7a91f 100644 --- a/src/main/java/com/bernard/juliabot/api/CCommande.java +++ b/src/main/java/com/bernard/juliabot/api/CCommande.java @@ -1,9 +1,16 @@ package com.bernard.juliabot.api; -import com.bernard.juliabot.Julia.Laboratory; - +/** + * Une super-interface décrivant les capacités d'une requête recue. + * @author mysaa + * + */ public interface CCommande { - public Laboratory getLabo(); + /** + * L'ID du laboratoire dans lequel a été lancé la commande + * @return La chaine de caractère de l'ID + */ + public String getLaboId(); } diff --git a/src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java b/src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java new file mode 100644 index 0000000..80ce3ab --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/CCommandeDiscord.java @@ -0,0 +1,60 @@ +package com.bernard.juliabot.api; + +import java.time.OffsetDateTime; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.User; + +/** + * Une CCommande décrivant une requète/commande envoyée depuis un message Discord. + * @author mysaa + * + */ +public interface CCommandeDiscord extends CCommandeString { + + /** + * Renvoie le message qui a créé cette requête, tel que récupéré par la JDA. + * + * La consistance du message n'est pas assurée. + * @return Le message à l'origine de la requête. + */ + public Message getMessage(); + + /** + * Renvoie le canal dans lequel la requête a été formulée, tel que récupéré du JDA. + * + * La consistance du channel n'est pas assurée. + * @return Le canal de formulation de la requête. + */ + public MessageChannel getChannel(); + + /** + * Renvoie l'utilisateur ayant formulé cette requête, tel que récupéré par la JDA. + * + * La consistance de l'user n'est pas assurée. + * @return L'utilisateur à l'origine de la requête. + */ + public User getUser(); + + /** + * Renvoie la JDA qui a détécté l'évenement. + * + * @return La JDA initiante. + */ + public JDA getJDA(); + + /** + * Renvoie le contenu original du message ayant créé la requête. + * @return Le texte retiré de ses effets de style (markdown). + */ + public String getContentStripped(); + + /** + * Renvoie la date de récéption du message. + * @return La date de récéption du message. + */ + public OffsetDateTime getPostDate(); + +} diff --git a/src/main/java/com/bernard/juliabot/api/CCommandeString.java b/src/main/java/com/bernard/juliabot/api/CCommandeString.java new file mode 100644 index 0000000..deb8a8d --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/CCommandeString.java @@ -0,0 +1,23 @@ +package com.bernard.juliabot.api; + +/** + * Une CCommande décrite par une chaine de caractères. + * @author mysaa + * + */ +public interface CCommandeString extends CCommande{ + + /** + * La chaine de caractères décrivant la commande. + * @return La chaine sus-nommée. + */ + public String getStringCommand(); + + /** + * Renvoie les arguments complèxes associés à cette chaine de caractères. + * L'objet renvoyé peut être toujours le même ou généré à chaque fois. + * @return Les arguments complexes récupérés de la chaine de la commande. + */ + public ArgumentsComplexes getArguments(); + +} diff --git a/src/main/java/com/bernard/juliabot/api/Command.java b/src/main/java/com/bernard/juliabot/api/Command.java deleted file mode 100644 index af9a9f8..0000000 --- a/src/main/java/com/bernard/juliabot/api/Command.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.bernard.juliabot.api; - -import java.lang.annotation.*; - -@Target(value = ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Command { - - public String name(); - public String[] aliases() default {}; - public String description(); - public String synopsis() default ""; - public boolean admin();//TODO a remplacer par les permissions - -} \ No newline at end of file diff --git a/src/main/java/com/bernard/juliabot/api/CommandArguments.java b/src/main/java/com/bernard/juliabot/api/CommandArguments.java deleted file mode 100644 index 7a77cd6..0000000 --- a/src/main/java/com/bernard/juliabot/api/CommandArguments.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.bernard.juliabot.api; - -import java.util.*; - -public class CommandArguments { - - List nommes; - Map arguments; - Set flags; - - public CommandArguments(List nommes, Map arguments, Set flags) { - this.nommes = nommes; - this.arguments = arguments; - this.flags = flags; - } - - public List getNommes() { - return nommes; - } - - public Map getArguments() { - return arguments; - } - - public Set getFlags() { - return flags; - } - - public boolean hasTag(String tag) { - return flags.contains(tag); - } - - public String getArgument(String name) { - return arguments.get(name); - } - - public String getNomme(int pos) { - return nommes.get(pos); - } - - public int getNommeCount() { - return nommes.size(); - } - -} diff --git a/src/main/java/com/bernard/juliabot/api/Commande.java b/src/main/java/com/bernard/juliabot/api/Commande.java new file mode 100644 index 0000000..75494bb --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/Commande.java @@ -0,0 +1,41 @@ +package com.bernard.juliabot.api; + +import java.lang.annotation.*; + +/** + * Annotation à appliquer à une méthode afin qu'elle réagisse aux commandes + * envoyées sur discord ou via le sysin. + * + * Tous les arguments de la méthodes doivent étendre + * {@link com.bernard.juliabot.api.CCommande}. + * @author mysaa + * + */ +@Target(value = ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Commande { + + /** + * Le nom de la commande. Doit être à peu prêt unique, les nom plus + * «communs» doivent être mis dans les alias. + */ + public String name(); + /** + * Tableau des alias possible de la commande, c'est moins grâve si + * il y a des doublons. + */ + public String[] alias() default {}; + /** + * Une description d'une ligne environ de la commande, explique son effet. + */ + public String description(); + /** + * Le synopsis de la commande dans un style proche des pages man. + */ + public String synopsis() default ""; + /** + * true si la commande ne peut être éxecutée que par des admins. + */ + public boolean admin() default false;//TODO a remplacer par les permissions + +} \ No newline at end of file diff --git a/src/main/java/com/bernard/juliabot/api/Discord.java b/src/main/java/com/bernard/juliabot/api/Discord.java deleted file mode 100644 index 690a77a..0000000 --- a/src/main/java/com/bernard/juliabot/api/Discord.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.bernard.juliabot.api; - -import java.lang.annotation.*; - -@Target(value = ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Discord { - - public String description(); - -} \ No newline at end of file diff --git a/src/main/java/com/bernard/juliabot/api/DiscordCCommande.java b/src/main/java/com/bernard/juliabot/api/DiscordCCommande.java deleted file mode 100644 index 21d1557..0000000 --- a/src/main/java/com/bernard/juliabot/api/DiscordCCommande.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bernard.juliabot.api; - -import java.time.OffsetDateTime; - -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.entities.User; - -public interface DiscordCCommande extends StringCCommande { - - public Message getMessage(); - - public MessageChannel getChannel(); - - public User getUser(); - - public JDA getJDA(); - - public String getContentStripped(); - - public OffsetDateTime getPostDate(); - -} diff --git a/src/main/java/com/bernard/juliabot/api/EventDiscord.java b/src/main/java/com/bernard/juliabot/api/EventDiscord.java new file mode 100644 index 0000000..3f25494 --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/EventDiscord.java @@ -0,0 +1,20 @@ +package com.bernard.juliabot.api; + +import java.lang.annotation.*; + +/** + * Annotation à appliquer à une méthode pour indiquer qu'elle doit + * être appelée lorsque la JDA recoit des évenements (et que ces évenements sont + * bien destinés au bon laboratoire). + * + * Les méthodes doivent avoir un unique argument qui étende + * {@link net.dv8tion.jda.api.events.GenericEvent}. + * @author mysaa + * + */ +@Target(value = ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface EventDiscord { + public String description(); + +} \ No newline at end of file diff --git a/src/main/java/com/bernard/juliabot/api/Julia.java b/src/main/java/com/bernard/juliabot/api/Julia.java new file mode 100644 index 0000000..96366ed --- /dev/null +++ b/src/main/java/com/bernard/juliabot/api/Julia.java @@ -0,0 +1,69 @@ +package com.bernard.juliabot.api; + +import java.sql.Connection; + +import com.bernard.juliabot.PrintStreamDiscord; +import static com.bernard.juliabot.Julia.theJulia; + +import net.dv8tion.jda.api.JDA; + +/** + * Anciennement appelée Trukilie, permet d'interragir avec Julia avec uniquement + * des appels statics, et donc depuis n'importe où dans le programme. + * @author mysaa + * + */ +public class Julia { + + /** + * Accès au JDA initialisé par Julia. + * @return La JDA. + */ + public static JDA jda() { + return theJulia().getJda(); + } + + /** + * Récupère la connection SQL à la base de données. + * + * Prévu pour que les juliaddons accèdent à leurs données. + * @return Une connection normalement ouverte. + */ + public static Connection juliaBDD() { + return theJulia().getJuliaBDD(); + } + + /** + * Envoie un message dans sysout et dans le canal «status» du Discord + * @param message Le message à envoyer, optimalement d'une seule ligne et assez court. + */ + public static void status(String message) { + System.out.println(message); + + PrintStreamDiscord.logErrMessage(message, theJulia().statusTextChannel()); + } + + /** + * Envoie un message dans le syserr et dans le canal d'erreur du Discord + * @param message Le message décrivant l'erreur, optimalement d'une seule ligne et assez court. + */ + public static void erreur(String message) { + theJulia().realErr().println(message); + + if(theJulia().getSyserr() != null) + theJulia().getSyserr().errMessage(message); + } + + /** + * Envoie un message d'erreur avec un stacktrace dans le syserr et dans le canal d'erreur du Discord. + * @param message Le message décrivant l'erreur, optimalement d'une seule ligne et assez court. + * @param error L'erreur qui sera écrite à la suite du message, avec son stacktrace. + */ + public static void erreur(String message, Throwable error) { + theJulia().realErr().println(message); + error.printStackTrace(theJulia().realErr()); + + theJulia().getSyserr().errMessageAndThrowable(message, error); + } + +} diff --git a/src/main/java/com/bernard/juliabot/api/JuliaConfig.java b/src/main/java/com/bernard/juliabot/api/JuliaConfig.java deleted file mode 100644 index 0fd072e..0000000 --- a/src/main/java/com/bernard/juliabot/api/JuliaConfig.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.bernard.juliabot.api; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import com.bernard.juliabot.Julia; - -public class JuliaConfig { - - public static final String get(String name) { - try { - PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("SELECT * FROM juliaConfig WHERE strID=?"); - st.setString(1, name); - ResultSet r = st.executeQuery(); - if(r.getFetchSize() == 0) - throw new IllegalArgumentException("La configuration "+name+" n'existe pas ... veuillez la rentrer avant de la demander"); - String value = r.getString("value"); - return value; - } catch (SQLException e) { - e.printStackTrace(); - throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?"); - } - } - - public static final void set(String name, String value) { - try { - PreparedStatement st = Julia.theJulia().getJuliaDatabase().prepareStatement("UPDATE juliaConfig SET value=? WHERE strID=?"); - st.setString(1, value); - st.setString(2, value); - int r = st.executeUpdate(); - if(r == 0) - throw new IllegalArgumentException("La configuration "+name+" n'a pas pu être modifiée ... existe-elle ?"); - } catch (SQLException e) { - e.printStackTrace(); - throw new IllegalStateException("Impossible de faire des requetes à la bdd de julia. Est-elle initialisée au moins ?"); - } - } - -} diff --git a/src/main/java/com/bernard/juliabot/api/JuLIAddon.java b/src/main/java/com/bernard/juliabot/api/Juliaddon.java similarity index 65% rename from src/main/java/com/bernard/juliabot/api/JuLIAddon.java rename to src/main/java/com/bernard/juliabot/api/Juliaddon.java index 968343b..1e5c0eb 100644 --- a/src/main/java/com/bernard/juliabot/api/JuLIAddon.java +++ b/src/main/java/com/bernard/juliabot/api/Juliaddon.java @@ -7,22 +7,31 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; +/** + * Annotation à appliquer à une classe principale d'un Juliaddon. + * @author mysaa + * + */ @Documented @Retention(RUNTIME) @Target(TYPE) -public @interface JuLIAddon { +public @interface Juliaddon { /** * Le nom de l'addon */ - String name(); + String nom(); /** * La version de l'addon + * + * Par défaut: La version spécifiée dans le nom du fichier de l'addon sera utilisé. */ String version() default ""; /** * Différentes classes, en plus de celle là, dans laquelle chercher des méthodes définissant des événements ou des commandes + * + * Par défaut: Aucune fille, donc uniquement cette classe. */ - Class[] searchPath() default {}; + Class[] filles() default {}; /** * La liste des personnes ayant dévellopé cet addon */ diff --git a/src/main/java/com/bernard/juliabot/api/StringCCommande.java b/src/main/java/com/bernard/juliabot/api/StringCCommande.java deleted file mode 100644 index 5c3c06b..0000000 --- a/src/main/java/com/bernard/juliabot/api/StringCCommande.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.bernard.juliabot.api; - -public interface StringCCommande extends CCommande{ - - public String getStringCommand(); - - public CommandArguments getArguments(); - -} diff --git a/src/main/java/com/bernard/juliabot/api/Trukilie.java b/src/main/java/com/bernard/juliabot/api/Trukilie.java deleted file mode 100644 index 5000dc3..0000000 --- a/src/main/java/com/bernard/juliabot/api/Trukilie.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.bernard.juliabot.api; - -import java.sql.Connection; - -import com.bernard.juliabot.Julia; - -import net.dv8tion.jda.api.JDA; - -public class Trukilie { - - public static JDA jda() { - return Julia.theJulia().getJda(); - } - - public static Connection juliaDB() { - return Julia.theJulia().getJuliaDatabase(); - } - -} diff --git a/src/main/java/com/bernard/juliabot/internaddon/Internaddon.java b/src/main/java/com/bernard/juliabot/internaddon/Internaddon.java index 83446ca..0df9dd6 100644 --- a/src/main/java/com/bernard/juliabot/internaddon/Internaddon.java +++ b/src/main/java/com/bernard/juliabot/internaddon/Internaddon.java @@ -1,60 +1,92 @@ package com.bernard.juliabot.internaddon; +import static com.bernard.juliabot.api.Julia.erreur; + +import java.lang.reflect.Method; +import java.text.DateFormat; +import java.time.Instant; import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; -import com.bernard.juliabot.CommandCalled; +import org.simmetrics.StringDistance; +import org.simmetrics.metrics.StringDistances; + +import com.bernard.juliabot.AppelACommande; +import com.bernard.juliabot.CommandeSurchargee; import com.bernard.juliabot.Julia; -import com.bernard.juliabot.Julia.Laboratory; +import com.bernard.juliabot.Julia.Laboratoire; import com.bernard.juliabot.JuliaAddon; -import com.bernard.juliabot.api.Command; -import com.bernard.juliabot.api.CommandArguments; -import com.bernard.juliabot.api.Discord; -import com.bernard.juliabot.api.DiscordCCommande; -import com.bernard.juliabot.api.JuLIAddon; -import com.bernard.juliabot.api.StringCCommande; +import com.bernard.juliabot.JuliaAddon.JuliaClassLoader; +import com.bernard.juliabot.api.ArgumentsComplexes; +import com.bernard.juliabot.api.CCommandeDiscord; +import com.bernard.juliabot.api.CCommandeString; +import com.bernard.juliabot.api.Commande; +import com.bernard.juliabot.api.EventDiscord; +import com.bernard.juliabot.api.Juliaddon; import com.thedeanda.lorem.LoremIpsum; +import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.requests.restaction.MessageAction; +import net.dv8tion.jda.internal.utils.tuple.Pair; -@JuLIAddon(name="internaddon", devs = "Bernard", version="beta") +/** + * Cet addon est chargé de force dans chaque laboratoire. Il est celui qui permet de charger/décharger + * les autres addons et surtout de comprendre les commandes depuis les events reçus. + * + * Cet addon est fait pour être le seul qui accède directement aux méthodes de {@link com.bernard.juliabot.Julia}, sans + * passer par {@link com.bernard.juilabot.api.Julia}. + * @author mysaa + */ +@Juliaddon(nom="internaddon", devs = "Bernard", version="beta") public class Internaddon { public static final String COMMANDEUR = "!!"; - @Discord(description = "LE catcheur des commandes discords. Les messages recus sont lus puis executes ici si ce sont des commandes") - public void getCommand(MessageReceivedEvent e) { + /** + * Le catcheur d'evnts qui reconnais les commandes et demande à JuL'IA de les éxecuter. + */ + @EventDiscord(description = "LE catcheur des commandes discords. Les messages recus sont lus puis executes ici si ce sont des commandes") + public void getCommande(MessageReceivedEvent e) { if(e.getMessage().getContentRaw().startsWith(COMMANDEUR)) { - String name = e.getMessage().getContentRaw().split(" ")[0].substring(COMMANDEUR.length()); + String nom = e.getMessage().getContentRaw().split(" ")[0].substring(COMMANDEUR.length()); - Laboratory labo = Julia.theJulia().getLaboratoires().get(Julia.theJulia().getLecouteur().getLabo(e));//Récupére le labo de l'évent + Laboratoire labo = Julia.theJulia().getLecouteur().getLabo(e);//Récupére le labo de l'évent InternalddonCCommande ccommande = new InternalddonCCommande(e,labo); try { - CommandCalled called = labo.executeCommand(name, ccommande); - System.out.println(called); + AppelACommande appelee = labo.executer(nom, ccommande); + System.out.println(appelee); }catch(IllegalArgumentException ex) { // La commande n'existe pas - e.getChannel().sendMessage("Moi pas connaitre `"+name+"`. Vous apprendre moi ?").queue(); + e.getChannel().sendMessage("Moi pas connaitre `"+nom+"`. Vous apprendre moi ?").queue(); } } } - @Command(name = "julia", aliases="juju", description = "Répond à l'appel", admin = true) - public void julia(DiscordCCommande commande) { + /** + * Une commande pour tester le ping de julia. + */ + @Commande(name = "julia", alias="juju", synopsis = "!!julia", description = "Répond à l'appel", admin = true) + public void julia(CCommandeDiscord commande) { User user = commande.getUser(); MessageChannel channel = commande.getChannel(); String[] julias = new String[]{"Présent !", "Présente !", "Présentbleu !", "Présentavion !", "Présent(e) !", "Présent(bleu) !", @@ -65,63 +97,187 @@ public class Internaddon { String out = julias[(int)Math.floor(Math.random() * julias.length)]; channel.sendMessage(out).queue(); } + + public static final DateFormat addonFileTimeDf = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.FRANCE); - @Command(name = "help", aliases= {"ausecours","?","allahuakbar"}, description = "Laissez-vous aider par le meilleur bot du monde", admin = true) - public void help(DiscordCCommande commande) { - StringBuilder s = new StringBuilder(); - s.append("```"); + /** + * Liste les addons chargés ainsi que les commandes enregistrées. + */ + @Commande(name = "aide", alias= {"help","ausecours","?","allahuakbar"}, synopsis = "!!help [commandName | pkg] --labo=str", description = "Laissez-vous aider par le meilleur bot du monde", admin = true) + public void aide(CCommandeDiscord commande) { + ArgumentsComplexes args = commande.getArguments(); - Laboratory l = commande.getLabo(); - s.append("Vous étes actuellement dans le laboratoire '"+l.getL()+"'\n"); - s.append("Liste des addons chargés :\n"); - for(JuliaAddon e : l.getLoadedAddons().values()) - s.append("\t- "+e.getName()+" en version "+e.getVersion()+"\n"); - s.append("\nListe des commandes chargées :\n"); - for(String c : l.getLoadedCommands().keySet()) { - s.append("\t- "+c); - String collected = l.getAliases().entrySet().stream() - .filter(e->e.getValue().equals(c)) - .map(Map.Entry::getKey) - .collect(Collectors.joining(", ")); - if(!collected.isEmpty()) - s.append(" a.k.a "+collected); - if(l.getLoadedCommands().get(c).getDesc() != null) - s.append(" :\n\t\t"+l.getLoadedCommands().get(c).getDesc()); - s.append('\n'); + String lab = args.getArguments().getOrDefault("labo", commande.getLaboId()); + + Laboratoire l = Julia.theJulia().getLaboratoires().get(lab); + EmbedBuilder msg = new EmbedBuilder(); + if(args.getNommeCount() == 1) { + // On veut décrire un laboratoire. + + msg.setTitle(String.format("Description du laboratoire «%s»", l.getL())); + + for(JuliaAddon e : l.getAddonsCharges()) { + String commandes = e.getLoader(l) + .getCommandesEnregistrees() + .stream() + .map(m -> m.getAnnotation(Commande.class)) + .map(c -> c.name()) + .collect(Collectors.joining("; ")); + msg.addField( + String.format("%s en version %s (%s)",e.getNom(),e.getVersion(),e.getPkg()), + String.format("Liste des commandes disponibles: %s", commandes), + false); + } + } else if (args.getNommeCount() == 2) { + // Compréhension du premier argument das cet ordre: + // pkg > lastPkgName > commandName > alias > addon + + String nom = args.getNomme(1); + String pkg = null; + CommandeSurchargee cs = null; + + Set pkgs = Julia.theJulia().pkgSet(); + + if(pkgs.contains(nom)) + pkg=nom; // C'est déjà un pkg donc bon + else { + Optional ops = pkgs.stream() + .filter(p -> p.toLowerCase(Locale.FRENCH).endsWith("."+nom.toLowerCase(Locale.FRENCH))) + .findAny(); + if(ops.isPresent()) + pkg = ops.get(); + else { + // On teste une commande OU un alias. + cs = l.commandeAssociee(nom); + + if(cs == null) + pkg = comprendreAddon(nom); + } + } + // On a «parse» le premier argument. + + if(pkg != null) { + // On veut décrire un package. + String pkgf = pkg; + Optional addonO = l.getAddonsCharges() + .stream() + .filter(a -> a.getPkg().equals(pkgf)) + .findAny(); + if(addonO.isEmpty()) { + // L'addon n'est pas chargé dans le laboratoire. + repondre(commande, "Vous voulez de l'aide sur l'internaddon "+pkg+" mais " + + "il n'est pas chargé dans ce laboratoire ...").complete(); + return; + } + JuliaAddon addon = addonO.get(); + + msg.setTitle(String.format("Description du juliaddon %s (%s)",addon.getNom(),addon.getPkg())); + msg.setDescription(String.format( + "Cet addon est chargé dans le laboratoire %s en version %s. " + + "Il est extrait du fichier %s chargé pour la dernière fois %s", + l.getL(),addon.getVersion(),addon.getFichierJar().getName(), addonFileTimeDf.format(Date.from(Instant.ofEpochMilli(addon.getDerniereModif()))))); + + JuliaClassLoader loader = addon.getLoader(l); + + for(Method m : loader.getEventsEnregistrees()) { + EventDiscord ed = m.getAnnotation(EventDiscord.class); + if(ed==null) { + erreur("Inconsistance dans le classLoader de l'addon "+addon+" : " + + "la méthode "+m.getName()+" est enregistrée comme event."); + repondre(commande, "Une erreur de classes est survenue. Contactez un développeur du Julia."); + return; + } + + msg.addField( + m.getName() , + ed.description(), + false); + } + + msg.addBlankField(false); + + for(Method m : loader.getCommandesEnregistrees()) { + Commande ed = m.getAnnotation(Commande.class); + if(ed==null) { + erreur("Inconsistance dans le classLoader de l'addon "+addon+" : " + + "la méthode "+m.getName()+" est enregistrée comme commande"); + repondre(commande, "Une erreur de classes est survenue. Contactez un développeur du Julia."); + return; + } + + msg.addField( + (ed.alias().length==0) + ? String.format("Commande %s", ed.name()) + : String.format("Commande %s (alias %s)", ed.name(),String.join(" ou ",ed.alias())) , + ed.description(), + false); + } + + + } else if (cs != null){ + // On veut décrire une commande. + + Method executeur = cs.getExecuteur(commande); + if(! (executeur.getDeclaringClass().getClassLoader() instanceof JuliaClassLoader)) { + repondre(commande, "Impossible de récupérer l'addon correspondant à cette commande !"); + return; + } + JuliaAddon addon = ((JuliaClassLoader)executeur.getDeclaringClass().getClassLoader()).getAddon(); + + msg.setTitle("Commande "+cs.getCommande().name()); + + msg.setDescription(cs.getDesc()); + + msg.addField("Synopsis",cs.getCommande().synopsis() + + (cs.getCommande().admin()?"\nCette commande requiert les droits d'administrateur.":""),false); + + msg.addField("Addon", + String.format("Cette commande est décrite par l'addon %s en version %s décrit " + + "dans le fichier %s à la date %s. La méthode à executer est la méthode %s " + + "de la classe %s.", addon.getNom(),addon.getVersion(),addon.getFichierJar().getName(), + addonFileTimeDf.format(Date.from(Instant.ofEpochMilli(addon.getDerniereModif()))),executeur.getName(),executeur.getDeclaringClass().getName()),false); + + if(cs.getCommande().alias().length != 0) + msg.addField("Aliases", String.join(", ", cs.getCommande().alias()), false); + + } else { + // On a pas compris ce qui devait être décrit. + repondre(commande, "Je n'ai pas compris ce sur quoi je devais vous aider ...").complete(); + return; + } } - s.append("```"); - commande.getChannel().sendMessage(s).queue(); + //msg.setFooter("Réponse à "+authorName(commande));// -> C'est moche + repondre(commande, msg.build()).complete(); } - @Command(name = "blabla", aliases= {}, description = "Pour vous prouver que je parle", admin = true) - public void blabla(DiscordCCommande commande) { + /** + * Fait que julia publie un gros bloc de texte de type Lorem ipsum. + */ + @Commande(name = "blabla", alias= {}, description = "Pour vous prouver que je parle", admin = true)//TODO ajouter des options peut-être. + public void blabla(CCommandeDiscord commande) { Message m = commande.getMessage(); m.getChannel().sendMessage("```"+LoremIpsum.getInstance().getWords(150, 200)+"```").queue(); m.delete(); } - @Command(name = "tuerBebePhoque", aliases= {}, description = "Pour votre plaisir", admin = true) - public void tuerBebePhoque(DiscordCCommande commande) { + /** + * Renvoie la photo d'un bébé phoque mort pour soulager les développeurs stréssés. + */ + @Commande(name = "tuerBebePhoque", alias= {}, description = "Pour votre plaisir", admin = true)//TODO remplir un peu cette méthode. + public void tuerBebePhoque(CCommandeDiscord commande) { Message m = commande.getMessage(); m.getChannel().sendMessage("http://toni.mi.free.fr/vanhebdo/actions/phoques/im_phoque_coupGourdinAssomme_Sang.jpg").queue(); } - - - @Discord(description = "Arthur, par-ce que vous n'étes pas qu'une caricature") - public void shutUp(MessageReceivedEvent e) { - if(e.getAuthor().getIdLong() == 187677269626585089L) {//Yukimyo = L'Orchidoclaste - - e.getChannel().sendMessage(e.getAuthor().getAsMention() +" dis du caca").queue(); - - } - } - - @Command(name = "args", description = "Décompose les messages à la Discord'", admin = true) - public void args(DiscordCCommande commande) { - CommandArguments ca = commande.getArguments(); + /** + * Commande de test de la décomposition des commandes. //XXX: À supprimer + * @see ArgumentsComplexes + */ + @Commande(name = "args", description = "Décompose les messages à la Discord'", admin = true) + public void args(CCommandeDiscord commande) { + ArgumentsComplexes ca = commande.getArguments();// Réparer la commande. StringBuilder s = new StringBuilder(); s.append("```"+commande.getStringCommand()+"```"); @@ -135,8 +291,11 @@ public class Internaddon { } - @Command(name="guilds", description = "Liste les guildes disponibles",admin=true) - public void guilds(DiscordCCommande commande) { + /** + * Liste les guildes auquel Julia à accès. + */ + @Commande(name="guildes", alias= {"guilds"}, description = "Liste les guildes disponibles",admin=true) + public void guildes(CCommandeDiscord commande) { MessageBuilder mb = new MessageBuilder(); mb.append("Liste des serveurs :\n"); Julia.theJulia().getJda().getGuilds() @@ -146,64 +305,234 @@ public class Internaddon { commande.getChannel().sendMessage(mb.build()).complete(); } - @Command(name="update",description = "Met a jour le dossier des addons",admin=true) - public void update(StringCCommande commande) { + /** + * Met à jour la liste des addons disponibles, en lisant le dossier juliaddons. + */ + @Commande(name="maj", alias= {"update","miseAJour"},description = "Met a jour le dossier des addons",admin=true) + public void maj(CCommandeString commande) { - Julia.theJulia().update(); + Julia.theJulia().addonsMaj(); + if(CCommandeDiscord.class.isInstance(commande.getClass())) + repondre((CCommandeDiscord)commande, "La liste des addons disponibles a été mise à jour."); } - @Command(name="load",description = "Charge l'addon dans ce laboratoire",admin=true) - public void load(DiscordCCommande commande) { + /** + * Charge l'addon spécifié en ligne de commande dans le laboratoire d'appel. + */ + @Commande(name="charger", alias= {"load"}, description = "Charge l'addon dans ce laboratoire",admin=true) + public void charger(CCommandeDiscord commande) { - CommandArguments cc = commande.getArguments(); + ArgumentsComplexes cc = commande.getArguments(); - String addonName = cc.getNomme(1); - String version = cc.getNomme(2); + String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId()); - Laboratory l = commande.getLabo(); + if(cc.getNommeCount()<2) { + repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete(); + return; + } + + String addonPkg = comprendreAddon(cc.getNomme(1)); + + if(addonPkg == null) { + repondre(commande, String.format("Je ne trouve pas d'addon correspondant à «%s» ...", cc.getNomme(1))).complete(); + return; + } + + String version = null; + if(cc.getNommeCount()<3) + version = Julia.theJulia().latest(addonPkg); + else + version = cc.getNomme(2); + + if(! Julia.theJulia().checkVersion(addonPkg,version)) { + repondre(commande, "Je ne trouve pas la version "+version+" pour l'addon "+addonPkg).complete(); + return; + } + + + + Laboratoire l = Julia.theJulia().getLaboratoires().get(lab); - String out = "Terminé avec succés"; try { - l.loadAddon(addonName, version); + l.loadAddon(addonPkg, version); }catch (Exception e) { - out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```"; + repondre(commande, "Impossible de charger l'addon spécifié ! Contactez un admin julia.").complete(); + erreur("Tentative de chargement depuis l'internaddon", e); + return; } - commande.getChannel().sendMessage(out); + + repondre(commande, String.format("L'addon %s a été chargé dans sa version %s dans le laboratoire %s", addonPkg, version, lab)).complete(); + } - @Command(name="unload",description = "Décharge l'addon de ce laboratoire",admin=true) - public void unload(DiscordCCommande commande) { + /** + * Décharge l'addon spécifié du laboratoire d'appel. + */ + @Commande(name="decharger", alias= {"unload"}, description = "Décharge l'addon de ce laboratoire",admin=true) + public void decharger(CCommandeDiscord commande) { - CommandArguments cc = commande.getArguments(); + ArgumentsComplexes cc = commande.getArguments(); - String addonName = cc.getNomme(1); + String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId()); + + if(cc.getNommeCount()<2) { + repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete(); + return; + } + + String addonPkg = comprendreAddon(cc.getNomme(1)); + + + Laboratoire l = Julia.theJulia().getLaboratoires().get(lab); - Laboratory l = commande.getLabo(); - String out = "Terminé avec succés"; try { - l.unloadAddon(addonName); + l.dechargerAddon(addonPkg); }catch (Exception e) { - out = "```"+e.getClass().toString()+"\n"+e.getMessage()+"```"; + repondre(commande, "Impossible de décharger l'addon spécifié ! Contactez un admin julia.").complete(); + erreur("Tentative de déchargement depuis l'internaddon", e); + return; } - commande.getChannel().sendMessage(out); + + repondre(commande, String.format("L'addon %s a été déchargé du laboratoire %s", addonPkg, lab)).complete(); } - @Command(name="caca",description = "Déclanche une exception ... Faut bien tester, hein !",admin=true) - public void caca(DiscordCCommande commande) { + /** + * Décharge puis recharge l'addon du laboratoire spécifié. + */ + @Commande(name="recharger", alias= {"reload"}, description = "Recharge l'addon de ce laboratoire",admin=true) + public void recharger(CCommandeDiscord commande) { + + ArgumentsComplexes cc = commande.getArguments(); + + String lab = cc.getArguments().getOrDefault("labo", commande.getLaboId()); + + if(cc.getNommeCount()<2) { + repondre(commande, "Il vous faut préciser l'addon que vous voulez charger !").complete(); + return; + } + + String addonPkg = comprendreAddon(cc.getNomme(1)); + + + Laboratoire l = Julia.theJulia().getLaboratoires().get(lab); + + try { + l.rechargeAddon(addonPkg, null); + }catch (Exception e) { + repondre(commande, "Impossible de recharger l'addon spécifié ! Contactez un admin julia.").complete(); + erreur("Tentative de rechargement depuis l'internaddon", e); + return; + } + + repondre(commande, String.format("L'addon %s a été rechargé dans le laboratoire %s", addonPkg, lab)).complete(); + + } + + /** + * Une commande qui lance une IllegalStateException à des fins de tests. + */ + //XXX: À supprimer ou cacher + @Commande(name="caca",description = "Déclanche une exception ... Faut bien tester, hein !",admin=true) + public void caca(CCommandeDiscord commande) { throw new IllegalStateException("Nan mais tout va bien ... je fait ce qu'on m'a demandé ^^"); } + StringDistance addonMetric = StringDistances.levenshtein(); + final float maxAcceptableDistance = 8.0f; + + /** + * Renvoie le pkg d'un addon disponible qui correspond le mieux au nom spécifié. + * @param nom Le nom, typiquement donné par l'utilisateur. + * @return Un pkg d'un internaddon, normalement chargeable. + */ + public String comprendreAddon(String nom) { + Set pkgs = Julia.theJulia().pkgSet(); + + if(pkgs.contains(nom)) + return nom; // C'est déjà un pkg donc bon + + Optional ops = pkgs.stream().filter(p -> p.endsWith("."+nom)).findAny(); + if(ops.isPresent()) + return ops.get(); + + + + List> listProches = pkgs.stream() + .map(s -> Pair.of(s, addonMetric.distance(s.substring(s.lastIndexOf(".")+1), nom))) + .filter(e -> e.getRight() < maxAcceptableDistance) + .sorted((a,b) -> Float.compare(a.getRight(), b.getRight())) + .collect(Collectors.toList()); + + if(listProches.size()>1) + if(listProches.get(0).getRight() < listProches.get(1).getRight()) + return listProches.get(0).getLeft(); + else + return null; + else if(listProches.size()==1) + return listProches.get(0).getLeft(); + else + return null; + + } + + /** + * Fait répondre à Julia sa réponse du message source + * @param commande La ccommande de requête + * @param message Le message à renvoyer + * @return L'action d'envoi de la réponse. + */ + public MessageAction repondre(CCommandeDiscord commande, MessageEmbed message) { + return commande.getMessage().replyEmbeds(message); + } + + /** + * Fait répondre à Julia sa réponse du message source + * @param commande La ccommande de requête + * @param message Le message à renvoyer + * @return L'action d'envoi de la réponse. + */ + public MessageAction repondre(CCommandeDiscord commande, Message message) { + return commande.getMessage().reply(message); + } + + /** + * Fait répondre à Julia sa réponse du message source + * @param commande La ccommande de requête + * @param message Le contenu du message à renvoyer + * @return L'action d'envoi de la réponse. + */ + public MessageAction repondre(CCommandeDiscord commande, String message) { + return commande.getMessage().reply(message).mentionRepliedUser(true); + } - public class InternalddonCCommande implements DiscordCCommande,StringCCommande{ + public String authorName(CCommandeDiscord commande) { + if(commande.getMessage().isFromGuild()) + return ((GuildChannel)commande.getChannel()).getGuild().retrieveMember(commande.getUser()).complete().getEffectiveName(); + else + return commande.getUser().getName(); + } + + /** + * Une simple implémentation de {@link CCommandeDiscord} et de {@link CCommandeString} afin d'appeler + * les commandes depuis les events jda. + * @author mysaa + * + */ + public class InternalddonCCommande implements CCommandeDiscord,CCommandeString{ Message m; - Laboratory labo; + Laboratoire labo; - public InternalddonCCommande(MessageReceivedEvent e,Laboratory labo) { + /** + * Crée une simple commande. + * @param e L'évenement trahissant la récéption de la commande. + * @param labo Le laboratoire associé à la commande. + */ + public InternalddonCCommande(MessageReceivedEvent e,Laboratoire labo) { m = e.getMessage(); this.labo = labo; } @@ -214,7 +543,7 @@ public class Internaddon { } @Override - public CommandArguments getArguments() { + public ArgumentsComplexes getArguments() { return parseCommandArguments(getStringCommand()); } @@ -249,14 +578,20 @@ public class Internaddon { } @Override - public Laboratory getLabo() { - return labo; + public String getLaboId() { + return labo.getL(); } } - public static CommandArguments parseCommandArguments(String raw) { + /** + * Comprend une ligne de commande, en séparant les nommes, flags et arguments en + * un seul objet. + * @param raw La ligne de commande à parser + * @return L'objet arguments complexes contenant toutes les données séparées. + */ + public static ArgumentsComplexes parseCommandArguments(String raw) { List nommes = new ArrayList(); Map arguments = new HashMap<>(); @@ -328,7 +663,7 @@ public class Internaddon { } - return new CommandArguments(nommes, arguments, flags); + return new ArgumentsComplexes(nommes, arguments, flags); } diff --git a/src/main/java/com/bernard/juliabot/internaddon/UnstableMessage.java b/src/main/java/com/bernard/juliabot/internaddon/UnstableMessage.java deleted file mode 100644 index 606b4d3..0000000 --- a/src/main/java/com/bernard/juliabot/internaddon/UnstableMessage.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.bernard.juliabot.internaddon; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.function.Consumer; - -import net.dv8tion.jda.api.entities.Message; - -public class UnstableMessage extends OutputStream{ - - MConsumer thisConsumer = new MConsumer(); - - public UnstableMessage(Message m) { - // TODO Auto-generated constructor stub - m.editMessage(""/* a préciser */).queue(thisConsumer, (e) -> { - - }); - } - - - @Override - public void write(int arg0) throws IOException { - // TODO Auto-generated method stub - - } - - public class MConsumer implements Consumer{ - @Override - public void accept(Message arg0) { - // TODO Auto-generated method stub - - } - } - - -} diff --git a/upload.sh b/upload.sh new file mode 100644 index 0000000..ebeb57a --- /dev/null +++ b/upload.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +gradle jar +gradle internalddon +gradle apiJar + +scp -r -P 27182 -4 build/libs/Juliabot.jar root@bernard.com.de:/srv/julia/ +scp -r -P 27182 -4 build/libs/JuliabotInternaddon_beta.jar root@bernard.com.de:/srv/julia/juliaddons/