From d915d1c2ea3a486c87b12821feec49694f21ba63 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 26 May 2019 01:24:51 -0400 Subject: [PATCH 1/7] +Added command injection from plugins --- src/dataStructures/UserInput.java | 9 +++++++++ src/main/Main.java | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/dataStructures/UserInput.java b/src/dataStructures/UserInput.java index 21fa03a..00e950c 100644 --- a/src/dataStructures/UserInput.java +++ b/src/dataStructures/UserInput.java @@ -60,6 +60,15 @@ public class UserInput isValid = false; } } + + //Used for injecting direct commands from plugins + public UserInput(String input, KittyGuild contextGuild) + { + int loc = FindFirstWhitespace(input); + key = input.substring(0, loc); + args = input.substring(loc); + isValid = true; + } public boolean IsValid() { diff --git a/src/main/Main.java b/src/main/Main.java index 8be398f..45deee6 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -91,8 +91,18 @@ public class Main extends ListenerAdapter if(pluginOutput != null && pluginOutput.size() > 0) { - for(int i = 0; i < pluginOutput.size(); ++i) - response.Call(pluginOutput.get(i)); + for(int i = 0; i < pluginOutput.size(); ++i) + { + if(pluginOutput.get(i).startsWith("!")) + { + commandManager.InvokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response); + } + else + { + response.Call(pluginOutput.get(i)); + } + } + } } From 99bd35611e813f630e791fa4fcd161f21c49ae25 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 27 May 2019 15:22:06 -0400 Subject: [PATCH 2/7] +Added raffling system --- commands.config | 3 + locCommands.config | 49 ++++---- locStrings.config | 169 +++++++++++++++------------ src/commands/CommandRaffleEnd.java | 32 +++++ src/commands/CommandRaffleJoin.java | 32 +++++ src/commands/CommandRaffleSpin.java | 32 +++++ src/commands/CommandRaffleStart.java | 42 +++++++ src/core/ObjectBuilderFactory.java | 3 + src/dataStructures/KittyGuild.java | 57 +++++++++ 9 files changed, 322 insertions(+), 97 deletions(-) create mode 100644 src/commands/CommandRaffleEnd.java create mode 100644 src/commands/CommandRaffleJoin.java create mode 100644 src/commands/CommandRaffleSpin.java create mode 100644 src/commands/CommandRaffleStart.java diff --git a/commands.config b/commands.config index db12800..27dd88f 100644 --- a/commands.config +++ b/commands.config @@ -29,6 +29,9 @@ map=1 perish, thenperish=1 ping=1 poll=1 +rafflejoin=1 +rafflespin=1 +rafflestart=1 rating=1 results=1 role=1 diff --git a/locCommands.config b/locCommands.config index 5ef2ec1..36e3e71 100644 --- a/locCommands.config +++ b/locCommands.config @@ -1,50 +1,53 @@ [ObjectBuilderFactory] indicator= -boop= -tony, stark, dontfeelgood, dontfeelsogood= yeet= -role= guildroleremove= -ping= bethistory= benchmark, bench= rating= -roll= -blur= -choose= poll= -rpstart= -guildrolenotallowed= +rafflespin= bet= -perish, thenperish= -teey= guildrolelist= stats= -dbstats= -beans= -eightball, 8ball= catch= guildroleadd= -vote= results= wolfram= -map= -info, about= givebeans= c++, g++, cplus, cpp= work= -showpoll= rpend= +java, jdoodle= +rafflejoin= +guildroleallowed= +buildHelp= +dbflush= +shutdown= +boop= +tony, stark, dontfeelgood, dontfeelsogood= +role= +ping= +roll= +blur= +choose= +rpstart= +guildrolenotallowed= +perish, thenperish= +teey= +dbstats= +rafflestart= +beans= +eightball, 8ball= +vote= +map= +info, about= +showpoll= rpg= tweet= -java, jdoodle= -guildroleallowed= help= -buildHelp= fetch= crouton= invite= -dbflush= -shutdown= diff --git a/locStrings.config b/locStrings.config index 23c4205..7d69929 100644 --- a/locStrings.config +++ b/locStrings.config @@ -17,20 +17,11 @@ BetHistoryInfo=Sees the amount of beans Kitty has earned through your bets! [CommandCatch] CatchInfo=Play catch with yourself or with a friend with @! -[CommandBeansShow] -BeansShowDisplay=You have %s beans! -BeansShowMentioned=I looked it up and %sbeans! -BeansShowInfo=Displays how many beans you have - [CommandGuildRoleList] GuildRoleListOutput=The allowed roles are %s! GuildRoleListEmpty=There are no roles allowed! GuildRoleListInfo=Outputs a list of the roles you are allowed to add to yourself! -[CommandHelp] -HelpInfo=Lets you look up specific commands, or get a link to a list of all commands. -HelpDisplay=You can get help with a specific command by typing `!help command`!\nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` - [CommandRoll] RollError=Didn't work ;3; RollInfo=Based on input of xdy where x is number of dice and y is faces kitty will roll that amount of dice, display the individual rolls and total @@ -43,16 +34,6 @@ GuildRoleAllowedDuplicate=Can't add the same role twice! [CommandStats] StatsInfo=Displays the actively running KittyBot application information -[CommandTweet] -TweetInfo=Kitty will tweet to her personal twitter account -TweetError=Tweet command failed! - -[CommandGuildRoleAdd] -GuildRoleAddSuccess=Added %s to %s -GuildRoleAddFailure=Failed to add %s to %s -GuildRoleAddNotAllowed=You are not allowed to add %s! -GuildRoleAddInfo=Add a role to yourself! - [CommandRole] RoleInfo=Will show the current role you have, Admins can change others roles with input of 'role x @y' with x being blacklist, general, mod, or admin. Blacklist will not allow the user to interact with kitty anymore, general mod and admin will give the user access to those commands. RoleStandardResponse=Your role is %s @@ -60,10 +41,6 @@ RoleError=You aren't allowed to do that! You must have the KittyRole '%s' or hig RoleChanged=Changed %s to role `%s`! RoleNeededRole=Please enter `general`, `mod`, or `admin`! -[CommandColiru] -ColiruError=Please provide some c++ code to attempt to compile! -ColiruInfo=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. - [CommandJDoodle] JDoodleInfo=Will compile any java code you put in! Supports Java 1.8 JDoodleError=Please provide some java code to get it compiled! @@ -76,12 +53,6 @@ ChangeIndicatorChanged=Indicator changed to `%s` [CommandPerish] PerishInfo=Adds a red, 'a n g e r y' overlay to your icon or the icon of a friend you mentioned -[CommandStark] -StarkInfo=Snaps your icon or the icon of a friend you mentioned - -[CommandYeet] -YeetInfo=Yeet yourself or yeet a friend with @! - [CommandTradeBeans] TradeBeanseStealingBeans=Stealing is wrong! *Steals 10 beans from %s* TradeBeansNoTargetError=You have to give *someone* your beans! @@ -104,19 +75,15 @@ ShutdownSafe=Shutting down, but first syncing database and finishing current thr ShutdownUnsafe=Shutting down and immediately and abandoning all threads without sync. ShutdownInfo=Stops kitty. `-s` or `safe` as an argument attempts to sync off the database before shutdown. -[CommandCrouton] -CroutonInfo=Crouton +[CommandRaffleSpin] +RaffleSpinInfo= +RaffleSpinSuccess=The winner issssssss %s! +RaffleSpinFailure=I can't choose a winner D: -[CommandTeey] -TeeyInfo=Teey yourself back into existance, or teey a friend with @! - -[CommandBetBeans] -BetBeansLowBet=Please bet with at least 50 beans! -BetBeansInfo=Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x -BetBeansNotValid=That's not a valid bet! -BetBeansLose=Sorry, you didn't win, try again! -BetBeansNotEnough=You don't have enough beans! -BetBeansWin=You won %s beans! +[CommandRaffleEnd] +RaffleEndSuccess= +RaffleEndInfo= +RaffleEndFailure=I don't think there's one going! [CommandDoWork] DoWorkFinished=I finished with my work! :D @@ -128,10 +95,6 @@ RPStartInfo=Starts an rp, add people to it by mentioning them! [CommandBlurry] BlurryInfo=Blurs your icon or the icon of a friend you mentioned -[CommandPollResults] -PollResultsResponse=%s people voted for %s `%s` with `%s%` !\n -PollResultsInfo=Will show current results of a poll and percentages of votes per choice - [CommandRating] RatingInfo='0' is fully sfw (Derpi and e621 searches are disabled), '1' is filtered (kitty auto appends a sfw tag on any searches), '2' is nsfw (any search will go through). Some other words are supported for setting filter as well. RatingWarning=Warning: NSFW may slip through, images are only based on tags on their respective sites! @@ -156,21 +119,10 @@ PollShowChoices=And the choices are:\n [CommandHelpBuilder] HelpBuilderInfo=Emit help for all commands as formatted HTML -[CommandRPEnd] -RPEndError=You can't end this RP! -RPEndInfo=Ends RP in channel and gives you a .txt file! -RPEndFileOut=Here's your file! - [CommandRPG] RPGInfo=Admin+ command only right now - experimental text RPG! Format is !rpg RPGInvalid=Invalid RPG Command! -[CommandBoop] -BoopPerson=%s booped %s! -BoopInfo=Kitty will react with a counter -BoopStandard=Woah! %s booped me! That's %s total! -BoopMultiple=%s booped several others - %s! - [CommandFetch] FetchError=That no picture! FetchEat=Me eat now *monch %s* @@ -185,6 +137,89 @@ FetchStare=*Stares at %s* InfoResponse=I'm made by `Rin#8904` and `Reverie Wisp#3703`!\nYou can find more info about me along with a Patreon link to support us and GitHub link for filing bugs https://www.rinsnowmew.com/bot/ InfoInfo=Provides author info and a link to Kitty's website +[CommandGuildRoleRemove] +GuildRoleRemoveNotAllowed=You're not allowed to add %s +GuildRoleRemoveFailure=Couldn't remove %s from %s +GuildRoleRemoveSuccess=Removed %s from %s! +GuildRoleRemoveInfo= + +[CommandWolfram] +WolframError=Something went wrong! +WolframInfo=Will query wolframalpha with your question and give a full image output of the answer +WolframNoArgs=You need to provide some arguments! + +[CommandMap] +MapInfo=Generates a map! You can pass additional information if you want with the flags `-s-w-h`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.\n\nDefault seed: Random,\nDefault Width: 35(max %s),\nDefault Height: 25(max %s) +MapSeed=Seed +MapInvalid=Invalid arguments provided! +MapVersion=Using mapgen v0.1 +MapWidth=Width +MapHeight=Height + +[CommandBeansShow] +BeansShowDisplay=You have %s beans! +BeansShowMentioned=I looked it up and %sbeans! +BeansShowInfo=Displays how many beans you have + +[CommandRaffleStart] +RaffleStartSuccess=Started a raffle with an entrance fee of %s beans! +RaffleStartFailure=There's already a raffle going! +RaffleStart= +RaffleStartInfo= + +[CommandHelp] +HelpInfo=Lets you look up specific commands, or get a link to a list of all commands. +HelpDisplay=You can get help with a specific command by typing `!help command`!\nGeneral Commands: `boop, roll, choose, help, info, vote, results, showpoll, wolfram, cplus, java, beans, role, bet, yeet` + +[CommandTweet] +TweetInfo=Kitty will tweet to her personal twitter account +TweetError=Tweet command failed! + +[CommandGuildRoleAdd] +GuildRoleAddSuccess=Added %s to %s +GuildRoleAddFailure=Failed to add %s to %s +GuildRoleAddNotAllowed=You are not allowed to add %s! +GuildRoleAddInfo=Add a role to yourself! + +[CommandColiru] +ColiruError=Please provide some c++ code to attempt to compile! +ColiruInfo=Will try to compile any c++ code you put in! Supports up to C++14 standard, uses g++. + +[CommandStark] +StarkInfo=Snaps your icon or the icon of a friend you mentioned + +[CommandYeet] +YeetInfo=Yeet yourself or yeet a friend with @! + +[CommandCrouton] +CroutonInfo=Crouton + +[CommandTeey] +TeeyInfo=Teey yourself back into existance, or teey a friend with @! + +[CommandBetBeans] +BetBeansLowBet=Please bet with at least 50 beans! +BetBeansInfo=Allows you to bet your beans, set your amount after the command! Warning! House always wins!\nSets of 3 will get 2x, 4 will get 10x, and 5 will get 1000x +BetBeansNotValid=That's not a valid bet! +BetBeansLose=Sorry, you didn't win, try again! +BetBeansNotEnough=You don't have enough beans! +BetBeansWin=You won %s beans! + +[CommandPollResults] +PollResultsResponse=%s people voted for %s `%s` with `%s%` !\n +PollResultsInfo=Will show current results of a poll and percentages of votes per choice + +[CommandRPEnd] +RPEndError=You can't end this RP! +RPEndInfo=Ends RP in channel and gives you a .txt file! +RPEndFileOut=Here's your file! + +[CommandBoop] +BoopPerson=%s booped %s! +BoopInfo=Kitty will react with a counter +BoopStandard=Woah! %s booped me! That's %s total! +BoopMultiple=%s booped several others - %s! + [CommandPing] PingResponse=Pong! PingInfo=Will respond with Pong! @@ -221,26 +256,12 @@ EightBallYes10=Signs point to yes. [CommandInvite] InviteInfo=Provides a direct invite link for KittyBot -[CommandGuildRoleRemove] -GuildRoleRemoveNotAllowed=You're not allowed to add %s -GuildRoleRemoveFailure=Couldn't remove %s from %s -GuildRoleRemoveSuccess=Removed %s from %s! -GuildRoleRemoveInfo= - -[CommandWolfram] -WolframError=Something went wrong! -WolframInfo=Will query wolframalpha with your question and give a full image output of the answer -WolframNoArgs=You need to provide some arguments! +[CommandRaffleJoin] +RaffleJoinFailure=You can't join the raffle ;3; +RaffleJoinInfo= +RaffleJoinSuccess=You joined the raffle! [CommandDBFlush] DBFlushInfo= -[CommandMap] -MapInfo=Generates a map! You can pass additional information if you want with the flags `-s-w-h`. If one of the fields isn't provided, its default will be used. Note that adjusting the width and height impacts the map outcomes.\n\nDefault seed: Random,\nDefault Width: 35(max %s),\nDefault Height: 25(max %s) -MapSeed=Seed -MapInvalid=Invalid arguments provided! -MapVersion=Using mapgen v0.1 -MapWidth=Width -MapHeight=Height - diff --git a/src/commands/CommandRaffleEnd.java b/src/commands/CommandRaffleEnd.java new file mode 100644 index 0000000..47ee4f6 --- /dev/null +++ b/src/commands/CommandRaffleEnd.java @@ -0,0 +1,32 @@ +package commands; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; + +public class CommandRaffleEnd extends Command +{ + public CommandRaffleEnd(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String HelpText() { return LocStrings.Stub("RaffleEndInfo"); } + + @Override + public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + if(guild.endRaffle()) + { + res.Call(LocStrings.Stub("RaffleEndSuccess")); + } + else + { + res.Call(LocStrings.Stub("RaffleEndFailure")); + } + } +} \ No newline at end of file diff --git a/src/commands/CommandRaffleJoin.java b/src/commands/CommandRaffleJoin.java new file mode 100644 index 0000000..a3ff7e0 --- /dev/null +++ b/src/commands/CommandRaffleJoin.java @@ -0,0 +1,32 @@ +package commands; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; + +public class CommandRaffleJoin extends Command +{ + public CommandRaffleJoin(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String HelpText() { return LocStrings.Stub("RaffleJoinInfo"); } + + @Override + public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + if(guild.joinRaffle(user)) + { + res.Call(LocStrings.Stub("RaffleJoinSuccess")); + } + else + { + res.Call(LocStrings.Stub("RaffleJoinFailure")); + } + } +} diff --git a/src/commands/CommandRaffleSpin.java b/src/commands/CommandRaffleSpin.java new file mode 100644 index 0000000..ecc1e2e --- /dev/null +++ b/src/commands/CommandRaffleSpin.java @@ -0,0 +1,32 @@ +package commands; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; + +public class CommandRaffleSpin extends Command +{ + public CommandRaffleSpin(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String HelpText() { return LocStrings.Stub("RaffleSpinInfo"); } + + @Override + public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + try + { + res.Call(String.format(LocStrings.Stub("RaffleSpinSuccess"), guild.chooseRaffleWinner().name)); + } + catch(Exception e) + { + res.Call(LocStrings.Stub("RaffleSpinFailure")); + } + } +} \ No newline at end of file diff --git a/src/commands/CommandRaffleStart.java b/src/commands/CommandRaffleStart.java new file mode 100644 index 0000000..fb2fac1 --- /dev/null +++ b/src/commands/CommandRaffleStart.java @@ -0,0 +1,42 @@ +package commands; + +import core.Command; +import core.LocStrings; +import dataStructures.KittyChannel; +import dataStructures.KittyGuild; +import dataStructures.KittyRating; +import dataStructures.KittyRole; +import dataStructures.KittyUser; +import dataStructures.Response; +import dataStructures.UserInput; + +public class CommandRaffleStart extends Command +{ + public CommandRaffleStart(KittyRole level, KittyRating rating) { super(level, rating); } + + @Override + public String HelpText() { return LocStrings.Stub("RaffleStartInfo"); } + + public int beanCost; + + @Override + public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) + { + try + { + beanCost = Integer.parseInt(input.args); + } + catch(Exception e) + { + beanCost = 100; + } + if(guild.startRaffle(beanCost)) + { + res.Call(String.format(LocStrings.Stub("RaffleStartSuccess"), beanCost)); + } + else + { + res.Call(LocStrings.Stub("RaffleStartFailure")); + } + } +} diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index 63ffa4c..92db292 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -348,6 +348,8 @@ public class ObjectBuilderFactory manager.Register(LocCommands.Stub("poll"), new CommandPollManage(KittyRole.Mod, KittyRating.Safe)); manager.Register(LocCommands.Stub("givebeans"), new CommandGiveBeans(KittyRole.Mod, KittyRating.Safe)); manager.Register(LocCommands.Stub("rpg"), new CommandRPG(KittyRole.Mod, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rafflestart"), new CommandRaffleStart(KittyRole.Mod, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rafflespin"), new CommandRaffleSpin(KittyRole.Mod, KittyRating.Safe)); // General manager.Register(LocCommands.Stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe)); @@ -382,6 +384,7 @@ public class ObjectBuilderFactory manager.Register(LocCommands.Stub("bethistory"), new CommandBetHistory(KittyRole.General, KittyRating.Safe)); manager.Register(LocCommands.Stub("crouton"), new CommandCrouton(KittyRole.General, KittyRating.Safe)); manager.Register(LocCommands.Stub("benchmark, bench"), new CommandBenchmark(KittyRole.General, KittyRating.Safe)); + manager.Register(LocCommands.Stub("rafflejoin"), new CommandRaffleJoin(KittyRole.General, KittyRating.Safe)); return manager; } diff --git a/src/dataStructures/KittyGuild.java b/src/dataStructures/KittyGuild.java index 583311a..1e0d6eb 100644 --- a/src/dataStructures/KittyGuild.java +++ b/src/dataStructures/KittyGuild.java @@ -1,6 +1,8 @@ package dataStructures; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; import core.DatabaseManager; import core.DatabaseTrackedObject; @@ -15,10 +17,13 @@ public class KittyGuild extends DatabaseTrackedObject public KittyUser guildOwner; public boolean polling; public String poll; + public boolean raffling; + public int raffleCost; public ArrayList hasVoted = new ArrayList(); public ArrayList emoji = new ArrayList(); public ArrayList choices = new ArrayList(); public AdminControl control; + public HashMap raffleUsers = new HashMap(); // Database synced info private final String roleListName = "guildRoles"; @@ -88,6 +93,58 @@ public class KittyGuild extends DatabaseTrackedObject return "Poll ended!"; } + //Raffle methods + public boolean startRaffle(int beanCost) + { + if(raffling) + { + return false; + } + raffleCost = beanCost; + raffling = true; + return true; + } + + public boolean endRaffle() + { + if(raffling) + { + raffleCost = 0; + raffling = false; + return true; + } + return false; + } + + public boolean joinRaffle(KittyUser user) + { + if(!raffleUsers.containsKey(user) && user.GetBeans() > raffleCost && raffling) + { + user.ChangeBeans(raffleCost); + raffleUsers.put(user, true); + return true; + } + return false; + } + + public KittyUser chooseRaffleWinner() + { + if(!raffleUsers.isEmpty()) + { + KittyUser chosen = (KittyUser) raffleUsers.keySet().toArray()[new Random().nextInt(raffleUsers.keySet().toArray().length)]; + for(int i = 0; i < 10; i ++) + { + if(raffleUsers.get(chosen)) + { + raffleUsers.replace(chosen, false); + return chosen; + } + } + + } + return null; + } + @Override public String Serialize() { From 3b8e8c7f01a45fa433e13eb10b15ae001f89c367 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 1 Jun 2019 23:52:06 -0400 Subject: [PATCH 3/7] =Fixed Raffling system and started char database --- commands.config | 1 + locCommands.config | 1 + src/core/ObjectBuilderFactory.java | 1 + src/dataStructures/KittyCharacter.java | 5 +++++ src/dataStructures/KittyGuild.java | 27 +++++++++++--------------- 5 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 src/dataStructures/KittyCharacter.java diff --git a/commands.config b/commands.config index 27dd88f..5b3532f 100644 --- a/commands.config +++ b/commands.config @@ -29,6 +29,7 @@ map=1 perish, thenperish=1 ping=1 poll=1 +raffleend=1 rafflejoin=1 rafflespin=1 rafflestart=1 diff --git a/locCommands.config b/locCommands.config index 36e3e71..b1e2cc7 100644 --- a/locCommands.config +++ b/locCommands.config @@ -27,6 +27,7 @@ shutdown= boop= tony, stark, dontfeelgood, dontfeelsogood= role= +raffleend= ping= roll= blur= diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index 92db292..d5fe6f0 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -350,6 +350,7 @@ public class ObjectBuilderFactory manager.Register(LocCommands.Stub("rpg"), new CommandRPG(KittyRole.Mod, KittyRating.Safe)); manager.Register(LocCommands.Stub("rafflestart"), new CommandRaffleStart(KittyRole.Mod, KittyRating.Safe)); manager.Register(LocCommands.Stub("rafflespin"), new CommandRaffleSpin(KittyRole.Mod, KittyRating.Safe)); + manager.Register(LocCommands.Stub("raffleend"), new CommandRaffleEnd(KittyRole.Mod, KittyRating.Safe)); // General manager.Register(LocCommands.Stub("fetch"), new CommandFetch(KittyRole.General, KittyRating.Safe)); diff --git a/src/dataStructures/KittyCharacter.java b/src/dataStructures/KittyCharacter.java new file mode 100644 index 0000000..0812a8a --- /dev/null +++ b/src/dataStructures/KittyCharacter.java @@ -0,0 +1,5 @@ +package dataStructures; + +public class KittyCharacter { + +} diff --git a/src/dataStructures/KittyGuild.java b/src/dataStructures/KittyGuild.java index 1e0d6eb..7331f01 100644 --- a/src/dataStructures/KittyGuild.java +++ b/src/dataStructures/KittyGuild.java @@ -1,8 +1,6 @@ package dataStructures; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Random; import core.DatabaseManager; import core.DatabaseTrackedObject; @@ -23,7 +21,8 @@ public class KittyGuild extends DatabaseTrackedObject public ArrayList emoji = new ArrayList(); public ArrayList choices = new ArrayList(); public AdminControl control; - public HashMap raffleUsers = new HashMap(); + public ArrayList raffleUsersUnchosen = new ArrayList(); + public ArrayList raffleUsersChosen = new ArrayList(); // Database synced info private final String roleListName = "guildRoles"; @@ -111,6 +110,8 @@ public class KittyGuild extends DatabaseTrackedObject { raffleCost = 0; raffling = false; + raffleUsersChosen.removeAll(raffleUsersChosen); + raffleUsersUnchosen.removeAll(raffleUsersUnchosen); return true; } return false; @@ -118,10 +119,10 @@ public class KittyGuild extends DatabaseTrackedObject public boolean joinRaffle(KittyUser user) { - if(!raffleUsers.containsKey(user) && user.GetBeans() > raffleCost && raffling) + if(!raffleUsersChosen.contains(user) && !raffleUsersUnchosen.contains(user) && user.GetBeans() > raffleCost && raffling) { user.ChangeBeans(raffleCost); - raffleUsers.put(user, true); + raffleUsersUnchosen.add(user); return true; } return false; @@ -129,18 +130,12 @@ public class KittyGuild extends DatabaseTrackedObject public KittyUser chooseRaffleWinner() { - if(!raffleUsers.isEmpty()) + if(!raffleUsersUnchosen.isEmpty()) { - KittyUser chosen = (KittyUser) raffleUsers.keySet().toArray()[new Random().nextInt(raffleUsers.keySet().toArray().length)]; - for(int i = 0; i < 10; i ++) - { - if(raffleUsers.get(chosen)) - { - raffleUsers.replace(chosen, false); - return chosen; - } - } - + KittyUser chosen = raffleUsersUnchosen.get((int) (Math.random() * raffleUsersUnchosen.size())); + raffleUsersUnchosen.remove(chosen); + raffleUsersChosen.add(chosen); + return chosen; } return null; } From 09b1e498e7fbcf3c73e81c47c9a92f1982f95460 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 1 Jun 2019 21:57:34 -0700 Subject: [PATCH 4/7] = Updated tracked stuff --- src/core/DatabaseTrackedObject.java | 17 +++++-- src/dataStructures/KittyTrackedString.java | 58 ++++++++++++++++++++++ src/dataStructures/KittyTrackedVector.java | 4 -- 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 src/dataStructures/KittyTrackedString.java diff --git a/src/core/DatabaseTrackedObject.java b/src/core/DatabaseTrackedObject.java index c149df5..2edfc91 100644 --- a/src/core/DatabaseTrackedObject.java +++ b/src/core/DatabaseTrackedObject.java @@ -4,7 +4,7 @@ package core; // have their data populated from database entries. public abstract class DatabaseTrackedObject { - private boolean isDirty; + private Boolean isDirty; public final String identifier; public DatabaseTrackedObject(String identifier) @@ -15,17 +15,26 @@ public abstract class DatabaseTrackedObject public final boolean IsDirty() { - return isDirty; + synchronized(isDirty) + { + return isDirty; + } } public final void MarkDirty() { - isDirty = true; + synchronized(isDirty) + { + isDirty = true; + } } public final void Resolve() { - isDirty = false; + synchronized(isDirty) + { + isDirty = false; + } } // Consider an object factory instead of dedicated serialization methods diff --git a/src/dataStructures/KittyTrackedString.java b/src/dataStructures/KittyTrackedString.java new file mode 100644 index 0000000..bba0559 --- /dev/null +++ b/src/dataStructures/KittyTrackedString.java @@ -0,0 +1,58 @@ +package dataStructures; + +import core.DatabaseTrackedObject; +import utils.GlobalLog; +import utils.LogFilter; + +public class KittyTrackedString extends DatabaseTrackedObject +{ + private String trackedString; // Tracked value + private final static String differentiator = "string-"; + + // Constructor with unique id and readable name + public KittyTrackedString(String readableName, String UniqueID) + { + super(differentiator + readableName + UniqueID); + } + + // Sets the value of the string and marks it as dirty + public void set(String newValue) + { + synchronized(trackedString) + { + trackedString = newValue; + MarkDirty(); + } + } + + // Returns string. The string is copied because it is immutable. + public String get() + { + synchronized(trackedString) + { + return trackedString; + } + } + + @Override + public String Serialize() + { + return trackedString; + } + + @Override + public void DeSerialzie(String string) + { + if(string != null && !string.isEmpty()) + { + trackedString = string; + } + else + { + GlobalLog.Log(LogFilter.Database, "String had null or empty value with identifier: " + identifier); + string = ""; + MarkDirty(); + } + } + +} diff --git a/src/dataStructures/KittyTrackedVector.java b/src/dataStructures/KittyTrackedVector.java index 1b80c6b..2b12714 100644 --- a/src/dataStructures/KittyTrackedVector.java +++ b/src/dataStructures/KittyTrackedVector.java @@ -5,13 +5,10 @@ import java.util.Vector; import core.DatabaseTrackedObject; -// Acts as a proxy of sorts for the allowedRole arraylist, keeping it tracked for a specific guild. -@SuppressWarnings("unused") public class KittyTrackedVector extends DatabaseTrackedObject { // Variables private Vector allowedRole = new Vector(); - private final String databaseID; // in-database ID of this value private final static String delimiter = "\n"; private final static String split = "\\n"; @@ -21,7 +18,6 @@ public class KittyTrackedVector extends DatabaseTrackedObject public KittyTrackedVector(String readableName, String UniqueID) { super(differentiator + readableName + UniqueID); - databaseID = differentiator + readableName + UniqueID; } From 355660eea4e480c59017aa8265651c49b21a05f0 Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 1 Jun 2019 22:06:28 -0700 Subject: [PATCH 5/7] = Tracked values updating --- src/dataStructures/KittyTrackedLong.java | 6 ++---- src/dataStructures/KittyTrackedString.java | 2 +- src/dataStructures/KittyTrackedVector.java | 22 +++++++++++----------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/dataStructures/KittyTrackedLong.java b/src/dataStructures/KittyTrackedLong.java index 588d64f..b584e4b 100644 --- a/src/dataStructures/KittyTrackedLong.java +++ b/src/dataStructures/KittyTrackedLong.java @@ -17,8 +17,7 @@ import utils.LogFilter; // public class KittyTrackedLong extends DatabaseTrackedObject { - private long tracked; // Tracked value - private final String databaseID; // in-database ID of this value + private long tracked; // Tracked value // Config private final static String differentiator = "long-"; @@ -26,7 +25,6 @@ public class KittyTrackedLong extends DatabaseTrackedObject public KittyTrackedLong(String readableName, String UniqueID) { super(differentiator + readableName + UniqueID); - databaseID = differentiator + readableName + UniqueID; } public long Add(long toAdd) @@ -73,7 +71,7 @@ public class KittyTrackedLong extends DatabaseTrackedObject catch(Exception e) { tracked = 0; - GlobalLog.Error(LogFilter.Core, "Falling back to default of 0 due to failure to deserialize long with database ID " + databaseID); + GlobalLog.Error(LogFilter.Core, "Falling back to default of 0 due to failure to deserialize long with database ID " + identifier); } } else diff --git a/src/dataStructures/KittyTrackedString.java b/src/dataStructures/KittyTrackedString.java index bba0559..d57d268 100644 --- a/src/dataStructures/KittyTrackedString.java +++ b/src/dataStructures/KittyTrackedString.java @@ -6,7 +6,7 @@ import utils.LogFilter; public class KittyTrackedString extends DatabaseTrackedObject { - private String trackedString; // Tracked value + private String trackedString; // Tracked value private final static String differentiator = "string-"; // Constructor with unique id and readable name diff --git a/src/dataStructures/KittyTrackedVector.java b/src/dataStructures/KittyTrackedVector.java index 2b12714..5bff03f 100644 --- a/src/dataStructures/KittyTrackedVector.java +++ b/src/dataStructures/KittyTrackedVector.java @@ -8,7 +8,7 @@ import core.DatabaseTrackedObject; public class KittyTrackedVector extends DatabaseTrackedObject { // Variables - private Vector allowedRole = new Vector(); + private Vector trackedVector = new Vector(); private final static String delimiter = "\n"; private final static String split = "\\n"; @@ -24,7 +24,7 @@ public class KittyTrackedVector extends DatabaseTrackedObject // See if the string is contined in the vector, regardless of case. public boolean containsIgnoreCase(String str) { - Iterator value = allowedRole.iterator(); + Iterator value = trackedVector.iterator(); while (value.hasNext()) { @@ -38,33 +38,33 @@ public class KittyTrackedVector extends DatabaseTrackedObject // Mirrored behavior public boolean contains(String str) { - return allowedRole.contains(str); + return trackedVector.contains(str); } public void add(String str) { - allowedRole.add(str); + trackedVector.add(str); this.MarkDirty(); } public boolean isEmpty() { - return allowedRole.isEmpty(); + return trackedVector.isEmpty(); } public int size() { - return allowedRole.size(); + return trackedVector.size(); } public String get(int index) { - return allowedRole.get(index); + return trackedVector.get(index); } public void remove(String str) { - allowedRole.remove(str); + trackedVector.remove(str); this.MarkDirty(); } @@ -74,12 +74,12 @@ public class KittyTrackedVector extends DatabaseTrackedObject { String toSerialize = ""; - for(int i = 0; i < allowedRole.size(); ++i) + for(int i = 0; i < trackedVector.size(); ++i) { if(i != 0) toSerialize += delimiter; - toSerialize += allowedRole.get(i); + toSerialize += trackedVector.get(i); } return toSerialize; @@ -96,7 +96,7 @@ public class KittyTrackedVector extends DatabaseTrackedObject String[] rolesSplit = string.split(split); for(int i = 0; i < rolesSplit.length; ++i) - allowedRole.add(rolesSplit[i]); + trackedVector.add(rolesSplit[i]); } } } From f363d15010e1955b56c0406bcb966262b1277b5c Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sat, 1 Jun 2019 23:10:46 -0700 Subject: [PATCH 6/7] + Added comments and mild formatting. --- src/core/DatabaseManager.java | 2 +- src/dataStructures/KittyTrackedString.java | 4 ++-- src/dataStructures/KittyUser.java | 14 +++++++------- src/main/Main.java | 19 +++++++++---------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/core/DatabaseManager.java b/src/core/DatabaseManager.java index 638fe2b..a8640a6 100644 --- a/src/core/DatabaseManager.java +++ b/src/core/DatabaseManager.java @@ -35,7 +35,7 @@ public class DatabaseManager if(driver.Connect() == false) { - GlobalLog.Error("Database failed to connect. Currently, without the DB, this bot can not run."); + GlobalLog.Error("A database failed to connect. Currently, without the DB, this bot can not run."); System.exit(1); } } diff --git a/src/dataStructures/KittyTrackedString.java b/src/dataStructures/KittyTrackedString.java index d57d268..f7c94bd 100644 --- a/src/dataStructures/KittyTrackedString.java +++ b/src/dataStructures/KittyTrackedString.java @@ -6,8 +6,8 @@ import utils.LogFilter; public class KittyTrackedString extends DatabaseTrackedObject { - private String trackedString; // Tracked value - private final static String differentiator = "string-"; + private String trackedString; // This is the string tracked in the database + private final static String differentiator = "string-"; // Lends a very slightly human-readable label to the database key // Constructor with unique id and readable name public KittyTrackedString(String readableName, String UniqueID) diff --git a/src/dataStructures/KittyUser.java b/src/dataStructures/KittyUser.java index 1523a8a..74e0179 100644 --- a/src/dataStructures/KittyUser.java +++ b/src/dataStructures/KittyUser.java @@ -9,13 +9,13 @@ import utils.LogFilter; // two unique user objects associated with them. public class KittyUser extends DatabaseTrackedObject { - public KittyGuild guild; - public String name; - public String uniqueID; - public String discordID; - public String avatarID; - private KittyRole role; - private long beans; + public KittyGuild guild; // The guild this user is associated with. A KittyUser can not be associated with more than one guild. + public String name; // The 'friendly name' of the user (readable name). + public String uniqueID; // The combination of the guild ID that discord uses and the user-specific ID discord uses. (A discord account has one user per server). + public String discordID; // The user-specific ID only. This is the ID associated with the discord account. + public String avatarID; // The searchable ID of the current avatar image for the user. + private KittyRole role; // The command permissions role this user has for issuing bot commands for this bot. + private long beans; // A value incremented each time a user sends a message in a server they're in. // Explicit Constructor public KittyUser(String name, KittyGuild guild, KittyRole role, String uniqueID, String avatarID, String discordID) diff --git a/src/main/Main.java b/src/main/Main.java index 45deee6..aa7608d 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -91,18 +91,17 @@ public class Main extends ListenerAdapter if(pluginOutput != null && pluginOutput.size() > 0) { - for(int i = 0; i < pluginOutput.size(); ++i) + for(int i = 0; i < pluginOutput.size(); ++i) + { + if(pluginOutput.get(i).startsWith("!")) { - if(pluginOutput.get(i).startsWith("!")) - { - commandManager.InvokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response); - } - else - { - response.Call(pluginOutput.get(i)); - } + commandManager.InvokeOnNewThread(guild, channel, user, new UserInput(pluginOutput.get(i).substring(1), guild), response); } - + else + { + response.Call(pluginOutput.get(i)); + } + } } } From 0338472d87f2cb54cedb73a1a1d10a9c5fdf29fd Mon Sep 17 00:00:00 2001 From: Matthew Cech Date: Sun, 2 Jun 2019 17:11:52 -0700 Subject: [PATCH 7/7] = Updated database to allow for multiple tables --- src/commands/CommandBoop.java | 2 +- src/commands/CommandDBFlush.java | 2 +- src/commands/CommandDBStats.java | 4 +- src/commands/CommandShutdown.java | 2 +- ...river.java => DatabaseDriverKeyValue.java} | 28 ++-- src/core/DatabaseManager.java | 149 +++++++++++++++--- src/core/ObjectBuilderFactory.java | 6 +- src/dataStructures/KittyGuild.java | 4 +- src/main/Superintendent.java | 2 +- src/network/JDBCDriverSQLite.java | 51 +++--- 10 files changed, 180 insertions(+), 70 deletions(-) rename src/core/{DatabaseDriver.java => DatabaseDriverKeyValue.java} (76%) diff --git a/src/commands/CommandBoop.java b/src/commands/CommandBoop.java index ccd0a41..6774212 100644 --- a/src/commands/CommandBoop.java +++ b/src/commands/CommandBoop.java @@ -56,7 +56,7 @@ public class CommandBoop extends Command { super(level, rating); boopTracker = new BoopTracker(); - DatabaseManager.instance.Register(boopTracker); + DatabaseManager.instance.globalRegister(boopTracker); } @Override diff --git a/src/commands/CommandDBFlush.java b/src/commands/CommandDBFlush.java index 484ac61..d0f37b8 100644 --- a/src/commands/CommandDBFlush.java +++ b/src/commands/CommandDBFlush.java @@ -24,7 +24,7 @@ public class CommandDBFlush extends Command @Override public void OnRun(KittyGuild guild, KittyChannel channel, KittyUser user, UserInput input, Response res) { - int numUpdated = DatabaseManager.instance.Upkeep(); + int numUpdated = DatabaseManager.instance.upkeep(); KittyEmbed embed = new KittyEmbed(); embed.title = "Database queue flushed"; diff --git a/src/commands/CommandDBStats.java b/src/commands/CommandDBStats.java index ae8c012..033bf34 100644 --- a/src/commands/CommandDBStats.java +++ b/src/commands/CommandDBStats.java @@ -33,9 +33,9 @@ public class CommandDBStats extends Command { KittyEmbed embed = new KittyEmbed(); embed.title = "Database Info"; - embed.descriptionText = "**Tracked Items:** " + DatabaseManager.instance.GetTrackedObjectsSize(); + embed.descriptionText = "**Tracked Items:** " + DatabaseManager.instance.getTrackedObjectsSize(); embed.descriptionText += "\n"; - embed.descriptionText += "**Last Upkeep:** " + dateFormat.format(DatabaseManager.instance.GetLastUpkeep()) + " UTC-7"; + embed.descriptionText += "**Last Upkeep:** " + dateFormat.format(DatabaseManager.instance.getLastUpkeep()) + " UTC-7"; embed.color = new Color(7*16, 8*16, 9*16); res.CallEmbed(embed); diff --git a/src/commands/CommandShutdown.java b/src/commands/CommandShutdown.java index 06eabda..57538a6 100644 --- a/src/commands/CommandShutdown.java +++ b/src/commands/CommandShutdown.java @@ -47,7 +47,7 @@ public class CommandShutdown extends Command { // Force upkeep, this works so long as upkeep is on the main thread. res.CallImmediate(LocStrings.Stub("ShutdownSafe")); - DatabaseManager.instance.Upkeep(); + DatabaseManager.instance.upkeep(); GlobalLog.Warn(LogFilter.Command, LocStrings.Lookup("ShutdownSafe")); System.exit(0); diff --git a/src/core/DatabaseDriver.java b/src/core/DatabaseDriverKeyValue.java similarity index 76% rename from src/core/DatabaseDriver.java rename to src/core/DatabaseDriverKeyValue.java index b751e32..df8032e 100644 --- a/src/core/DatabaseDriver.java +++ b/src/core/DatabaseDriverKeyValue.java @@ -13,19 +13,21 @@ import utils.LogFilter; // This is where we put everything and swap out the moving parts, // ie MySQL, PostgreSQL, SQLite, etc... // -// Right now this can be messed up with SQL injection stuff if users -// are allowed to directly touch data. Leaving it like this temporarily, -// and is for prototyping only! -public class DatabaseDriver +// This isn't overly flexible though, +public class DatabaseDriverKeyValue { // Config and local varaibles private JDBCDriver driver; - private final String globalTableName = "kitty_globals"; - private final String globalKeyName = "GlobalKey"; - private final String globalValueName = "GlobalValue"; + private final String tableName; // Table name + private final String keyColumnName; // Column name for the key + private final String valueColumnName; // Column name for the value - public DatabaseDriver() + public DatabaseDriverKeyValue(String tableName, String keyColumnName, String valueColumnName) { + this.tableName = tableName; + this.keyColumnName = keyColumnName; + this.valueColumnName = valueColumnName; + driver = null; } @@ -47,7 +49,7 @@ public class DatabaseDriver } // Verify tables we want to use exist - EnsureTableExists(globalTableName, globalKeyName, globalValueName); // General table. Do not remove. + EnsureTableExists(tableName, keyColumnName, valueColumnName); // General table. Do not remove. return true; } @@ -87,7 +89,7 @@ public class DatabaseDriver // Prototype formatting for key updating private void UpdateKey(String key, String value) { - String command = "UPDATE " + globalTableName + " SET " + globalValueName + " = ? WHERE " + globalKeyName + " = ?"; + String command = "UPDATE " + tableName + " SET " + valueColumnName + " = ? WHERE " + keyColumnName + " = ?"; boolean status = driver.ExecuteStatement(JDBCStatementType.Update, command, new String[] { value, key }); GlobalLog.Log(LogFilter.Database, "UpdateKey status: " + status); } @@ -95,7 +97,7 @@ public class DatabaseDriver // Protoype updating for seeing if a key exists private boolean HasKey(String key) { - String command = "SELECT COUNT(1) as count FROM " + globalTableName + " WHERE " + globalKeyName + " = ?"; + String command = "SELECT COUNT(1) as count FROM " + tableName + " WHERE " + keyColumnName + " = ?"; ResultSet set = driver.ExecuteReturningStatement(JDBCStatementType.Select, command, new String[] { key }); String out = ResultAsString(set, "count"); return out.charAt(0) == '1'; @@ -104,7 +106,7 @@ public class DatabaseDriver // Prototype for getting a key private String GetKey(String key) { - String command = "SELECT " + globalValueName + " as searchedKey FROM " + globalTableName +" WHERE " + globalKeyName + " = ?"; + String command = "SELECT " + valueColumnName + " as searchedKey FROM " + tableName +" WHERE " + keyColumnName + " = ?"; ResultSet set = driver.ExecuteReturningStatement(JDBCStatementType.Select, command, new String[] { key }); return ResultAsString(set, "searchedKey"); } @@ -112,7 +114,7 @@ public class DatabaseDriver // Prototype for creating a key private void CreateKey(String key, String value) { - String command = "INSERT INTO " + globalTableName + " (GlobalKey, GlobalValue) VALUES (?, ?)"; + String command = "INSERT INTO " + tableName + " (GlobalKey, GlobalValue) VALUES (?, ?)"; boolean status = driver.ExecuteStatement(JDBCStatementType.Insert, command, new String[] { key, value }); GlobalLog.Log(LogFilter.Database, "CreateKey status: " + status); } diff --git a/src/core/DatabaseManager.java b/src/core/DatabaseManager.java index a8640a6..c4a12c1 100644 --- a/src/core/DatabaseManager.java +++ b/src/core/DatabaseManager.java @@ -5,16 +5,33 @@ import java.util.Vector; import utils.GlobalLog; import utils.LogFilter; +// This wrangles all of the differentiated storage systems. Internally, these may be tables, +// different databases, etc -- the goal is that it's abstracted away. +// +// TODO: Implement intermediate structure on account of duplicate patterns showing up. public class DatabaseManager { // Singleton accessor public static DatabaseManager instance = null; + // Database names and configs + private final String globalTableName = "kitty_globals"; // Table name + private final String globalKeyColumnName = "GlobalKey"; // Column name for the key + private final String globalValueColumnName = "GlobalValue"; // Column name for the value + + private final String characterTableName = "kitty_characters"; // Table name + private final String characterKeyColumnName = "CharacterKey"; // Column name for the key + private final String characterValueColumnName = "CharacterValue"; // Column name for the value + + // Private internal variables - private Vector trackedObjects; - private DatabaseDriver driver; + private Vector globalDataTrackedObjects; + private Vector characterDataTrackedObjects; + private DatabaseDriverKeyValue globalDataDriver; + private DatabaseDriverKeyValue characterDataDriver; private Date lastUpkeep; + // Constructor to enforce singleton. public DatabaseManager() { GlobalLog.Log(LogFilter.Database, "Creating database manager"); @@ -29,75 +46,157 @@ public class DatabaseManager return; } + // Initialize variables lastUpkeep = new Date(); - trackedObjects = new Vector(); - driver = new DatabaseDriver(); + globalDataTrackedObjects = new Vector(); + characterDataTrackedObjects = new Vector(); - if(driver.Connect() == false) + // Initialize data sets + globalDataDriver = new DatabaseDriverKeyValue(globalTableName, globalKeyColumnName, globalValueColumnName); + characterDataDriver = new DatabaseDriverKeyValue(characterTableName, characterKeyColumnName, characterValueColumnName); + + // Connect data sets + if(globalDataDriver.Connect() == false) { - GlobalLog.Error("A database failed to connect. Currently, without the DB, this bot can not run."); + GlobalLog.Error("Global database failed to connect. Without this DB, this bot can not run."); + System.exit(1); + } + + if(characterDataDriver.Connect() == false) + { + GlobalLog.Error("Character database failed to connect. Without this DB, this bot can not run."); System.exit(1); } } // Thumbs through registered objects and syncs them with the database. // Consider moving this operation to a separate thread. - public int Upkeep() + public int upkeep() { - synchronized(trackedObjects) + int total = 0; + + total += globalDataUpkeep(); + total += characterDataUpkeep(); + + lastUpkeep = new Date(); + return total; + } + + // Global data management and updating, returns how many items were updated. + private int globalDataUpkeep() + { + synchronized(globalDataTrackedObjects) { int numUpdated = 0; - for(int i = 0 ; i < trackedObjects.size(); ++i) + for(int i = 0; i < globalDataTrackedObjects.size(); ++i) { - DatabaseTrackedObject dto = trackedObjects.get(i); + DatabaseTrackedObject dto = globalDataTrackedObjects.get(i); if(dto.IsDirty()) { - SetRemoteValue(dto.identifier, dto.Serialize()); + globalSetRemoteValue(dto.identifier, dto.Serialize()); dto.Resolve(); ++numUpdated; } } - lastUpkeep = new Date(); + return numUpdated; + } + } + + // Character data management and updating, returns how many items were updated. + private int characterDataUpkeep() + { + synchronized(characterDataTrackedObjects) + { + int numUpdated = 0; + + for(int i = 0; i < characterDataTrackedObjects.size(); ++i) + { + DatabaseTrackedObject dto = characterDataTrackedObjects.get(i); + + if(dto.IsDirty()) + { + characterSetRemoteValue(dto.identifier, dto.Serialize()); + dto.Resolve(); + ++numUpdated; + } + } return numUpdated; } } - public void Register(DatabaseTrackedObject tracked) + + ///////////////// + // Global Data // + ///////////////// + public void globalRegister(DatabaseTrackedObject tracked) { - synchronized(trackedObjects) + synchronized(globalDataTrackedObjects) { - trackedObjects.add(tracked); - tracked.DeSerialzie(GetRemoteValue(tracked.identifier)); + globalDataTrackedObjects.add(tracked); + tracked.DeSerialzie(globalGetRemoteValue(tracked.identifier)); } } - public String GetRemoteValue(String key) + private String globalGetRemoteValue(String key) { - synchronized(driver) + synchronized(globalDataDriver) { - return driver.CreateGetKey(key); + return globalDataDriver.CreateGetKey(key); } } - public void SetRemoteValue(String key, String value) + private void globalSetRemoteValue(String key, String value) { - synchronized(driver) + synchronized(globalDataDriver) { - driver.CreateSetKey(key, value); + globalDataDriver.CreateSetKey(key, value); } } - public Date GetLastUpkeep() + + //////////////////// + // Character Data // + //////////////////// + public void characterRegister(DatabaseTrackedObject tracked) + { + synchronized(characterDataTrackedObjects) + { + characterDataTrackedObjects.add(tracked); + tracked.DeSerialzie(characterGetRemoteValue(tracked.identifier)); + } + } + + private String characterGetRemoteValue(String key) + { + synchronized(characterDataDriver) + { + return characterDataDriver.CreateGetKey(key); + } + } + + private void characterSetRemoteValue(String key, String value) + { + synchronized(characterDataDriver) + { + characterDataDriver.CreateSetKey(key, value); + } + } + + + /////////////////////// + // Utility functions // + /////////////////////// + public Date getLastUpkeep() { return lastUpkeep; } - public int GetTrackedObjectsSize() + public int getTrackedObjectsSize() { - return trackedObjects.size(); + return globalDataTrackedObjects.size(); } } diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index d5fe6f0..ec55748 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -131,7 +131,7 @@ public class ObjectBuilderFactory { // Construct a new guild with defaults guild = new KittyGuild(uid, new AdminControl(event.getGuild()), emotesString); - DatabaseManager.instance.Register(guild); + DatabaseManager.instance.globalRegister(guild); guildCache.put(uid, guild); } } @@ -241,7 +241,7 @@ public class ObjectBuilderFactory String discordID = event.getMember().getUser().getId(); String avatarID = event.getAuthor().getAvatarUrl(); user = new KittyUser(name, guild, role, uid, avatarID, discordID); - DatabaseManager.instance.Register(user); + DatabaseManager.instance.globalRegister(user); userCache.put(uid, user); } } @@ -285,7 +285,7 @@ public class ObjectBuilderFactory KittyRole role = KittyRole.General; KittyGuild guild = guildCache.get(guildID); user = new KittyUser(name, guild, role, uid, avatarID, discordID); - DatabaseManager.instance.Register(user); + DatabaseManager.instance.globalRegister(user); userCache.put(uid, user); } } diff --git a/src/dataStructures/KittyGuild.java b/src/dataStructures/KittyGuild.java index 7331f01..b2d6868 100644 --- a/src/dataStructures/KittyGuild.java +++ b/src/dataStructures/KittyGuild.java @@ -35,8 +35,8 @@ public class KittyGuild extends DatabaseTrackedObject private void RegisterTrackedObjects() { - DatabaseManager.instance.Register(roleList); - DatabaseManager.instance.Register(beans); + DatabaseManager.instance.globalRegister(roleList); + DatabaseManager.instance.globalRegister(beans); } // Default content for a guild diff --git a/src/main/Superintendent.java b/src/main/Superintendent.java index 207a642..b7b19f4 100644 --- a/src/main/Superintendent.java +++ b/src/main/Superintendent.java @@ -92,7 +92,7 @@ public class Superintendent // Upkeep database lazily on occasion if(delayTimerCurrent.decrementAndGet() < 0) { - databaseManager.Upkeep(); + databaseManager.upkeep(); delayTimerCurrent.set(delayTimerReset); } diff --git a/src/network/JDBCDriverSQLite.java b/src/network/JDBCDriverSQLite.java index 8fc64ee..594906f 100644 --- a/src/network/JDBCDriverSQLite.java +++ b/src/network/JDBCDriverSQLite.java @@ -13,34 +13,41 @@ import utils.LogFilter; // Only to be called by the generic driver. public class JDBCDriverSQLite extends JDBCDriver { - Connection connection = null; - String databaseFolder = "db/"; - String databaseName = "catfood"; + private static Connection connection = null; + public static final String databaseFolder = "db/"; + public static final String databaseName = "catfood"; @Override public boolean Connect() - { - try + { + if(connection == null) { - { // Scope to discard file... - File f = new File(databaseFolder); - if(!f.exists() || !f.isDirectory()) - { - f.mkdir(); + try + { + { // Scope to discard file... + File f = new File(databaseFolder); + if(!f.exists() || !f.isDirectory()) + { + f.mkdir(); + } } + + // db parameters + String url = "jdbc:sqlite:" + databaseFolder + databaseName + ".db"; + + // create a connection to the database + connection = DriverManager.getConnection(url); + + GlobalLog.Log(LogFilter.Database, "Connection to SQLite has been established."); + } + catch (SQLException e) + { + GlobalLog.Error(e.getMessage()); } - - // db parameters - String url = "jdbc:sqlite:db/" + databaseName + ".db"; - - // create a connection to the database - connection = DriverManager.getConnection(url); - - GlobalLog.Log(LogFilter.Database, "Connection to SQLite has been established."); - } - catch (SQLException e) + } + else { - GlobalLog.Error(e.getMessage()); + GlobalLog.Log(LogFilter.Database, "SQLite database asked to connect a second time. This is perfectly fine as this app has all its data tied together."); } return connection != null; @@ -52,7 +59,9 @@ public class JDBCDriverSQLite extends JDBCDriver try { if (connection != null) + { connection.close(); + } return true; }