diff --git a/src/main/java/com/jagrosh/vortex/managers/BlockingSessionController.java b/src/main/java/com/jagrosh/vortex/managers/BlockingSessionController.java new file mode 100644 index 0000000..979f669 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/managers/BlockingSessionController.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.utils; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.utils.SessionControllerAdapter; +import net.dv8tion.jda.internal.utils.JDALogger; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public class BlockingSessionController extends SessionControllerAdapter +{ + private final int MAX_DELAY = 60*1000; // 1 minute + + @Override + protected void runWorker() + { + synchronized (lock) + { + if (workerHandle == null) + { + workerHandle = new BlockingQueueWorker(); + workerHandle.start(); + } + } + } + + protected class BlockingQueueWorker extends QueueWorker + { + @Override + public void run() + { + try + { + if (this.delay > 0) + { + final long interval = System.currentTimeMillis() - lastConnect; + if (interval < this.delay) + Thread.sleep(this.delay - interval); + } + } + catch (InterruptedException ex) + { + JDALogger.getLog(SessionControllerAdapter.class).error("Unable to backoff", ex); + } + while (!connectQueue.isEmpty()) + { + SessionConnectNode node = connectQueue.poll(); + try + { + node.run(connectQueue.isEmpty()); + lastConnect = System.currentTimeMillis(); + if (connectQueue.isEmpty()) + break; + if (this.delay > 0) + Thread.sleep(this.delay); + int total = 0; + while(node.getJDA().getStatus() != JDA.Status.CONNECTED + && node.getJDA().getStatus() != JDA.Status.SHUTDOWN + && total < MAX_DELAY) + { + total += 100; + Thread.sleep(100); + } + } + catch (InterruptedException e) + { + JDALogger.getLog(SessionControllerAdapter.class).error("Failed to run node", e); + appendSession(node); + } + } + synchronized (lock) + { + workerHandle = null; + if (!connectQueue.isEmpty()) + runWorker(); + } + } + } +} diff --git a/src/main/java/com/jagrosh/vortex/managers/ConditionalEventManager.java b/src/main/java/com/jagrosh/vortex/managers/ConditionalEventManager.java new file mode 100644 index 0000000..18d813c --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/managers/ConditionalEventManager.java @@ -0,0 +1,103 @@ +/* + * Copyright 2020 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.utils; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.events.GenericEvent; +import net.dv8tion.jda.api.events.user.update.GenericUserUpdateEvent; +import net.dv8tion.jda.api.hooks.InterfacedEventManager; +import net.dv8tion.jda.api.sharding.ShardManager; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public abstract class ConditionalEventManager extends InterfacedEventManager +{ + protected abstract List getOrderedShardManagers(); + + @Override + public void handle(GenericEvent ge) + { + // check if this guild is already loaded by some other shard + long selfId; + try + { + selfId = ge.getJDA().getSelfUser().getIdLong(); + } + catch ( IllegalStateException ex) // selfid not ready yet + { + return; + } + Guild guild; + try + { + guild = (Guild) ge.getClass().getMethod("getGuild").invoke(ge); + } + catch (NoSuchMethodException | InvocationTargetException ex) // no getGuild method or not in guild + { + guild = null; + } + catch (IllegalAccessException ex) // something actually went wrong + { + guild = null; + ex.printStackTrace(); + } + long guildId = guild == null ? 0 : guild.getIdLong(); + + if(guildId != 0) + { + for(ShardManager bot: getOrderedShardManagers()) + { + // if we find the account that got this event, break the loop and run the event + if(bot.getShards().get(0).getSelfUser().getIdLong() == selfId) + { + break; + } + // however, if we first encounter a different account that can see this guild, + // return and ignore the event completely + if(bot.getGuildById(guildId) != null) + { + return; + } + } + } + + // for user updates, only use the event of the first shard manager + if(ge instanceof GenericUserUpdateEvent) + { + for(ShardManager bot: getOrderedShardManagers()) + { + // if we iterate to the account that got this event, break the loop and run the event + if(bot.getShards().get(0).getSelfUser().getIdLong() == selfId) + { + break; + } + // however, if we first encounter a different account that already can see this user, + // return and ignore the event + if(bot.getUserById(((GenericUserUpdateEvent)ge).getUser().getIdLong()) != null) + { + return; + } + } + } + + // otherwise, continue as normal + super.handle(ge); + } +} diff --git a/src/main/java/com/jagrosh/vortex/managers/MultiBotManager.java b/src/main/java/com/jagrosh/vortex/managers/MultiBotManager.java new file mode 100644 index 0000000..f1dc122 --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/managers/MultiBotManager.java @@ -0,0 +1,205 @@ +/* + * Copyright 2020 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.utils; + +import java.util.*; +import java.util.stream.Collectors; +import javax.security.auth.login.LoginException; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.OnlineStatus; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder; +import net.dv8tion.jda.api.sharding.ShardManager; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import net.dv8tion.jda.api.utils.cache.CacheFlag; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public class MultiBotManager +{ + private final List bots; + + protected MultiBotManager(List builders) throws LoginException, IllegalArgumentException + { + this.bots = new ArrayList<>(); + for(DefaultShardManagerBuilder b: builders) + { + b.setEventManagerProvider(i -> new MultiBotEventManager()); + b.setBulkDeleteSplittingEnabled(false); + b.setRequestTimeoutRetry(true); + b.setSessionController(new SlowerConcurrentSessionController(20)); + bots.add(b.build()); + } + } + + public int size() + { + return bots.size(); + } + + public List getShardManagers() + { + return bots; + } + + public List getBotIds() + { + return bots.stream().map(bot -> bot.getShards().get(0).getSelfUser().getIdLong()).collect(Collectors.toList()); + } + + public RestAction retrieveUserById(long id) + { + if(!bots.isEmpty()) + return bots.get(0).retrieveUserById(id); + return null; + } + + public Guild getGuildById(long id) + { + for(ShardManager shards: bots) + if(shards.getGuildById(id) != null) + return shards.getGuildById(id); + return null; + } + + public User getUserById(long id) + { + for(ShardManager shards: bots) + if(shards.getUserById(id) != null) + return shards.getUserById(id); + return null; + } + + public TextChannel getTextChannelById(long id) + { + for(ShardManager shards: bots) + if(shards.getTextChannelById(id) != null) + return shards.getTextChannelById(id); + return null; + } + + public boolean isHighestAccount(Guild guild) + { + return getGuildById(guild.getIdLong()).getJDA().getSelfUser().getIdLong() == guild.getJDA().getSelfUser().getIdLong(); + } + + public Collection getMutualGuilds(long userId) + { + HashMap guilds = new HashMap<>(); + for(ShardManager shards: bots) + for(Guild guild: getMutualGuilds(shards, userId)) + if(!guilds.containsKey(guild.getIdLong())) + guilds.put(guild.getIdLong(), guild); + return guilds.values(); + } + + private static Collection getMutualGuilds(ShardManager shards, long userId) + { + List guilds = new ArrayList<>(); + for(JDA jda: shards.getShards()) + { + // only query the shards that are actually connected + // this prevents a problematic or loading shard from slowing down the rest of the bot + // with infinite resources, we wouldn't need to check this, but this has been a + // frequent bottleneck in the bot's startup and reconnecting lifecycle + if(jda.getStatus() == JDA.Status.CONNECTED) + { + User user = jda.getUserById(userId); + if(user != null) + guilds.addAll(jda.getMutualGuilds(user)); + } + } + return guilds; + } + + private class MultiBotEventManager extends ConditionalEventManager + { + @Override + protected List getOrderedShardManagers() + { + return bots; + } + } + + public static class MultiBotManagerBuilder + { + private final List builders = new ArrayList<>(); + + public MultiBotManagerBuilder addBot(String token, Collection intents) + { + builders.add(DefaultShardManagerBuilder.create(token, intents)); + return this; + } + + public MultiBotManagerBuilder setMemberCachePolicy(MemberCachePolicy policy) + { + builders.forEach(b -> b.setMemberCachePolicy(policy)); + return this; + } + + public MultiBotManagerBuilder enableCache(CacheFlag... flags) + { + return enableCache(Arrays.asList(flags)); + } + + public MultiBotManagerBuilder enableCache(Collection flags) + { + builders.forEach(b -> b.enableCache(flags)); + return this; + } + + public MultiBotManagerBuilder disableCache(CacheFlag... flags) + { + return disableCache(Arrays.asList(flags)); + } + + public MultiBotManagerBuilder disableCache(Collection flags) + { + builders.forEach(b -> b.disableCache(flags)); + return this; + } + + public MultiBotManagerBuilder addEventListeners(Object... listeners) + { + builders.forEach(b -> b.addEventListeners(listeners)); + return this; + } + + public MultiBotManagerBuilder setStatus(OnlineStatus status) + { + builders.forEach(b -> b.setStatus(status)); + return this; + } + + public MultiBotManagerBuilder setActivity(Activity activity) + { + builders.forEach(b -> b.setActivity(activity)); + return this; + } + + public MultiBotManager build() throws LoginException, IllegalArgumentException + { + return new MultiBotManager(builders); + } + } +} diff --git a/src/main/java/com/jagrosh/vortex/managers/SlowerConcurrentSessionController.java b/src/main/java/com/jagrosh/vortex/managers/SlowerConcurrentSessionController.java new file mode 100644 index 0000000..98f6d3e --- /dev/null +++ b/src/main/java/com/jagrosh/vortex/managers/SlowerConcurrentSessionController.java @@ -0,0 +1,46 @@ +/* + * Copyright 2021 John Grosh (john.a.grosh@gmail.com). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jagrosh.vortex.utils; + +import net.dv8tion.jda.api.utils.ConcurrentSessionController; + +/** + * + * @author John Grosh (john.a.grosh@gmail.com) + */ +public class SlowerConcurrentSessionController extends ConcurrentSessionController +{ + private final int delay; + + public SlowerConcurrentSessionController(int delay) + { + super(); + this.delay = delay; + } + + @Override + protected void runWorker() + { + synchronized (lock) + { + if (workerHandle == null) + { + workerHandle = new QueueWorker(delay); + workerHandle.start(); + } + } + } +} diff --git a/src/main/java/com/jagrosh/vortex/utils/BlockingSessionController.java b/src/main/java/com/jagrosh/vortex/utils/BlockingSessionController.java deleted file mode 100644 index 979f669..0000000 --- a/src/main/java/com/jagrosh/vortex/utils/BlockingSessionController.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018 John Grosh (john.a.grosh@gmail.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jagrosh.vortex.utils; - -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.utils.SessionControllerAdapter; -import net.dv8tion.jda.internal.utils.JDALogger; - -/** - * - * @author John Grosh (john.a.grosh@gmail.com) - */ -public class BlockingSessionController extends SessionControllerAdapter -{ - private final int MAX_DELAY = 60*1000; // 1 minute - - @Override - protected void runWorker() - { - synchronized (lock) - { - if (workerHandle == null) - { - workerHandle = new BlockingQueueWorker(); - workerHandle.start(); - } - } - } - - protected class BlockingQueueWorker extends QueueWorker - { - @Override - public void run() - { - try - { - if (this.delay > 0) - { - final long interval = System.currentTimeMillis() - lastConnect; - if (interval < this.delay) - Thread.sleep(this.delay - interval); - } - } - catch (InterruptedException ex) - { - JDALogger.getLog(SessionControllerAdapter.class).error("Unable to backoff", ex); - } - while (!connectQueue.isEmpty()) - { - SessionConnectNode node = connectQueue.poll(); - try - { - node.run(connectQueue.isEmpty()); - lastConnect = System.currentTimeMillis(); - if (connectQueue.isEmpty()) - break; - if (this.delay > 0) - Thread.sleep(this.delay); - int total = 0; - while(node.getJDA().getStatus() != JDA.Status.CONNECTED - && node.getJDA().getStatus() != JDA.Status.SHUTDOWN - && total < MAX_DELAY) - { - total += 100; - Thread.sleep(100); - } - } - catch (InterruptedException e) - { - JDALogger.getLog(SessionControllerAdapter.class).error("Failed to run node", e); - appendSession(node); - } - } - synchronized (lock) - { - workerHandle = null; - if (!connectQueue.isEmpty()) - runWorker(); - } - } - } -} diff --git a/src/main/java/com/jagrosh/vortex/utils/ConditionalEventManager.java b/src/main/java/com/jagrosh/vortex/utils/ConditionalEventManager.java deleted file mode 100644 index 18d813c..0000000 --- a/src/main/java/com/jagrosh/vortex/utils/ConditionalEventManager.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020 John Grosh (john.a.grosh@gmail.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jagrosh.vortex.utils; - -import java.lang.reflect.InvocationTargetException; -import java.util.List; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.events.GenericEvent; -import net.dv8tion.jda.api.events.user.update.GenericUserUpdateEvent; -import net.dv8tion.jda.api.hooks.InterfacedEventManager; -import net.dv8tion.jda.api.sharding.ShardManager; - -/** - * - * @author John Grosh (john.a.grosh@gmail.com) - */ -public abstract class ConditionalEventManager extends InterfacedEventManager -{ - protected abstract List getOrderedShardManagers(); - - @Override - public void handle(GenericEvent ge) - { - // check if this guild is already loaded by some other shard - long selfId; - try - { - selfId = ge.getJDA().getSelfUser().getIdLong(); - } - catch ( IllegalStateException ex) // selfid not ready yet - { - return; - } - Guild guild; - try - { - guild = (Guild) ge.getClass().getMethod("getGuild").invoke(ge); - } - catch (NoSuchMethodException | InvocationTargetException ex) // no getGuild method or not in guild - { - guild = null; - } - catch (IllegalAccessException ex) // something actually went wrong - { - guild = null; - ex.printStackTrace(); - } - long guildId = guild == null ? 0 : guild.getIdLong(); - - if(guildId != 0) - { - for(ShardManager bot: getOrderedShardManagers()) - { - // if we find the account that got this event, break the loop and run the event - if(bot.getShards().get(0).getSelfUser().getIdLong() == selfId) - { - break; - } - // however, if we first encounter a different account that can see this guild, - // return and ignore the event completely - if(bot.getGuildById(guildId) != null) - { - return; - } - } - } - - // for user updates, only use the event of the first shard manager - if(ge instanceof GenericUserUpdateEvent) - { - for(ShardManager bot: getOrderedShardManagers()) - { - // if we iterate to the account that got this event, break the loop and run the event - if(bot.getShards().get(0).getSelfUser().getIdLong() == selfId) - { - break; - } - // however, if we first encounter a different account that already can see this user, - // return and ignore the event - if(bot.getUserById(((GenericUserUpdateEvent)ge).getUser().getIdLong()) != null) - { - return; - } - } - } - - // otherwise, continue as normal - super.handle(ge); - } -} diff --git a/src/main/java/com/jagrosh/vortex/utils/MultiBotManager.java b/src/main/java/com/jagrosh/vortex/utils/MultiBotManager.java deleted file mode 100644 index f1dc122..0000000 --- a/src/main/java/com/jagrosh/vortex/utils/MultiBotManager.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2020 John Grosh (john.a.grosh@gmail.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jagrosh.vortex.utils; - -import java.util.*; -import java.util.stream.Collectors; -import javax.security.auth.login.LoginException; -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.OnlineStatus; -import net.dv8tion.jda.api.entities.Activity; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.requests.GatewayIntent; -import net.dv8tion.jda.api.requests.RestAction; -import net.dv8tion.jda.api.sharding.DefaultShardManagerBuilder; -import net.dv8tion.jda.api.sharding.ShardManager; -import net.dv8tion.jda.api.utils.MemberCachePolicy; -import net.dv8tion.jda.api.utils.cache.CacheFlag; - -/** - * - * @author John Grosh (john.a.grosh@gmail.com) - */ -public class MultiBotManager -{ - private final List bots; - - protected MultiBotManager(List builders) throws LoginException, IllegalArgumentException - { - this.bots = new ArrayList<>(); - for(DefaultShardManagerBuilder b: builders) - { - b.setEventManagerProvider(i -> new MultiBotEventManager()); - b.setBulkDeleteSplittingEnabled(false); - b.setRequestTimeoutRetry(true); - b.setSessionController(new SlowerConcurrentSessionController(20)); - bots.add(b.build()); - } - } - - public int size() - { - return bots.size(); - } - - public List getShardManagers() - { - return bots; - } - - public List getBotIds() - { - return bots.stream().map(bot -> bot.getShards().get(0).getSelfUser().getIdLong()).collect(Collectors.toList()); - } - - public RestAction retrieveUserById(long id) - { - if(!bots.isEmpty()) - return bots.get(0).retrieveUserById(id); - return null; - } - - public Guild getGuildById(long id) - { - for(ShardManager shards: bots) - if(shards.getGuildById(id) != null) - return shards.getGuildById(id); - return null; - } - - public User getUserById(long id) - { - for(ShardManager shards: bots) - if(shards.getUserById(id) != null) - return shards.getUserById(id); - return null; - } - - public TextChannel getTextChannelById(long id) - { - for(ShardManager shards: bots) - if(shards.getTextChannelById(id) != null) - return shards.getTextChannelById(id); - return null; - } - - public boolean isHighestAccount(Guild guild) - { - return getGuildById(guild.getIdLong()).getJDA().getSelfUser().getIdLong() == guild.getJDA().getSelfUser().getIdLong(); - } - - public Collection getMutualGuilds(long userId) - { - HashMap guilds = new HashMap<>(); - for(ShardManager shards: bots) - for(Guild guild: getMutualGuilds(shards, userId)) - if(!guilds.containsKey(guild.getIdLong())) - guilds.put(guild.getIdLong(), guild); - return guilds.values(); - } - - private static Collection getMutualGuilds(ShardManager shards, long userId) - { - List guilds = new ArrayList<>(); - for(JDA jda: shards.getShards()) - { - // only query the shards that are actually connected - // this prevents a problematic or loading shard from slowing down the rest of the bot - // with infinite resources, we wouldn't need to check this, but this has been a - // frequent bottleneck in the bot's startup and reconnecting lifecycle - if(jda.getStatus() == JDA.Status.CONNECTED) - { - User user = jda.getUserById(userId); - if(user != null) - guilds.addAll(jda.getMutualGuilds(user)); - } - } - return guilds; - } - - private class MultiBotEventManager extends ConditionalEventManager - { - @Override - protected List getOrderedShardManagers() - { - return bots; - } - } - - public static class MultiBotManagerBuilder - { - private final List builders = new ArrayList<>(); - - public MultiBotManagerBuilder addBot(String token, Collection intents) - { - builders.add(DefaultShardManagerBuilder.create(token, intents)); - return this; - } - - public MultiBotManagerBuilder setMemberCachePolicy(MemberCachePolicy policy) - { - builders.forEach(b -> b.setMemberCachePolicy(policy)); - return this; - } - - public MultiBotManagerBuilder enableCache(CacheFlag... flags) - { - return enableCache(Arrays.asList(flags)); - } - - public MultiBotManagerBuilder enableCache(Collection flags) - { - builders.forEach(b -> b.enableCache(flags)); - return this; - } - - public MultiBotManagerBuilder disableCache(CacheFlag... flags) - { - return disableCache(Arrays.asList(flags)); - } - - public MultiBotManagerBuilder disableCache(Collection flags) - { - builders.forEach(b -> b.disableCache(flags)); - return this; - } - - public MultiBotManagerBuilder addEventListeners(Object... listeners) - { - builders.forEach(b -> b.addEventListeners(listeners)); - return this; - } - - public MultiBotManagerBuilder setStatus(OnlineStatus status) - { - builders.forEach(b -> b.setStatus(status)); - return this; - } - - public MultiBotManagerBuilder setActivity(Activity activity) - { - builders.forEach(b -> b.setActivity(activity)); - return this; - } - - public MultiBotManager build() throws LoginException, IllegalArgumentException - { - return new MultiBotManager(builders); - } - } -} diff --git a/src/main/java/com/jagrosh/vortex/utils/SlowerConcurrentSessionController.java b/src/main/java/com/jagrosh/vortex/utils/SlowerConcurrentSessionController.java deleted file mode 100644 index 98f6d3e..0000000 --- a/src/main/java/com/jagrosh/vortex/utils/SlowerConcurrentSessionController.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2021 John Grosh (john.a.grosh@gmail.com). - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jagrosh.vortex.utils; - -import net.dv8tion.jda.api.utils.ConcurrentSessionController; - -/** - * - * @author John Grosh (john.a.grosh@gmail.com) - */ -public class SlowerConcurrentSessionController extends ConcurrentSessionController -{ - private final int delay; - - public SlowerConcurrentSessionController(int delay) - { - super(); - this.delay = delay; - } - - @Override - protected void runWorker() - { - synchronized (lock) - { - if (workerHandle == null) - { - workerHandle = new QueueWorker(delay); - workerHandle.start(); - } - } - } -}