diff --git a/.gitignore b/.gitignore index 0dd928cb9..08ded24d9 100644 --- a/.gitignore +++ b/.gitignore @@ -119,7 +119,7 @@ nbproject/private/ run.bat target/ .nb-gradle/ -/dependency-reduced-pom.xml +*/dependency-reduced-pom.xml *credentials.json *credentials.yaml *tokens.json @@ -132,3 +132,4 @@ target/ /music_persistence/ /bootloader.json gc-*.log +*dbconf.yaml \ No newline at end of file diff --git a/FredBoat-Bootloader/pom.xml b/FredBoat-Bootloader/pom.xml index 35b464d0f..a5844d026 100644 --- a/FredBoat-Bootloader/pom.xml +++ b/FredBoat-Bootloader/pom.xml @@ -24,17 +24,33 @@ ~ --> - + + + fredboat + FredBoat-Root + 1.0 + + 4.0.0 - com.frederikam FredBoat-Bootloader 1.0 jar + - UTF-8 - 1.8 - 1.8 + fredboat.bootloader.Bootloader + + + + + fredboat + Shared + 1.0 + + + @@ -51,7 +67,7 @@ - com.frederikam.fredboat.bootloader.Bootloader + fredboat.bootloader.Bootloader @@ -61,12 +77,4 @@ - - - org.json - json - 20160810 - jar - - - \ No newline at end of file + diff --git a/FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/ExitCodes.java b/FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/ExitCodes.java deleted file mode 100644 index 9c6a2d5a9..000000000 --- a/FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/ExitCodes.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2017 Frederik Ar. Mikkelsen - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ - -package com.frederikam.fredboat.bootloader; - -public class ExitCodes { - - public static final int EXIT_CODE_NORMAL = 0; - public static final int EXIT_CODE_UPDATE = 20; - public static final int EXIT_CODE_RESTART = 21; - -} diff --git a/FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/Bootloader.java b/FredBoat-Bootloader/src/main/java/fredboat/bootloader/Bootloader.java similarity index 93% rename from FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/Bootloader.java rename to FredBoat-Bootloader/src/main/java/fredboat/bootloader/Bootloader.java index d894a5af8..9aa926ff7 100644 --- a/FredBoat-Bootloader/src/main/java/com/frederikam/fredboat/bootloader/Bootloader.java +++ b/FredBoat-Bootloader/src/main/java/fredboat/bootloader/Bootloader.java @@ -1,4 +1,5 @@ /* + * * MIT License * * Copyright (c) 2017 Frederik Ar. Mikkelsen @@ -20,10 +21,13 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - * */ -package com.frederikam.fredboat.bootloader; +package fredboat.bootloader; + +import fredboat.shared.constant.ExitCodes; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.File; import java.io.FileInputStream; @@ -31,8 +35,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.Scanner; -import org.json.JSONArray; -import org.json.JSONObject; public class Bootloader { @@ -40,7 +42,7 @@ public class Bootloader { private static String jarName; private static int recentBoots = 0; private static long lastBoot = 0L; - + public static void main(String[] args) throws IOException, InterruptedException { OUTER: while (true) { @@ -48,14 +50,14 @@ public static void main(String[] args) throws IOException, InterruptedException Scanner scanner = new Scanner(is); JSONObject json = new JSONObject(scanner.useDelimiter("\\A").next()); scanner.close(); - + command = json.getJSONArray("command"); jarName = json.getString("jarName"); Process process = boot(); process.waitFor(); System.out.println("[BOOTLOADER] Bot exited with code " + process.exitValue()); - + switch (process.exitValue()) { case ExitCodes.EXIT_CODE_UPDATE: System.out.println("[BOOTLOADER] Now updating..."); @@ -65,7 +67,7 @@ public static void main(String[] args) throws IOException, InterruptedException case ExitCodes.EXIT_CODE_NORMAL: System.out.println("[BOOTLOADER] Now shutting down..."); break OUTER; - //SIGINT received or clean exit + //SIGINT received or clean exit default: System.out.println("[BOOTLOADER] Now restarting.."); break; @@ -75,18 +77,18 @@ public static void main(String[] args) throws IOException, InterruptedException private static Process boot() throws IOException { //Check that we are not booting too quick (we could be stuck in a login loop) - if(System.currentTimeMillis() - lastBoot > 3000 * 1000){ + if (System.currentTimeMillis() - lastBoot > 3000 * 1000) { recentBoots = 0; } - + recentBoots++; lastBoot = System.currentTimeMillis(); - - if(recentBoots >= 4){ + + if (recentBoots >= 4) { System.out.println("[BOOTLOADER] Failed to restart 3 times, probably due to login errors. Exiting..."); System.exit(-1); } - + //ProcessBuilder pb = new ProcessBuilder(System.getProperty("java.home") + "/bin/java -jar "+new File("FredBoat-1.0.jar").getAbsolutePath()) ProcessBuilder pb = new ProcessBuilder() .inheritIO(); @@ -94,9 +96,9 @@ private static Process boot() throws IOException { command.forEach((Object str) -> { list.add((String) str); }); - + pb.command(list); - + Process process = pb.start(); return process; } diff --git a/FredBoat/.gitignore b/FredBoat/.gitignore index d35ced37e..e6c65aad7 100644 --- a/FredBoat/.gitignore +++ b/FredBoat/.gitignore @@ -1,6 +1,5 @@ /logs/ /bootloader.json -/dependency-reduced-pom.xml /music_persistence/ /credentials_test.json /credentials.json.old diff --git a/FredBoat/config.yaml b/FredBoat/config.yaml index 1aee473e9..c0187fe41 100644 --- a/FredBoat/config.yaml +++ b/FredBoat/config.yaml @@ -1,7 +1,7 @@ --- -patron: false -development: true # Set this to true for self hosting -prefix: '<<' # Default prefix used by the bot -restServerEnabled: true # Change this if you are running multiple FredBoat bots on the same machine -admins: [] # add comma separated userIds and roleIds that should have access to admin commands -useAutoBlacklist: true # set to true to automatically blacklist users who frequently hit the rate limits +patron: false # Set this to true for self hosting the music bot +development: true # Set this to true for self hosting the full bot (including non music commands) +prefix: '<<' # Default prefix used by the bot +restServerEnabled: true # Set this to false if you are running multiple FredBoat bots on the same machine +admins: [] # add comma separated userIds and roleIds that should have access to bot admin commands +useAutoBlacklist: true # set to true to automatically blacklist users who frequently hit the rate limits diff --git a/FredBoat/feature_flags.properties b/FredBoat/feature_flags.properties index d69235a9a..5aa8bb4b5 100644 --- a/FredBoat/feature_flags.properties +++ b/FredBoat/feature_flags.properties @@ -31,3 +31,5 @@ # example to turn a feature on (uncomment it): #RATE_LIMITER=false #CHATBOT=false +#DATA_METHODS=false +PERMISSIONS=false diff --git a/FredBoat/pom.xml b/FredBoat/pom.xml index 396dcd9c1..87de39de7 100644 --- a/FredBoat/pom.xml +++ b/FredBoat/pom.xml @@ -24,201 +24,196 @@ ~ --> - + + + fredboat + FredBoat-Root + 1.0 + + 4.0.0 - fredboat FredBoat 1.0 jar + - UTF-8 - 1.8 - 1.8 fredboat.FredBoat + - com.github.DV8FromTheWorld + + fredboat + Shared + 1.0 + + + + net.dv8tion JDA - 1a13578 + 3.1.1_217 + + net.sf.trove4j + trove4j + 3.0.3 + + + org.apache.commons commons-collections4 4.1 compile + com.sedmelluq lavaplayer 1.2.39 + com.sedmelluq jda-nas 1.0.5 + frederikam JCA 1.0 + commons-io commons-io 2.5 - org.springframework.boot - spring-boot-starter-web - 1.5.3.RELEASE - - - org.slf4j - slf4j-api - 1.7.25 + + org.apache.commons + commons-lang3 + 3.6 + ch.qos.logback logback-classic 1.2.3 - org.apache.commons - commons-lang3 - 3.5 + + org.slf4j + slf4j-api + 1.7.25 + com.sparkjava spark-core - 2.5.5 + 2.6.0 + org.yaml snakeyaml 1.18 - + net.sourceforge.htmlunit htmlunit - 2.26 + 2.27 - + org.eclipse.jetty.websocket websocket-client - + it.unimi.dsi fastutil 8.1.0 - + org.hibernate hibernate-core 5.2.10.Final + org.hibernate hibernate-ehcache 5.2.10.Final + org.hibernate hibernate-hikaricp 5.2.10.Final + + org.springframework.boot + spring-boot-starter-web + 1.5.4.RELEASE + + + org.springframework spring-orm - 4.3.8.RELEASE + 4.3.9.RELEASE + org.postgresql postgresql 42.1.1 - org.junit.jupiter - junit-jupiter-api - 5.0.0-M4 - test - - - - + org.xerial sqlite-jdbc - 3.16.1 + 3.19.3 - + com.github.gwenn sqlite-dialect 24970986d0 - - + com.jcraft jsch 0.1.54 - - + org.togglz togglz-core 2.4.1.Final + + + org.junit.jupiter + junit-jupiter-api + 5.0.0-M4 + test + - - - jcenter - jcenter-bintray - http://jcenter.bintray.com - - - - false - - bintray-frederikam-JCA - bintray - http://dl.bintray.com/frederikam/JCA - - - sedmelluq - sedmelluq - http://maven.sedmelluq.com/ - - - jitpack.io - https://jitpack.io - - + - - - maven-clean-plugin - 3.0.0 - - - auto-clean - initialize - - clean - - - - maven-surefire-plugin @@ -301,7 +296,7 @@ org.springframework.boot spring-boot-maven-plugin - 1.5.3.RELEASE + 1.5.4.RELEASE diff --git a/FredBoat/src/main/java/fredboat/Config.java b/FredBoat/src/main/java/fredboat/Config.java index d1573394d..35f7e28e6 100644 --- a/FredBoat/src/main/java/fredboat/Config.java +++ b/FredBoat/src/main/java/fredboat/Config.java @@ -26,8 +26,8 @@ package fredboat; import com.mashape.unirest.http.exceptions.UnirestException; +import fredboat.shared.constant.DistributionEnum; import fredboat.util.DiscordUtil; -import fredboat.util.constant.DistributionEnum; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/FredBoat/src/main/java/fredboat/FredBoat.java b/FredBoat/src/main/java/fredboat/FredBoat.java index 928d00953..879acc572 100644 --- a/FredBoat/src/main/java/fredboat/FredBoat.java +++ b/FredBoat/src/main/java/fredboat/FredBoat.java @@ -45,16 +45,15 @@ import fredboat.event.EventListenerSelf; import fredboat.event.ShardWatchdogListener; import fredboat.feature.I18n; -import fredboat.util.constant.DistributionEnum; +import fredboat.shared.constant.DistributionEnum; +import fredboat.util.JDAUtil; import fredboat.util.log.SimpleLogToSLF4JAdapter; import frederikam.jca.JCA; import frederikam.jca.JCABuilder; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDAInfo; import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.ISnowflake; import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.VoiceChannel; import net.dv8tion.jda.core.events.ReadyEvent; @@ -66,6 +65,7 @@ import org.slf4j.LoggerFactory; import javax.security.auth.login.LoginException; + import java.io.IOException; import java.util.ArrayList; import java.util.Collections; @@ -326,7 +326,12 @@ public void onInit(ReadyEvent readyEvent) { int ready = numShardsReady.get(); if (ready == Config.CONFIG.getNumShards()) { log.info("All " + ready + " shards are ready."); - MusicPersistenceHandler.reloadPlaylists(); + + if (Config.CONFIG.getNumShards() <= 10) { + MusicPersistenceHandler.reloadPlaylists(); + } else { + log.warn("Skipped music persistence loading! We are using more than 10 shards, so probably not a good idea to run that."); + } } //Rejoin old channels if revived @@ -395,20 +400,11 @@ public static List getShards() { } public static List getAllGuilds() { - ArrayList list = new ArrayList<>(); - - for (FredBoat fb : shards) { - list.addAll(fb.getJda().getGuilds()); - } - - return list; + return JDAUtil.getAllGuilds(shards); } public static int countAllGuilds() { - return Collections.unmodifiableCollection(shards) - .stream() - .mapToInt(shard -> shard.getJda().getGuilds().size()) - .sum(); + return JDAUtil.countAllGuilds(shards); } //this probably takes horribly long and should be solved in a different way @@ -425,28 +421,19 @@ public static int countAllGuilds() { // return map; // } - private static int biggestUserCount = -1; + private static AtomicInteger biggestUserCount = new AtomicInteger(-1); //IMPORTANT: do not use this for actually counting, it will not be accurate; it is meant to be used to initialize // sets or maps that are about to hold all those user values public static int getExpectedUserCount() { - if (biggestUserCount <= 0) { //initialize + if (biggestUserCount.get() <= 0) { //initialize countAllUniqueUsers(); } - return biggestUserCount; + return biggestUserCount.get(); } public static long countAllUniqueUsers() { - int expected = biggestUserCount > 0 ? biggestUserCount : LongOpenHashSet.DEFAULT_INITIAL_SIZE; - LongOpenHashSet uniqueUsers = new LongOpenHashSet(expected + 100000); //add 100k for good measure - Collections.unmodifiableCollection(shards).forEach( - shard -> shard.getJda().getUsers().parallelStream().mapToLong(ISnowflake::getIdLong).forEach(uniqueUsers::add) - ); - //never shrink the user count (might happen due to not connected shards) - if (uniqueUsers.size() > biggestUserCount) { - biggestUserCount = uniqueUsers.size(); - } - return uniqueUsers.size(); + return JDAUtil.countAllUniqueUsers(shards, biggestUserCount); } public static TextChannel getTextChannelById(String id) { @@ -507,6 +494,14 @@ public ShardInfo getShardInfo() { } } + public long getGuildCount() { + return JDAUtil.countAllGuilds(Collections.singletonList(this)); + } + + public long getUserCount() { + return JDAUtil.countAllUniqueUsers(Collections.singletonList(this), biggestUserCount); + } + public abstract void revive(); public ShardWatchdogListener getShardWatchdogListener() { diff --git a/FredBoat/src/main/java/fredboat/FredBoatBot.java b/FredBoat/src/main/java/fredboat/FredBoatBot.java index 10ee9f546..0332218da 100644 --- a/FredBoat/src/main/java/fredboat/FredBoatBot.java +++ b/FredBoat/src/main/java/fredboat/FredBoatBot.java @@ -32,6 +32,7 @@ import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.JDABuilder; +import net.dv8tion.jda.core.entities.VoiceChannel; import net.dv8tion.jda.core.exceptions.RateLimitedException; import net.dv8tion.jda.core.hooks.EventListener; import org.slf4j.Logger; @@ -109,7 +110,8 @@ public void revive() { PlayerRegistry.getPlayingPlayers().stream() .filter(guildPlayer -> guildPlayer.getJda().getShardInfo().getShardId() == shardId) .forEach(guildPlayer -> { - if (guildPlayer.getChannel() != null) channelsToRejoin.add(guildPlayer.getChannel().getId()); + VoiceChannel channel = guildPlayer.getChannel(); + if (channel != null) channelsToRejoin.add(channel.getId()); }); } catch (Exception ex) { log.error("Caught exception while reviving shard " + this, ex); diff --git a/FredBoat/src/main/java/fredboat/agent/ShardWatchdogAgent.java b/FredBoat/src/main/java/fredboat/agent/ShardWatchdogAgent.java index 73488d6af..f24a57470 100644 --- a/FredBoat/src/main/java/fredboat/agent/ShardWatchdogAgent.java +++ b/FredBoat/src/main/java/fredboat/agent/ShardWatchdogAgent.java @@ -28,7 +28,7 @@ import fredboat.Config; import fredboat.FredBoat; import fredboat.event.ShardWatchdogListener; -import fredboat.util.constant.DistributionEnum; +import fredboat.shared.constant.DistributionEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/FredBoat/src/main/java/fredboat/api/API.java b/FredBoat/src/main/java/fredboat/api/API.java index dafce27b1..d6bf8ccfc 100644 --- a/FredBoat/src/main/java/fredboat/api/API.java +++ b/FredBoat/src/main/java/fredboat/api/API.java @@ -74,8 +74,8 @@ public static void start() { for (FredBoat fb : shards) { JSONObject fbStats = new JSONObject(); fbStats.put("id", fb.getShardInfo().getShardId()) - .put("guilds", fb.getJda().getGuilds().size()) - .put("users", fb.getJda().getUsers().size()) + .put("guilds", fb.getGuildCount()) + .put("users", fb.getUserCount()) .put("status", fb.getJda().getStatus()); a.put(fbStats); diff --git a/FredBoat/src/main/java/fredboat/audio/AbstractPlayer.java b/FredBoat/src/main/java/fredboat/audio/AbstractPlayer.java index bee652e9f..285cdb2d6 100644 --- a/FredBoat/src/main/java/fredboat/audio/AbstractPlayer.java +++ b/FredBoat/src/main/java/fredboat/audio/AbstractPlayer.java @@ -32,7 +32,6 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; import com.sedmelluq.discord.lavaplayer.source.bandcamp.BandcampAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.beam.BeamAudioSourceManager; -import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager; import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; @@ -49,7 +48,7 @@ import fredboat.audio.queue.TrackEndMarkerHandler; import fredboat.audio.source.PlaylistImportSourceManager; import fredboat.audio.source.SpotifyPlaylistSourceManager; -import fredboat.util.constant.DistributionEnum; +import fredboat.shared.constant.DistributionEnum; import net.dv8tion.jda.core.audio.AudioSendHandler; import org.slf4j.LoggerFactory; @@ -94,7 +93,7 @@ private static void initAudioPlayerManager() { playerManager.useRemoteNodes(Config.CONFIG.getLavaplayerNodes()); } - playerManager.setItemLoaderThreadPoolSize(100); + playerManager.setItemLoaderThreadPoolSize(500); } } @@ -111,7 +110,8 @@ public static AudioPlayerManager registerSourceManagers(AudioPlayerManager mng) } //add new source managers above the HttpAudio one, because it will either eat your request or throw an exception //so you will never reach a source manager below it - mng.registerSourceManager(new HttpAudioSourceManager()); + // commented out to prevent leaking our ip +// mng.registerSourceManager(new HttpAudioSourceManager()); return mng; } diff --git a/FredBoat/src/main/java/fredboat/audio/GuildPlayer.java b/FredBoat/src/main/java/fredboat/audio/GuildPlayer.java index 66cbcca64..795a53afd 100644 --- a/FredBoat/src/main/java/fredboat/audio/GuildPlayer.java +++ b/FredBoat/src/main/java/fredboat/audio/GuildPlayer.java @@ -191,8 +191,13 @@ public List getLiveTracks() { return l; } + //may return null public VoiceChannel getChannel() { - return getUserCurrentVoiceChannel(getGuild().getSelfMember()); + Guild guild = getGuild(); + if (guild != null) + return getUserCurrentVoiceChannel(guild.getSelfMember()); + else + return null; } /** diff --git a/FredBoat/src/main/java/fredboat/audio/MusicPersistenceHandler.java b/FredBoat/src/main/java/fredboat/audio/MusicPersistenceHandler.java index 99607d2ed..da0720919 100644 --- a/FredBoat/src/main/java/fredboat/audio/MusicPersistenceHandler.java +++ b/FredBoat/src/main/java/fredboat/audio/MusicPersistenceHandler.java @@ -34,8 +34,8 @@ import fredboat.audio.queue.RepeatMode; import fredboat.audio.queue.SplitAudioTrackContext; import fredboat.feature.I18n; -import fredboat.util.constant.DistributionEnum; -import fredboat.util.constant.ExitCodes; +import fredboat.shared.constant.DistributionEnum; +import fredboat.shared.constant.ExitCodes; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.VoiceChannel; diff --git a/FredBoat/src/main/java/fredboat/command/admin/BotRestartCommand.java b/FredBoat/src/main/java/fredboat/command/admin/BotRestartCommand.java index f1ec73197..3c379604d 100644 --- a/FredBoat/src/main/java/fredboat/command/admin/BotRestartCommand.java +++ b/FredBoat/src/main/java/fredboat/command/admin/BotRestartCommand.java @@ -30,7 +30,7 @@ import fredboat.commandmeta.abs.ICommand; import fredboat.commandmeta.abs.ICommandRestricted; import fredboat.perms.PermissionLevel; -import fredboat.util.constant.ExitCodes; +import fredboat.shared.constant.ExitCodes; import fredboat.util.TextUtils; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; diff --git a/FredBoat/src/main/java/fredboat/command/admin/ExitCommand.java b/FredBoat/src/main/java/fredboat/command/admin/ExitCommand.java index e85300a73..22d0393b0 100644 --- a/FredBoat/src/main/java/fredboat/command/admin/ExitCommand.java +++ b/FredBoat/src/main/java/fredboat/command/admin/ExitCommand.java @@ -30,7 +30,7 @@ import fredboat.commandmeta.abs.ICommand; import fredboat.commandmeta.abs.ICommandRestricted; import fredboat.perms.PermissionLevel; -import fredboat.util.constant.ExitCodes; +import fredboat.shared.constant.ExitCodes; import fredboat.util.TextUtils; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; diff --git a/FredBoat/src/main/java/fredboat/command/admin/UpdateCommand.java b/FredBoat/src/main/java/fredboat/command/admin/UpdateCommand.java index 3b0899373..db251f512 100644 --- a/FredBoat/src/main/java/fredboat/command/admin/UpdateCommand.java +++ b/FredBoat/src/main/java/fredboat/command/admin/UpdateCommand.java @@ -30,7 +30,7 @@ import fredboat.commandmeta.abs.ICommand; import fredboat.commandmeta.abs.ICommandRestricted; import fredboat.perms.PermissionLevel; -import fredboat.util.constant.ExitCodes; +import fredboat.shared.constant.ExitCodes; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; diff --git a/FredBoat/src/main/java/fredboat/command/maintenance/GitInfoCommand.java b/FredBoat/src/main/java/fredboat/command/maintenance/GitInfoCommand.java index c8895df8d..c81be30f2 100644 --- a/FredBoat/src/main/java/fredboat/command/maintenance/GitInfoCommand.java +++ b/FredBoat/src/main/java/fredboat/command/maintenance/GitInfoCommand.java @@ -68,7 +68,7 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy @ hh:mm:ss z"); EmbedBuilder embedBuilder = new EmbedBuilder(); - embedBuilder.setTitle("Build & git info", url); + embedBuilder.setTitle("Build & git info"); embedBuilder.addField("Commit info", gitRepoState.describe + "\n\n" + gitRepoState.commitMessageFull, false); embedBuilder.addField("Commit timestamp", gitRepoState.commitTime, false); embedBuilder.addField("Commit on Github", url, false); diff --git a/FredBoat/src/main/java/fredboat/command/maintenance/PingCommand.java b/FredBoat/src/main/java/fredboat/command/maintenance/PingCommand.java new file mode 100644 index 000000000..0e653cb43 --- /dev/null +++ b/FredBoat/src/main/java/fredboat/command/maintenance/PingCommand.java @@ -0,0 +1,33 @@ +package fredboat.command.maintenance; + +import fredboat.commandmeta.abs.Command; +import fredboat.commandmeta.abs.IMaintenanceCommand; +import net.dv8tion.jda.core.JDA; +import net.dv8tion.jda.core.entities.*; + +/** + * Created by epcs on 6/30/2017. + * Good enough of an indicator of the ping to Discord. + */ + +public class PingCommand extends Command implements IMaintenanceCommand { + @Override + public String help(Guild guild) { + return "{0}{1}\n#Returns the ping to Discord."; //TODO: i18n + } + + @Override + public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message message, String[] args) { + + JDA jda = guild.getJDA(); + long ping = jda.getPing(); + + channel.sendMessage(ping + "ms").queue(); + } +} + +//hello +//this is a comment +//I want pats +//multiple pats +//pats never seen before diff --git a/FredBoat/src/main/java/fredboat/command/maintenance/ShardsCommand.java b/FredBoat/src/main/java/fredboat/command/maintenance/ShardsCommand.java index 0aa003f15..984b6779d 100644 --- a/FredBoat/src/main/java/fredboat/command/maintenance/ShardsCommand.java +++ b/FredBoat/src/main/java/fredboat/command/maintenance/ShardsCommand.java @@ -29,10 +29,10 @@ import fredboat.FredBoat; import fredboat.commandmeta.abs.Command; import fredboat.commandmeta.abs.IMaintenanceCommand; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.MessageBuilder; import net.dv8tion.jda.core.entities.*; +import net.dv8tion.jda.core.entities.impl.JDAImpl; import java.util.ArrayList; import java.util.List; @@ -57,11 +57,12 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m List shards = new ArrayList<>(FredBoat.getShards()); int borkenShards = 0; int healthyGuilds = 0; - LongOpenHashSet healthyUsers = new LongOpenHashSet(FredBoat.getExpectedUserCount()); + int healthyUsers = 0; for (FredBoat fb : shards) { if (fb.getJda().getStatus() == JDA.Status.CONNECTED && !full) { - healthyGuilds += fb.getJda().getGuilds().size(); - fb.getJda().getUsers().parallelStream().mapToLong(ISnowflake::getIdLong).forEach(healthyUsers::add); + healthyGuilds += fb.getGuildCount(); + // casting to get the underlying map, this is safe because we only need the .size() + healthyUsers += ((JDAImpl) fb.getJda()).getUserMap().size(); } else { if (borkenShards % SHARDS_PER_MESSAGE == 0) { mb = new MessageBuilder() @@ -74,9 +75,9 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m .append(" ") .append(fb.getJda().getStatus()) .append(" -- Guilds: ") - .append(String.format("%04d", fb.getJda().getGuilds().size())) + .append(String.format("%04d", fb.getGuildCount())) .append(" -- Users: ") - .append(fb.getJda().getUsers().size()) + .append(fb.getUserCount()) .append("\n"); borkenShards++; } @@ -86,7 +87,7 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m if (!full) { channel.sendMessage("```diff\n+ " + (shards.size() - borkenShards) + "/" + Config.CONFIG.getNumShards() + " shards are " + JDA.Status.CONNECTED - + " -- Guilds: " + healthyGuilds + " -- Users: " + healthyUsers.size() + "\n```").queue(); + + " -- Guilds: " + healthyGuilds + " -- Users: " + healthyUsers + "\n```").queue(); } //detailed shards diff --git a/FredBoat/src/main/java/fredboat/command/moderation/HardbanCommand.java b/FredBoat/src/main/java/fredboat/command/moderation/HardbanCommand.java index 4b4c14cc8..5e1e9e846 100644 --- a/FredBoat/src/main/java/fredboat/command/moderation/HardbanCommand.java +++ b/FredBoat/src/main/java/fredboat/command/moderation/HardbanCommand.java @@ -37,10 +37,12 @@ import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.requests.RestAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.MessageFormat; +import java.util.function.Consumer; /** * Created by napster on 19.04.17. @@ -62,18 +64,35 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m return; } + //was there a target provided? Member target = ArgumentUtil.checkSingleFuzzyMemberSearchResult(channel, args[1]); - if (target == null) return; + //are we allowed to do that? if (!checkHardBanAuthorization(channel, invoker, target)) return; - target.getGuild().getController().ban(target, 7).queue( - aVoid -> { - TextUtils.replyWithName(channel, invoker, MessageFormat.format(I18n.get(guild).getString("hardbanSuccess"), target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId())); - }, - throwable -> log.error(MessageFormat.format(I18n.get(guild).getString("modBanFail"), target.getUser())) - ); + //putting together a reason + String plainReason = DiscordUtil.getReasonForModAction(args, guild); + String auditLogReason = DiscordUtil.formatReasonForAuditLog(plainReason, guild, invoker); + + //putting together the action + RestAction modAction = guild.getController().ban(target, 7, auditLogReason); + + //on success + String successOutput = MessageFormat.format(I18n.get(guild).getString("hardbanSuccess"), + target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId()) + + "\n" + plainReason; + Consumer onSuccess = aVoid -> TextUtils.replyWithName(channel, invoker, successOutput); + + //on fail + String failOutput = MessageFormat.format(I18n.get(guild).getString("modBanFail"), target.getUser()); + Consumer onFail = t -> { + log.error("Failed to ban user {} in guild {}", target.getUser().getIdLong(), guild.getIdLong(), t); + TextUtils.replyWithName(channel, invoker, failOutput); + }; + + //issue the mod action + modAction.queue(onSuccess, onFail); } private boolean checkHardBanAuthorization(TextChannel channel, Member mod, Member target) { @@ -118,7 +137,7 @@ private boolean checkHardBanAuthorization(TextChannel channel, Member mod, Membe @Override public String help(Guild guild) { - String usage = "{0}{1} \n#"; + String usage = "{0}{1} \n#"; return usage + I18n.get(guild).getString("helpHardbanCommand"); } } diff --git a/FredBoat/src/main/java/fredboat/command/moderation/KickCommand.java b/FredBoat/src/main/java/fredboat/command/moderation/KickCommand.java index 1a9366307..71a3c0e3c 100644 --- a/FredBoat/src/main/java/fredboat/command/moderation/KickCommand.java +++ b/FredBoat/src/main/java/fredboat/command/moderation/KickCommand.java @@ -37,10 +37,12 @@ import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.requests.RestAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.MessageFormat; +import java.util.function.Consumer; /** * Created by napster on 19.04.17. @@ -62,18 +64,35 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m return; } + //was there a target provided? Member target = ArgumentUtil.checkSingleFuzzyMemberSearchResult(channel, args[1]); - if (target == null) return; + //are we allowed to do that? if (!checkKickAuthorization(channel, invoker, target)) return; - target.getGuild().getController().kick(target).queue( - aVoid -> { - TextUtils.replyWithName(channel, invoker, MessageFormat.format(I18n.get(guild).getString("kickSuccess"), target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId())); - }, - throwable -> log.error(MessageFormat.format(I18n.get(guild).getString("kickFail"), target.getUser())) - ); + //putting together a reason + String plainReason = DiscordUtil.getReasonForModAction(args, guild); + String auditLogReason = DiscordUtil.formatReasonForAuditLog(plainReason, guild, invoker); + + //putting together the action + RestAction modAction = guild.getController().kick(target, auditLogReason); + + //on success + String successOutput = MessageFormat.format(I18n.get(guild).getString("kickSuccess"), + target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId()) + + "\n" + plainReason; + Consumer onSuccess = aVoid -> TextUtils.replyWithName(channel, invoker, successOutput); + + //on fail + String failOutput = MessageFormat.format(I18n.get(guild).getString("kickFail"), target.getUser()); + Consumer onFail = t -> { + log.error("Failed to kick user {} in guild {}", target.getUser().getIdLong(), guild.getIdLong(), t); + TextUtils.replyWithName(channel, invoker, failOutput); + }; + + //issue the mod action + modAction.queue(onSuccess, onFail); } private boolean checkKickAuthorization(TextChannel channel, Member mod, Member target) { @@ -117,7 +136,7 @@ private boolean checkKickAuthorization(TextChannel channel, Member mod, Member t @Override public String help(Guild guild) { - String usage = "{0}{1} \n#"; + String usage = "{0}{1} \n#"; return usage + I18n.get(guild).getString("helpKickCommand"); } } diff --git a/FredBoat/src/main/java/fredboat/command/moderation/PermissionsCommand.java b/FredBoat/src/main/java/fredboat/command/moderation/PermissionsCommand.java index 84119fd0f..8ab907eec 100644 --- a/FredBoat/src/main/java/fredboat/command/moderation/PermissionsCommand.java +++ b/FredBoat/src/main/java/fredboat/command/moderation/PermissionsCommand.java @@ -32,11 +32,12 @@ import fredboat.db.EntityWriter; import fredboat.db.entity.GuildPermissions; import fredboat.feature.I18n; +import fredboat.feature.togglz.FeatureFlags; import fredboat.perms.PermissionLevel; import fredboat.perms.PermsUtil; +import fredboat.shared.constant.BotConstants; import fredboat.util.ArgumentUtil; import fredboat.util.TextUtils; -import fredboat.util.constant.BotConstants; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.Permission; import net.dv8tion.jda.core.entities.Guild; @@ -66,6 +67,11 @@ public PermissionsCommand(PermissionLevel permissionLevel) { @Override public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message message, String[] args) { + if (!FeatureFlags.PERMISSIONS.isActive()) { + channel.sendMessage("Permissions are currently disabled.").queue(); + return; + } + if (args.length < 2) { HelpCommand.sendFormattedCommandHelp(message); return; diff --git a/FredBoat/src/main/java/fredboat/command/moderation/SoftbanCommand.java b/FredBoat/src/main/java/fredboat/command/moderation/SoftbanCommand.java index 52d2ddb75..5aae530ce 100644 --- a/FredBoat/src/main/java/fredboat/command/moderation/SoftbanCommand.java +++ b/FredBoat/src/main/java/fredboat/command/moderation/SoftbanCommand.java @@ -38,10 +38,12 @@ import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.entities.TextChannel; +import net.dv8tion.jda.core.requests.RestAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.MessageFormat; +import java.util.function.Consumer; public class SoftbanCommand extends Command implements IModerationCommand { @@ -50,25 +52,44 @@ public class SoftbanCommand extends Command implements IModerationCommand { @Override public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message message, String[] args) { //Ensure we have a search term - if(args.length == 1){ + if (args.length == 1) { String command = args[0].substring(Config.CONFIG.getPrefix().length()); HelpCommand.sendFormattedCommandHelp(guild, channel, invoker, command); return; } + //was there a target provided? Member target = ArgumentUtil.checkSingleFuzzyMemberSearchResult(channel, args[1]); - if (target == null) return; + //are we allowed to do that? if (!checkAuthorization(channel, invoker, target)) return; - target.getGuild().getController().ban(target, 7).queue( - aVoid -> { - target.getGuild().getController().unban(target.getUser()).queue(); - TextUtils.replyWithName(channel, invoker, MessageFormat.format(I18n.get(guild).getString("softbanSuccess"), target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId())); - }, - throwable -> log.error(MessageFormat.format(I18n.get(guild).getString("modBanFail"), target.getUser())) - ); + //putting together a reason + String plainReason = DiscordUtil.getReasonForModAction(args, guild); + String auditLogReason = DiscordUtil.formatReasonForAuditLog(plainReason, guild, invoker); + + //putting together the action + RestAction modAction = guild.getController().ban(target, 7, auditLogReason); + + //on success + String successOutput = MessageFormat.format(I18n.get(guild).getString("softbanSuccess"), + target.getUser().getName(), target.getUser().getDiscriminator(), target.getUser().getId()) + + "\n" + plainReason; + Consumer onSuccess = aVoid -> { + guild.getController().unban(target.getUser()).queue(); + TextUtils.replyWithName(channel, invoker, successOutput); + }; + + //on fail + String failOutput = MessageFormat.format(I18n.get(guild).getString("modBanFail"), target.getUser()); + Consumer onFail = t -> { + log.error("Failed to ban user {} in guild {}", target.getUser().getIdLong(), guild.getIdLong(), t); + TextUtils.replyWithName(channel, invoker, failOutput); + }; + + //issue the mod action + modAction.queue(onSuccess, onFail); } private boolean checkAuthorization(TextChannel channel, Member mod, Member target) { @@ -112,7 +133,7 @@ private boolean checkAuthorization(TextChannel channel, Member mod, Member targe @Override public String help(Guild guild) { - String usage = "{0}{1} \n#"; + String usage = "{0}{1} \n#"; return usage + I18n.get(guild).getString("helpSoftbanCommand"); } } diff --git a/FredBoat/src/main/java/fredboat/command/music/control/SkipCommand.java b/FredBoat/src/main/java/fredboat/command/music/control/SkipCommand.java index 36881f561..f78cf1355 100644 --- a/FredBoat/src/main/java/fredboat/command/music/control/SkipCommand.java +++ b/FredBoat/src/main/java/fredboat/command/music/control/SkipCommand.java @@ -42,10 +42,15 @@ import net.dv8tion.jda.core.entities.TextChannel; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.logging.impl.SLF4JLog; +import org.slf4j.LoggerFactory; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -53,20 +58,41 @@ public class SkipCommand extends Command implements IMusicCommand, ICommandRestr private static final String TRACK_RANGE_REGEX = "^(0?\\d+)-(0?\\d+)$"; private static final Pattern trackRangePattern = Pattern.compile(TRACK_RANGE_REGEX); + /** + * Represents the relationship between a guild's id and skip cooldown. + */ + private static Map guildIdToLastSkip = new HashMap(); + + /** + * The default cooldown for calling the {@link #onInvoke} method in milliseconds. + */ + private static final int SKIP_COOLDOWN = 500; + @Override public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message message, String[] args) { GuildPlayer player = PlayerRegistry.get(guild); player.setCurrentTC(channel); + if (player.isQueueEmpty()) { channel.sendMessage(I18n.get(guild).getString("skipEmpty")).queue(); return; } - if(args.length == 1){ + if (!guildIdToLastSkip.containsKey(guild.getId())) { + guildIdToLastSkip.put(guild.getId(), System.currentTimeMillis()); + } + + if (isOnCooldown(guild)) { + return; + } + + guildIdToLastSkip.put(guild.getId(), System.currentTimeMillis()); + + if (args.length == 1) { skipNext(guild, channel, invoker, args); } else if (args.length == 2 && StringUtils.isNumeric(args[1])) { skipGivenIndex(player, channel, invoker, args); - } else if (args.length == 2 && trackRangePattern.matcher(args[1]).matches()){ + } else if (args.length == 2 && trackRangePattern.matcher(args[1]).matches()) { skipInRange(player, channel, invoker, args); } else { String command = args[0].substring(Config.CONFIG.getPrefix().length()); @@ -74,18 +100,29 @@ public void onInvoke(Guild guild, TextChannel channel, Member invoker, Message m } } + /** + * Specifies whether the skip command is on cooldown. + * @param guild The guild where the skip command was called. + * @return {@code true} if the elapsed time since the skip command is less than or equal to + * {@link #SKIP_COOLDOWN}; otherwise, {@code false}. + */ + private boolean isOnCooldown(Guild guild) { + long currentTIme = System.currentTimeMillis(); + return currentTIme - guildIdToLastSkip.get(guild.getId()) <= SKIP_COOLDOWN; + } + private void skipGivenIndex(GuildPlayer player, TextChannel channel, Member invoker, String[] args) { int givenIndex = Integer.parseInt(args[1]); - if(givenIndex == 1){ + if (givenIndex == 1) { skipNext(channel.getGuild(), channel, invoker, args); return; } - if(player.getRemainingTracks().size() < givenIndex){ + if (player.getRemainingTracks().size() < givenIndex) { channel.sendMessage(MessageFormat.format(I18n.get(channel.getGuild()).getString("skipOutOfBounds"), givenIndex, player.getRemainingTracks().size())).queue(); return; - } else if (givenIndex < 1){ + } else if (givenIndex < 1) { channel.sendMessage(I18n.get(channel.getGuild()).getString("skipNumberTooLow")).queue(); return; } @@ -94,7 +131,7 @@ private void skipGivenIndex(GuildPlayer player, TextChannel channel, Member invo player.skipTracksForMemberPerms(channel, invoker, atc); Pair result = player.skipTracksForMemberPerms(channel, invoker, atc); - if(result.getLeft()) { + if (result.getLeft()) { channel.sendMessage(MessageFormat.format(I18n.get(channel.getGuild()).getString("skipSuccess"), givenIndex, atc.getEffectiveTitle())).queue(); } } @@ -103,7 +140,8 @@ private void skipInRange(GuildPlayer player, TextChannel channel, Member invoker Matcher trackMatch = trackRangePattern.matcher(args[1]); if (!trackMatch.find()) return; - int startTrackIndex, endTrackIndex; + int startTrackIndex; + int endTrackIndex; String tmp = ""; try { tmp = trackMatch.group(1); @@ -135,21 +173,21 @@ private void skipInRange(GuildPlayer player, TextChannel channel, Member invoker Pair pair = player.skipTracksForMemberPerms(channel, invoker, tracks); - if(pair.getLeft()) { + if (pair.getLeft()) { channel.sendMessage(MessageFormat.format(I18n.get(channel.getGuild()).getString("skipRangeSuccess"), TextUtils.forceNDigits(startTrackIndex, 2), TextUtils.forceNDigits(endTrackIndex, 2))).queue(); } } - private void skipNext(Guild guild, TextChannel channel, Member invoker, String[] args){ + private void skipNext(Guild guild, TextChannel channel, Member invoker, String[] args) { GuildPlayer player = PlayerRegistry.get(guild); AudioTrackContext atc = player.getPlayingTrack(); - if(atc == null) { + if (atc == null) { channel.sendMessage(I18n.get(guild).getString("skipTrackNotFound")).queue(); } else { Pair result = player.skipTracksForMemberPerms(channel, invoker, atc); - if(result.getLeft()) { + if (result.getLeft()) { channel.sendMessage(MessageFormat.format(I18n.get(guild).getString("skipSuccess"), 1, atc.getEffectiveTitle())).queue(); } } diff --git a/FredBoat/src/main/java/fredboat/command/music/info/NowplayingCommand.java b/FredBoat/src/main/java/fredboat/command/music/info/NowplayingCommand.java index abfaa80f3..d84210c53 100644 --- a/FredBoat/src/main/java/fredboat/command/music/info/NowplayingCommand.java +++ b/FredBoat/src/main/java/fredboat/command/music/info/NowplayingCommand.java @@ -41,7 +41,7 @@ import fredboat.commandmeta.abs.Command; import fredboat.commandmeta.abs.IMusicCommand; import fredboat.feature.I18n; -import fredboat.util.constant.BotConstants; +import fredboat.shared.constant.BotConstants; import fredboat.util.TextUtils; import fredboat.util.rest.YoutubeAPI; import fredboat.util.rest.YoutubeVideo; diff --git a/FredBoat/src/main/java/fredboat/command/util/ServerInfoCommand.java b/FredBoat/src/main/java/fredboat/command/util/ServerInfoCommand.java index e32a66aef..fd61c7f49 100644 --- a/FredBoat/src/main/java/fredboat/command/util/ServerInfoCommand.java +++ b/FredBoat/src/main/java/fredboat/command/util/ServerInfoCommand.java @@ -28,7 +28,7 @@ import fredboat.commandmeta.abs.Command; import fredboat.commandmeta.abs.IUtilCommand; import fredboat.feature.I18n; -import fredboat.util.constant.BotConstants; +import fredboat.shared.constant.BotConstants; import net.dv8tion.jda.core.EmbedBuilder; import net.dv8tion.jda.core.OnlineStatus; import net.dv8tion.jda.core.entities.Guild; diff --git a/FredBoat/src/main/java/fredboat/commandmeta/CommandManager.java b/FredBoat/src/main/java/fredboat/commandmeta/CommandManager.java index 27d27a20c..7eb738f91 100644 --- a/FredBoat/src/main/java/fredboat/commandmeta/CommandManager.java +++ b/FredBoat/src/main/java/fredboat/commandmeta/CommandManager.java @@ -34,10 +34,10 @@ import fredboat.feature.I18n; import fredboat.perms.PermissionLevel; import fredboat.perms.PermsUtil; +import fredboat.shared.constant.BotConstants; +import fredboat.shared.constant.DistributionEnum; import fredboat.util.DiscordUtil; import fredboat.util.TextUtils; -import fredboat.util.constant.BotConstants; -import fredboat.util.constant.DistributionEnum; import fredboat.util.rest.RestActionScheduler; import net.dv8tion.jda.core.Permission; import net.dv8tion.jda.core.entities.Guild; diff --git a/FredBoat/src/main/java/fredboat/commandmeta/abs/Command.java b/FredBoat/src/main/java/fredboat/commandmeta/abs/Command.java index 79547e481..2fbcd59b5 100644 --- a/FredBoat/src/main/java/fredboat/commandmeta/abs/Command.java +++ b/FredBoat/src/main/java/fredboat/commandmeta/abs/Command.java @@ -34,11 +34,11 @@ import java.util.ArrayList; public abstract class Command implements ICommand { - + public static String name = "Undefined"; - public static ArrayList aliasses = new ArrayList<>(); - - public void onInvoke(JDA jda, Guild guild, TextChannel channel, Member invoker, Message message, ArrayList args){ + public static ArrayList aliases = new ArrayList<>(); + + public void onInvoke(JDA jda, Guild guild, TextChannel channel, Member invoker, Message message, ArrayList args) { String[] newA = new String[args.size()]; int i = 0; for (String str : args) { @@ -47,25 +47,25 @@ public void onInvoke(JDA jda, Guild guild, TextChannel channel, Member invoker, } onInvoke(guild, channel, invoker, message, newA);//Old system is default } - + public static CommandInfo getCommandInfo(){ - return new CommandInfo(name, "Undefined", "Undefined", aliasses); + return new CommandInfo(name, "Undefined", "Undefined", aliases); } - + public static class CommandInfo { - + public String name; public String desc; public String usage; - public ArrayList aliasses; + public ArrayList aliases; - public CommandInfo(String name, String desc, String usage, ArrayList aliasses) { + public CommandInfo(String name, String desc, String usage, ArrayList aliases) { this.name = name; this.desc = desc; this.usage = usage; - this.aliasses = aliasses; + this.aliases = aliases; } - + } - + } diff --git a/FredBoat/src/main/java/fredboat/commandmeta/init/MainCommandInitializer.java b/FredBoat/src/main/java/fredboat/commandmeta/init/MainCommandInitializer.java index 422f785f9..c8010d075 100644 --- a/FredBoat/src/main/java/fredboat/commandmeta/init/MainCommandInitializer.java +++ b/FredBoat/src/main/java/fredboat/commandmeta/init/MainCommandInitializer.java @@ -38,41 +38,47 @@ public class MainCommandInitializer { public static void initCommands() { CommandRegistry.registerCommand("help", new HelpCommand(), "info"); - - CommandRegistry.registerCommand("unblacklist", new UnblacklistCommand(), "unlimit"); CommandRegistry.registerCommand("commands", new CommandsCommand(), "comms", "cmds"); + CommandRegistry.registerCommand("invite", new InviteCommand()); + + /* Bot Maintenance */ + CommandRegistry.registerCommand("unblacklist", new UnblacklistCommand(), "unlimit"); CommandRegistry.registerCommand("version", new VersionCommand()); - CommandRegistry.registerCommand("say", new SayCommand()); CommandRegistry.registerCommand("uptime", new StatsCommand(), "stats"); - CommandRegistry.registerCommand("serverinfo", new fredboat.command.util.ServerInfoCommand(), "guildinfo"); - CommandRegistry.registerCommand("invite", new InviteCommand()); - CommandRegistry.registerCommand("userinfo", new fredboat.command.util.UserInfoCommand(), "memberinfo"); + CommandRegistry.registerCommand("update", new UpdateCommand()); + CommandRegistry.registerCommand("compile", new CompileCommand()); + CommandRegistry.registerCommand("mvntest", new MavenTestCommand()); + CommandRegistry.registerCommand("botrestart", new BotRestartCommand()); + CommandRegistry.registerCommand("eval", new EvalCommand()); + CommandRegistry.registerCommand("shards", new ShardsCommand()); + CommandRegistry.registerCommand("revive", new ReviveCommand()); + CommandRegistry.registerCommand("test", new TestCommand()); CommandRegistry.registerCommand("gitinfo", new GitInfoCommand(), "git"); CommandRegistry.registerCommand("exit", new ExitCommand()); - CommandRegistry.registerCommand("avatar", new AvatarCommand(), "ava"); - CommandRegistry.registerCommand("test", new TestCommand()); - CommandRegistry.registerCommand("brainfuck", new BrainfuckCommand()); + + /* Moderation */ + CommandRegistry.registerCommand("hardban", new HardbanCommand()); + CommandRegistry.registerCommand("kick", new KickCommand()); + CommandRegistry.registerCommand("softban", new SoftbanCommand()); + CommandRegistry.registerCommand("clear", new ClearCommand()); + + /* Util */ + CommandRegistry.registerCommand("serverinfo", new fredboat.command.util.ServerInfoCommand(), "guildinfo"); + CommandRegistry.registerCommand("userinfo", new fredboat.command.util.UserInfoCommand(), "memberinfo"); + CommandRegistry.registerCommand("ping", new PingCommand()); + CommandRegistry.registerCommand("fuzzy", new FuzzyUserSearchCommand()); + + /* Fun Commands */ CommandRegistry.registerCommand("joke", new JokeCommand(), "jk"); //TODO LeetCommand is borken. Don't throw unnecessary error reports until it's fixed or removed. // CommandRegistry.registerCommand("leet", new LeetCommand(), "1337", "l33t", "1ee7"); CommandRegistry.registerCommand("riot", new RiotCommand()); - CommandRegistry.registerCommand("update", new UpdateCommand()); - CommandRegistry.registerCommand("compile", new CompileCommand()); - CommandRegistry.registerCommand("mvntest", new MavenTestCommand()); - CommandRegistry.registerCommand("botrestart", new BotRestartCommand()); CommandRegistry.registerCommand("dance", new DanceCommand()); - CommandRegistry.registerCommand("eval", new EvalCommand()); - CommandRegistry.registerCommand("clear", new ClearCommand()); CommandRegistry.registerCommand("talk", new TalkCommand()); - CommandRegistry.registerCommand("mal", new MALCommand()); CommandRegistry.registerCommand("akinator", new AkinatorCommand()); - CommandRegistry.registerCommand("fuzzy", new FuzzyUserSearchCommand()); - CommandRegistry.registerCommand("hardban", new HardbanCommand()); - CommandRegistry.registerCommand("kick", new KickCommand()); - CommandRegistry.registerCommand("softban", new SoftbanCommand()); CommandRegistry.registerCommand("catgirl", new CatgirlCommand(), "neko", "catgrill"); - CommandRegistry.registerCommand("shards", new ShardsCommand()); - CommandRegistry.registerCommand("revive", new ReviveCommand()); + CommandRegistry.registerCommand("avatar", new AvatarCommand(), "ava"); + CommandRegistry.registerCommand("say", new SayCommand()); /* Other Anime Discord, Sergi memes or any other memes */ // saved in this album https://imgur.com/a/wYvDu @@ -101,13 +107,20 @@ public static void initCommands() { CommandRegistry.registerCommand("faceofdisapproval", new TextCommand("ಠ_ಠ"), "fod", "disapproving"); CommandRegistry.registerCommand("sendenergy", new TextCommand("༼ つ ◕_◕ ༽つ")); CommandRegistry.registerCommand("peeking", new TextCommand("┬┴┬┴┤ ͜ʖ ͡°) ├┬┴┬┴"), "peekinglenny", "peek"); - CommandRegistry.registerCommand("dealwithit", new TextCommand("(•\\_•) ( •\\_•)>⌐■-■ (⌐■_■)"), "dwi"); //NOTE: This may break, depending on how the backlashes are handled. + CommandRegistry.registerCommand("dealwithit", new TextCommand("(•\\_•) ( •\\_•)>⌐■-■ (⌐■_■)"), "dwi"); CommandRegistry.registerCommand("channelingenergy", new TextCommand("(ノ◕ヮ◕)ノ*:・゚✧ ✧゚・: *ヽ(◕ヮ◕ヽ)")); CommandRegistry.registerCommand("butterfly", new TextCommand("Ƹ̵̡Ӝ̵̨̄Ʒ")); - CommandRegistry.registerCommand("angrytableflip", new TextCommand("(ノಠ益ಠ)ノ彡┻━┻"), "tableflipbutangry"); + CommandRegistry.registerCommand("angrytableflip", new TextCommand("(ノಠ益ಠ)ノ彡┻━┻"), "tableflipbutangry", "atp"); CommandRegistry.registerCommand("cooldog", new DogCommand(), "dog", "dogmeme"); - CommandRegistry.registerCommand("lood", new TextCommand("T-that's l-lewd, baka!!!"), "lewd"); + CommandRegistry.registerCommand("lood", new TextCommand("T-that's l-lewd, baka!!!"), "lewd", "l00d"); CommandRegistry.registerCommand("useless", new TextCommand("This command is useless.")); + CommandRegistry.registerCommand("swtf", new TextCommand("¯\\\\(°_o)/¯"), "shrugwtf"); + CommandRegistry.registerCommand("hurray", new TextCommand("ヽ(^o^)ノ"), "yay", "woot"); + + /* Misc - All commands under this line fall in this category */ + + CommandRegistry.registerCommand("mal", new MALCommand()); + CommandRegistry.registerCommand("brainfuck", new BrainfuckCommand()); CommandRegistry.registerCommand("github", new TextCommand("https://github.com/Frederikam")); CommandRegistry.registerCommand("repo", new TextCommand("https://github.com/Frederikam/FredBoat")); diff --git a/FredBoat/src/main/java/fredboat/commandmeta/init/MusicCommandInitializer.java b/FredBoat/src/main/java/fredboat/commandmeta/init/MusicCommandInitializer.java index f5e9ea413..5a27e84ff 100644 --- a/FredBoat/src/main/java/fredboat/commandmeta/init/MusicCommandInitializer.java +++ b/FredBoat/src/main/java/fredboat/commandmeta/init/MusicCommandInitializer.java @@ -43,9 +43,10 @@ import fredboat.command.util.CommandsCommand; import fredboat.command.util.HelpCommand; import fredboat.command.util.MusicHelpCommand; +import fredboat.command.util.UserInfoCommand; import fredboat.commandmeta.CommandRegistry; import fredboat.perms.PermissionLevel; -import fredboat.util.constant.DistributionEnum; +import fredboat.shared.constant.DistributionEnum; import fredboat.util.rest.SearchUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,52 +57,63 @@ public class MusicCommandInitializer { public static void initCommands() { CommandRegistry.registerCommand("help", new HelpCommand(), "info"); - - CommandRegistry.registerCommand("mgitinfo", new GitInfoCommand(), "mgit"); - CommandRegistry.registerCommand("munblacklist", new UnblacklistCommand(), "munlimit"); - CommandRegistry.registerCommand("mexit", new ExitCommand()); - CommandRegistry.registerCommand("mbotrestart", new BotRestartCommand()); - CommandRegistry.registerCommand("mstats", new StatsCommand()); + CommandRegistry.registerCommand("music", new MusicHelpCommand(), "musichelp"); + CommandRegistry.registerCommand("commands", new CommandsCommand(), "comms", "cmds"); + + /* Control */ CommandRegistry.registerCommand("play", new PlayCommand(SearchUtil.SearchProvider.YOUTUBE), "yt", "youtube"); CommandRegistry.registerCommand("sc", new PlayCommand(SearchUtil.SearchProvider.SOUNDCLOUD), "soundcloud"); - CommandRegistry.registerCommand("meval", new EvalCommand()); CommandRegistry.registerCommand("skip", new SkipCommand(), "sk"); CommandRegistry.registerCommand("join", new JoinCommand(), "summon", "jn"); - CommandRegistry.registerCommand("nowplaying", new NowplayingCommand(), "np"); CommandRegistry.registerCommand("leave", new LeaveCommand(), "lv"); - CommandRegistry.registerCommand("list", new ListCommand(), "queue", "q"); - CommandRegistry.registerCommand("mupdate", new UpdateCommand()); - CommandRegistry.registerCommand("mcompile", new CompileCommand()); - CommandRegistry.registerCommand("mmvntest", new MavenTestCommand()); CommandRegistry.registerCommand("select", new SelectCommand(), "sel"); CommandRegistry.registerCommand("stop", new StopCommand(), "st"); CommandRegistry.registerCommand("pause", new PauseCommand(), "pa", "ps"); - CommandRegistry.registerCommand("unpause", new UnpauseCommand(), "unp", "resume"); - CommandRegistry.registerCommand("getid", new GetIdCommand()); CommandRegistry.registerCommand("shuffle", new ShuffleCommand(), "sh"); CommandRegistry.registerCommand("reshuffle", new ReshuffleCommand(), "resh"); CommandRegistry.registerCommand("repeat", new RepeatCommand(), "rep"); CommandRegistry.registerCommand("volume", new VolumeCommand(), "vol"); - CommandRegistry.registerCommand("restart", new RestartCommand()); + CommandRegistry.registerCommand("unpause", new UnpauseCommand(), "unp", "resume"); + CommandRegistry.registerCommand("split", new PlaySplitCommand()); + CommandRegistry.registerCommand("destroy", new DestroyCommand()); + + /* Info */ + CommandRegistry.registerCommand("nowplaying", new NowplayingCommand(), "np"); + CommandRegistry.registerCommand("list", new ListCommand(), "queue", "q"); CommandRegistry.registerCommand("export", new ExportCommand(), "ex"); + CommandRegistry.registerCommand("gr", new GensokyoRadioCommand(), "gensokyo", "gensokyoradio"); + CommandRegistry.registerCommand("muserinfo", new UserInfoCommand()); + + /* Seeking */ + CommandRegistry.registerCommand("seek", new SeekCommand()); + CommandRegistry.registerCommand("forward", new ForwardCommand(), "fwd"); + CommandRegistry.registerCommand("rewind", new RewindCommand(), "rew"); + CommandRegistry.registerCommand("restart", new RestartCommand()); + + /* Bot Maintenance Commands */ + CommandRegistry.registerCommand("mgitinfo", new GitInfoCommand(), "mgit"); + CommandRegistry.registerCommand("munblacklist", new UnblacklistCommand(), "munlimit"); + CommandRegistry.registerCommand("mexit", new ExitCommand()); + CommandRegistry.registerCommand("mbotrestart", new BotRestartCommand()); + CommandRegistry.registerCommand("mstats", new StatsCommand()); + CommandRegistry.registerCommand("meval", new EvalCommand()); + CommandRegistry.registerCommand("mupdate", new UpdateCommand()); + CommandRegistry.registerCommand("mcompile", new CompileCommand()); + CommandRegistry.registerCommand("mmvntest", new MavenTestCommand()); + CommandRegistry.registerCommand("getid", new GetIdCommand()); CommandRegistry.registerCommand("playerdebug", new PlayerDebugCommand()); - CommandRegistry.registerCommand("music", new MusicHelpCommand(), "musichelp"); - CommandRegistry.registerCommand("commands", new CommandsCommand(), "comms", "cmds"); CommandRegistry.registerCommand("nodes", new NodesCommand()); - CommandRegistry.registerCommand("gr", new GensokyoRadioCommand(), "gensokyo", "gensokyoradio"); CommandRegistry.registerCommand("mshards", new ShardsCommand()); - CommandRegistry.registerCommand("split", new PlaySplitCommand()); - CommandRegistry.registerCommand("config", new ConfigCommand(), "cfg"); - CommandRegistry.registerCommand("lang", new LanguageCommand(), "language"); CommandRegistry.registerCommand("mrevive", new ReviveCommand()); CommandRegistry.registerCommand("adebug", new AudioDebugCommand()); CommandRegistry.registerCommand("announce", new AnnounceCommand()); - CommandRegistry.registerCommand("destroy", new DestroyCommand()); - - CommandRegistry.registerCommand("seek", new SeekCommand()); - CommandRegistry.registerCommand("forward", new ForwardCommand(), "fwd"); - CommandRegistry.registerCommand("rewind", new RewindCommand(), "rew"); - + CommandRegistry.registerCommand("mping", new PingCommand()); + + /* Bot configuration */ + CommandRegistry.registerCommand("config", new ConfigCommand(), "cfg"); + CommandRegistry.registerCommand("lang", new LanguageCommand(), "language"); + + /* Perms */ CommandRegistry.registerCommand("admin", new PermissionsCommand(PermissionLevel.ADMIN)); CommandRegistry.registerCommand("dj", new PermissionsCommand(PermissionLevel.DJ)); CommandRegistry.registerCommand("user", new PermissionsCommand(PermissionLevel.USER)); diff --git a/FredBoat/src/main/java/fredboat/db/DatabaseManager.java b/FredBoat/src/main/java/fredboat/db/DatabaseManager.java index 5a3b743f7..1c2434f4b 100644 --- a/FredBoat/src/main/java/fredboat/db/DatabaseManager.java +++ b/FredBoat/src/main/java/fredboat/db/DatabaseManager.java @@ -92,6 +92,8 @@ public synchronized void startup() { properties.put("hibernate.connection.provider_class", "org.hibernate.hikaricp.internal.HikariCPConnectionProvider"); properties.put("hibernate.connection.url", jdbcUrl); if (dialect != null && !"".equals(dialect)) properties.put("hibernate.dialect", dialect); + properties.put("hibernate.cache.use_second_level_cache", "true"); + properties.put("hibernate.cache.provider_configuration_file_resource_path", "ehcache.xml"); properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory"); //this does a lot of logs @@ -296,4 +298,4 @@ public void log(int level, String message) { } } -} \ No newline at end of file +} diff --git a/FredBoat/src/main/java/fredboat/db/entity/GuildPermissions.java b/FredBoat/src/main/java/fredboat/db/entity/GuildPermissions.java index eeb219731..0d08ad9ab 100644 --- a/FredBoat/src/main/java/fredboat/db/entity/GuildPermissions.java +++ b/FredBoat/src/main/java/fredboat/db/entity/GuildPermissions.java @@ -26,6 +26,8 @@ package fredboat.db.entity; import fredboat.perms.PermissionLevel; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; import javax.persistence.Column; import javax.persistence.Entity; @@ -37,6 +39,7 @@ @Entity @Table(name = "guild_permissions") +@Cache(usage= CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region="guild_permissions") public class GuildPermissions implements IEntity { // Guild ID diff --git a/FredBoat/src/main/java/fredboat/feature/togglz/FeatureFlags.java b/FredBoat/src/main/java/fredboat/feature/togglz/FeatureFlags.java index bec3b42a5..2da93d348 100644 --- a/FredBoat/src/main/java/fredboat/feature/togglz/FeatureFlags.java +++ b/FredBoat/src/main/java/fredboat/feature/togglz/FeatureFlags.java @@ -44,7 +44,16 @@ public enum FeatureFlags implements Feature { //using the chatbot class @Label("Chatbot") @EnabledByDefault - CHATBOT; + CHATBOT, + + @Label("Permissions") + @EnabledByDefault + PERMISSIONS, + + //using data methods that don't collect everything to new data structures + @Label("Streaming data methods") + @EnabledByDefault + DATA_METHODS; public boolean isActive() { return FeatureConfig.getTheFeatureManager().isActive(this); diff --git a/FredBoat/src/main/java/fredboat/perms/PermsUtil.java b/FredBoat/src/main/java/fredboat/perms/PermsUtil.java index 276aca72b..e88db44de 100644 --- a/FredBoat/src/main/java/fredboat/perms/PermsUtil.java +++ b/FredBoat/src/main/java/fredboat/perms/PermsUtil.java @@ -28,6 +28,7 @@ import fredboat.Config; import fredboat.db.EntityReader; import fredboat.db.entity.GuildPermissions; +import fredboat.feature.togglz.FeatureFlags; import fredboat.util.DiscordUtil; import fredboat.util.TextUtils; import net.dv8tion.jda.core.Permission; @@ -51,6 +52,10 @@ public static PermissionLevel getPerms(Member member) { return PermissionLevel.ADMIN; } + if (!FeatureFlags.PERMISSIONS.isActive()) { + return PermissionUtil.checkPermission(member, Permission.MESSAGE_MANAGE) ? PermissionLevel.DJ : PermissionLevel.USER; + } + GuildPermissions gp = EntityReader.getGuildPermissions(member.getGuild()); if (checkList(gp.getAdminList(), member)) return PermissionLevel.ADMIN; diff --git a/FredBoat/src/main/java/fredboat/util/DiscordUtil.java b/FredBoat/src/main/java/fredboat/util/DiscordUtil.java index ed5f100cd..03d07ae90 100644 --- a/FredBoat/src/main/java/fredboat/util/DiscordUtil.java +++ b/FredBoat/src/main/java/fredboat/util/DiscordUtil.java @@ -28,24 +28,19 @@ import com.mashape.unirest.http.Unirest; import com.mashape.unirest.http.exceptions.UnirestException; import fredboat.Config; -import fredboat.util.constant.BotConstants; +import fredboat.feature.I18n; +import fredboat.shared.constant.BotConstants; import net.dv8tion.jda.core.JDA; import net.dv8tion.jda.core.OnlineStatus; -import net.dv8tion.jda.core.entities.Guild; -import net.dv8tion.jda.core.entities.Member; -import net.dv8tion.jda.core.entities.Message; -import net.dv8tion.jda.core.entities.Role; -import net.dv8tion.jda.core.entities.User; +import net.dv8tion.jda.core.entities.*; import net.dv8tion.jda.core.exceptions.RateLimitedException; -import net.dv8tion.jda.core.requests.Request; -import net.dv8tion.jda.core.requests.Requester; -import net.dv8tion.jda.core.requests.Response; -import net.dv8tion.jda.core.requests.RestAction; -import net.dv8tion.jda.core.requests.Route; +import net.dv8tion.jda.core.requests.*; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.text.MessageFormat; +import java.util.Arrays; import java.util.List; public class DiscordUtil { @@ -185,4 +180,21 @@ public static JSONObject getApplicationInfo(String token) throws UnirestExceptio .getObject(); } + // ########## Moderation related helper functions + public static String getReasonForModAction(String[] commandArgs, Guild guild) { + String r = null; + if (commandArgs.length > 2) { + r = String.join(" ", Arrays.copyOfRange(commandArgs, 2, commandArgs.length)); + } + + return I18n.get(guild).getString("modReason") + ": " + (r != null ? r : "No reason provided."); + } + + public static String formatReasonForAuditLog(String plainReason, Guild guild, Member invoker) { + String i18nAuditLogMessage = MessageFormat.format(I18n.get(guild).getString("modAuditLogMessage"), + invoker.getEffectiveName(), invoker.getUser().getDiscriminator(), invoker.getUser().getId()) + ", "; + int auditLogMaxLength = 512 - i18nAuditLogMessage.length(); //512 is a hard limit by discord + return i18nAuditLogMessage + (plainReason.length() > auditLogMaxLength ? + plainReason.substring(0, auditLogMaxLength) : plainReason); + } } diff --git a/FredBoat/src/main/java/fredboat/util/JDAUtil.java b/FredBoat/src/main/java/fredboat/util/JDAUtil.java new file mode 100644 index 000000000..d9de40905 --- /dev/null +++ b/FredBoat/src/main/java/fredboat/util/JDAUtil.java @@ -0,0 +1,146 @@ +/* + * MIT License + * + * Copyright (c) 2017 Frederik Ar. Mikkelsen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +package fredboat.util; + +import fredboat.FredBoat; +import fredboat.feature.togglz.FeatureFlags; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import net.dv8tion.jda.core.entities.Guild; +import net.dv8tion.jda.core.entities.ISnowflake; +import net.dv8tion.jda.core.entities.impl.JDAImpl; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * JDA methods/hacks that had merit to put in its own class. + * + * @author Shredder121 + */ +public class JDAUtil { + + + public static int countAllGuilds(List shards) { + if (FeatureFlags.DATA_METHODS.isActive()) { + return New.countAllGuilds(shards); + } else { + return Old.countAllGuilds(shards); + } + } + + public static long countAllUniqueUsers(List shards, AtomicInteger biggestUserCount) { + if (FeatureFlags.DATA_METHODS.isActive()) { + return New.countAllUniqueUsers(shards, biggestUserCount); + } else { + return Old.countAllUniqueUsers(shards, biggestUserCount); + } + } + public static List getAllGuilds(List shards) { + if (FeatureFlags.DATA_METHODS.isActive()) { + return New.getAllGuilds(shards); + } else { + return Old.getAllGuilds(shards); + } + } + + + + private static class New { + + public static int countAllGuilds(List shards) { + return shards.stream() + // don't do this at home, we only use it for the size() + .mapToInt(shard -> ((JDAImpl) shard.getJda()).getGuildMap().size()) + .sum(); + } + + public static long countAllUniqueUsers(List shards, AtomicInteger biggestUserCount) { + int expected = biggestUserCount.get() > 0 ? biggestUserCount.get() : LongOpenHashSet.DEFAULT_INITIAL_SIZE; + LongOpenHashSet uniqueUsers = new LongOpenHashSet(expected + 100000); //add 100k for good measure + Collections.unmodifiableCollection(shards).forEach( + // IMPLEMENTATION NOTE: READ + // careful, touching the map is in not all cases safe + // In this case, it just so happens to be safe, because the map is synchronized + // this means however, that for the (small) duration, the map cannot be used by other threads (if there are any) + shard -> ((JDAImpl) shard.getJda()).getUserMap().forEachValue(user -> { + uniqueUsers.add(user.getIdLong()); + return true; + }) + ); + //never shrink the user count (might happen due to not connected shards) + biggestUserCount.accumulateAndGet(uniqueUsers.size(), Math::max); + return uniqueUsers.size(); + } + + public static List getAllGuilds(List shards) { + ArrayList list = new ArrayList<>(); + + for (FredBoat fb : shards) { + // addAll() does actually need to use .toArray() but 1 copy is better than 2 + list.addAll(((JDAImpl)fb.getJda()).getGuildMap().valueCollection()); + } + + return list; + } + + private New() { + } + } + private static final class Old { + + public static int countAllGuilds(List shards) { + return Collections.unmodifiableCollection(shards) + .stream() + .mapToInt(shard -> shard.getJda().getGuilds().size()) + .sum(); + } + + public static long countAllUniqueUsers(List shards, AtomicInteger biggestUserCount) { + int expected = biggestUserCount.get() > 0 ? biggestUserCount.get() : LongOpenHashSet.DEFAULT_INITIAL_SIZE; + LongOpenHashSet uniqueUsers = new LongOpenHashSet(expected + 100000); //add 100k for good measure + Collections.unmodifiableCollection(shards).forEach( + shard -> shard.getJda().getUsers().parallelStream().mapToLong(ISnowflake::getIdLong).forEach(uniqueUsers::add) + ); + //never shrink the user count (might happen due to not connected shards) + biggestUserCount.accumulateAndGet(uniqueUsers.size(), Math::max); + return uniqueUsers.size(); + } + + public static List getAllGuilds(List shards) { + ArrayList list = new ArrayList<>(); + + for (FredBoat fb : shards) { + list.addAll(fb.getJda().getGuilds()); + } + + return list; + } + + private Old() { + } + } +} diff --git a/FredBoat/src/main/resources/lang b/FredBoat/src/main/resources/lang index 1c64b5684..7816988fb 160000 --- a/FredBoat/src/main/resources/lang +++ b/FredBoat/src/main/resources/lang @@ -1 +1 @@ -Subproject commit 1c64b5684d0372d47afec346d3e80d7598d0af40 +Subproject commit 7816988fbd744ed42fb2bd284f6427268d566dbe diff --git a/FredBoat/src/test/java/fredboat/ProvideJDASingleton.java b/FredBoat/src/test/java/fredboat/ProvideJDASingleton.java index 9eeec6638..99010a501 100644 --- a/FredBoat/src/test/java/fredboat/ProvideJDASingleton.java +++ b/FredBoat/src/test/java/fredboat/ProvideJDASingleton.java @@ -1,6 +1,6 @@ package fredboat; -import fredboat.util.constant.BotConstants; +import fredboat.shared.constant.BotConstants; import fredboat.util.TextUtils; import net.dv8tion.jda.core.AccountType; import net.dv8tion.jda.core.EmbedBuilder; diff --git a/README.md b/README.md index 80263af8e..0975a5403 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ FredBoat is licensed under the MIT license, so feel free to copy small or large [![Join FredBoat Hangout](https://discordapp.com/api/guilds/174820236481134592/embed.png?style=banner2)](https://discord.gg/cgPFW4q) ## Documentation -Help can be found at https://frederikam.github.io/FredBoat/ +Help can be found at https://docs.fredboat.com/ For installation instructions, go to http://docs.fredboat.com/selfhosting diff --git a/Shared/pom.xml b/Shared/pom.xml new file mode 100644 index 000000000..911d791d9 --- /dev/null +++ b/Shared/pom.xml @@ -0,0 +1,47 @@ + + + + + + fredboat + FredBoat-Root + 1.0 + + + 4.0.0 + Shared + 1.0 + + + + org.json + json + 20170516 + + + \ No newline at end of file diff --git a/FredBoat/src/main/java/fredboat/util/constant/BotConstants.java b/Shared/src/main/java/fredboat/shared/constant/BotConstants.java similarity index 97% rename from FredBoat/src/main/java/fredboat/util/constant/BotConstants.java rename to Shared/src/main/java/fredboat/shared/constant/BotConstants.java index 8a1e1bc18..54a8ae3bd 100644 --- a/FredBoat/src/main/java/fredboat/util/constant/BotConstants.java +++ b/Shared/src/main/java/fredboat/shared/constant/BotConstants.java @@ -23,7 +23,7 @@ * */ -package fredboat.util.constant; +package fredboat.shared.constant; import java.awt.*; diff --git a/FredBoat/src/main/java/fredboat/util/constant/DistributionEnum.java b/Shared/src/main/java/fredboat/shared/constant/DistributionEnum.java similarity index 97% rename from FredBoat/src/main/java/fredboat/util/constant/DistributionEnum.java rename to Shared/src/main/java/fredboat/shared/constant/DistributionEnum.java index acbc684d0..f2b803186 100644 --- a/FredBoat/src/main/java/fredboat/util/constant/DistributionEnum.java +++ b/Shared/src/main/java/fredboat/shared/constant/DistributionEnum.java @@ -23,7 +23,7 @@ * */ -package fredboat.util.constant; +package fredboat.shared.constant; public enum DistributionEnum { MAIN("production", false), diff --git a/FredBoat/src/main/java/fredboat/util/constant/ExitCodes.java b/Shared/src/main/java/fredboat/shared/constant/ExitCodes.java similarity index 97% rename from FredBoat/src/main/java/fredboat/util/constant/ExitCodes.java rename to Shared/src/main/java/fredboat/shared/constant/ExitCodes.java index 4a7dffb59..100833eee 100644 --- a/FredBoat/src/main/java/fredboat/util/constant/ExitCodes.java +++ b/Shared/src/main/java/fredboat/shared/constant/ExitCodes.java @@ -23,7 +23,7 @@ * */ -package fredboat.util.constant; +package fredboat.shared.constant; public class ExitCodes { diff --git a/pom.xml b/pom.xml index 455496d6e..7b56b6393 100644 --- a/pom.xml +++ b/pom.xml @@ -24,15 +24,68 @@ ~ --> - + 4.0.0 fredboat - 1.0 FredBoat-Root + 1.0 pom FredBoat FredBoat-Bootloader + Shared - \ No newline at end of file + + + UTF-8 + 1.8 + 1.8 + + + + + jcenter + jcenter-bintray + http://jcenter.bintray.com + + + + false + + bintray-frederikam-JCA + bintray + http://dl.bintray.com/frederikam/JCA + + + sedmelluq + sedmelluq + http://maven.sedmelluq.com/ + + + jitpack.io + https://jitpack.io + + + + + + + + maven-clean-plugin + 3.0.0 + + + auto-clean + initialize + + clean + + + + + + +