diff --git a/bot/bot.sln b/bot/bot.sln index 1851e8c..a422777 100644 --- a/bot/bot.sln +++ b/bot/bot.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bot", "bot\bot.csproj", "{1E318685-BF0A-4508-AE47-76C7442994D7}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "responses", "responses\responses.csproj", "{5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -13,6 +15,10 @@ Global {1E318685-BF0A-4508-AE47-76C7442994D7}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E318685-BF0A-4508-AE47-76C7442994D7}.Release|Any CPU.ActiveCfg = Release|Any CPU {1E318685-BF0A-4508-AE47-76C7442994D7}.Release|Any CPU.Build.0 = Release|Any CPU + {5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/bot/bot/Autonomous.cs b/bot/bot/Autonomous.cs index 893a1ba..0ac97de 100644 --- a/bot/bot/Autonomous.cs +++ b/bot/bot/Autonomous.cs @@ -3,9 +3,126 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Reflection; +using MySql.Data.MySqlClient; namespace bot { class Autonomous { - + public int id; + public string name; + public int startDay; + public int[] startTime; + public int periodicity; + public int randomness; + public Type responseType; + public string parameters; + + public DateTime nextTrigger = new DateTime(0); + public DateTime linkTrigger = new DateTime(0); + + public int autolinkid; + public Autonomous autolink; + public bool linkrespond; + public int timeout; + public int torandomness; + + public Random rng = new Random(); + + public Autonomous(int id, string name, int startDay, int[] startTime, int periodicity, int randomness, + string responseType, string parameters, + int autolinkid, bool linkrespond, int timeout, int torandomness) { + this.id = id; + this.name = name; + this.startDay = startDay; + this.startTime = startTime; + this.periodicity = periodicity; + this.randomness = randomness; + + this.responseType = Assembly.GetExecutingAssembly().GetTypes().Where(t => String.Equals(t.Namespace, "bot.responses", StringComparison.Ordinal) && String.Equals(t.Name, responseType, StringComparison.Ordinal)).ToArray()[0]; + this.parameters = parameters; + + this.autolinkid = autolinkid; + this.linkrespond = linkrespond; + this.timeout = timeout; + this.torandomness = torandomness; + + CalculateNextTrigger(); + } + + public Autonomous(int id, string name, int startDay, int[] startTime, int periodicity, int randomness, + int responseId, string parameters, + int autolinkid, bool linkrespond, int timeout, int torandomness) { + this.id = id; + this.name = name; + this.startDay = startDay; + this.startTime = startTime; + this.periodicity = periodicity; + this.randomness = randomness; + + string responseType = (string)(new MySqlCommand("SELECT `name` FROM `resptypes` WHERE `id`=" + responseId, _G.conn)).ExecuteScalar(); + this.responseType = Assembly.GetExecutingAssembly().GetTypes().Where(t => String.Equals(t.Namespace, "bot.responses", StringComparison.Ordinal) && String.Equals(t.Name, responseType, StringComparison.Ordinal)).ToArray()[0]; + this.parameters = parameters; + + this.autolinkid = autolinkid; + this.linkrespond = linkrespond; + this.timeout = timeout; + this.torandomness = torandomness; + + CalculateNextTrigger(); + } + + public void triggerRoutine(bool force = false) { + if(_G.getLocalTimeFromUTC() > nextTrigger || force) { + ResponseCaller.callResponse(responseType, parameters, new Message("null","null")); + CalculateNextTrigger(); + if(autolinkid != -1) { + linkTrigger = _G.getLocalTimeFromUTC().AddSeconds(timeout + (rng.Next(2) == 0 ? 1 : -1) * rng.Next(torandomness)); + Bot.ignoreResponses = linkrespond; + } + } else if(_G.getLocalTimeFromUTC() > linkTrigger && linkTrigger != new DateTime(0)) { + autolink.triggerRoutine(true); + linkTrigger = new DateTime(0); + Bot.ignoreResponses = false; + } + } + + public void CalculateNextTrigger() { + DateTime now = _G.getLocalTimeFromUTC(); + + if(nextTrigger == new DateTime(0)) { + if(startDay == -2) + nextTrigger = now.AddSeconds(periodicity + (rng.Next(2) == 0 ? 1 : -1) * rng.Next(randomness)); + else if(startDay == -1) { + if(startTime[0] == -1) + nextTrigger = now; + else { + if(now.Hour < startTime[0] || (now.Hour == startTime[0] && now.Minute < startTime[1])) + nextTrigger = new DateTime(now.Year, now.Month, now.Day, startTime[0], startTime[1], 0); + else { + DateTime tomorrow = now.AddDays(1); + nextTrigger = new DateTime(tomorrow.Year, tomorrow.Month, tomorrow.Day, startTime[0], startTime[1], 0); + } + } + } else if(startDay == -999) + nextTrigger = now.AddYears(1000); + else { + DateTime tmp; + if((int)now.DayOfWeek == startDay - 1) { + if(now.Hour < startTime[0] || (now.Hour == startTime[0] && now.Minute < startTime[1])) + nextTrigger = new DateTime(now.Year, now.Month, now.Day, startTime[0], startTime[1], 0); + else { + tmp = now.AddDays(7); + nextTrigger = new DateTime(tmp.Year, tmp.Month, tmp.Day, startTime[0], startTime[1], 0); + } + } else { + int adder = (startDay - 1) - (int)now.DayOfWeek; + tmp = now.AddDays(adder); + if(adder < 0) tmp.AddDays(7); + nextTrigger = new DateTime(tmp.Year, tmp.Month, tmp.Day, startTime[0], startTime[1], 0); + } + } + } else if(startDay != -999) + nextTrigger = now.AddSeconds(periodicity + (rng.Next(2) == 0 ? 1 : -1) * rng.Next(randomness)); + } } } diff --git a/bot/bot/Bot.cs b/bot/bot/Bot.cs index 52bfb99..89a5103 100644 --- a/bot/bot/Bot.cs +++ b/bot/bot/Bot.cs @@ -19,6 +19,20 @@ namespace bot { static List indResponseList = new List(); static List autoList = new List(); + public static bool ignoreResponses = false; + + public static void AutonomousThread() { + while(true) { + try { + foreach(Autonomous auto in autoList) { + auto.triggerRoutine(); + } + } catch(Exception e) { + // catch this at some point + } + } + } + public static void loadNavigationList() { List tmpList = new List(); var tmp = _G.spawnNewConnection(); @@ -61,7 +75,39 @@ namespace bot { } public static void loadAutonomousList() { + List tmpList = new List(); + var tmp = _G.spawnNewConnection(); + var r = Query.Reader("SELECT * FROM `autonomous`", tmp); + while(r.Read()) { + tmpList.Add(new Autonomous( + r.GetInt32("id"), + r.GetString("name"), + r.GetInt32("startday"), + new int[] { Int32.Parse(r.GetString("starttime").Split(',')[0]), Int32.Parse(r.GetString("starttime").Split(',')[1]) }, + r.GetInt32("periodicity"), + r.GetInt32("randomness"), + r.GetInt32("respid"), + r.GetString("parameters"), + r.GetInt32("autolink"), + !r.GetBoolean("linkrespond"), + r.GetInt32("timeout"), + r.GetInt32("torandomness"))); + } + r.Close(); + tmp.Close(); + autoList = tmpList; + // TODO improve this later + foreach(Autonomous auto in autoList) { + if(auto.autolinkid != -1) { + foreach(Autonomous autoauto in autoList) { + if(auto.autolinkid == autoauto.id) { + auto.autolink = autoauto; + break; + } + } + } + } } static void Main(string[] args) { @@ -82,6 +128,10 @@ namespace bot { loadResponseList(); Console.WriteLine("OK"); + Console.Write("Loading autonomous routine list ..."); + loadAutonomousList(); + Console.WriteLine("OK"); + Console.Write("Updating response types on database ... "); tmp = "DELETE FROM resptypes WHERE "; foreach(Type t in ResponseCaller.getResponseTypes()) { @@ -136,35 +186,39 @@ namespace bot { _G.startThread(Pulse.pulseThread); - // TODO add autonomous thread start - Chat.reloadContext(_G.driver); + (new Thread(new ThreadStart(Bot.AutonomousThread))).Start(); + Console.WriteLine(_G.propername + " has started successfully."); DateTime lastAction = new DateTime(0); while(Chat.isChatting(_G.driver)) { Message msg = Chat.waitForNewMessage(_G.driver); - if(msg == null) break; - if(msg.msg == "!dump") { - foreach(Response r in responseList) - Chat.sendMessage("IF "+ r.condstr +" THEN "+ r.responseType.Name); - } - if(msg.msg == "!update") { - Bot.loadResponseList(); - Chat.sendMessage("response list updated"); - } + if(!ignoreResponses) { + if(msg == null) break; + if(msg.msg == "!dump") { + foreach(Response r in responseList) + Chat.sendMessage("IF " + r.condstr + " THEN " + r.responseType.Name); + } + if(msg.msg == "!update") { + Bot.loadResponseList(); + Chat.sendMessage("response list updated"); + Bot.loadAutonomousList(); + Chat.sendMessage("autonomous list updated"); + } - foreach(Response response in indResponseList) { - if(response.triggerResponse(msg)) break; - } + foreach(Response response in indResponseList) { + if(response.triggerResponse(msg)) break; + } - foreach(Response response in responseList) { - if((DateTime.Now - lastAction).TotalSeconds >= _G.defaultCooldown) { - if(response.triggerResponse(msg)) { - lastAction = DateTime.Now; - break; + foreach(Response response in responseList) { + if((DateTime.Now - lastAction).TotalSeconds >= _G.defaultCooldown) { + if(response.triggerResponse(msg)) { + lastAction = DateTime.Now; + break; + } } } } diff --git a/bot/bot/Chat.cs b/bot/bot/Chat.cs index 1fe364b..4091144 100644 --- a/bot/bot/Chat.cs +++ b/bot/bot/Chat.cs @@ -17,6 +17,8 @@ namespace bot { static int currentMessage; public static void reloadContext(FirefoxDriver d) { + while(!ProtectionContext.Protect()) ; + Console.WriteLine("reloading context"); while(true) { try { @@ -35,19 +37,26 @@ namespace bot { Console.WriteLine("reloading context complete"); if(d.FindElement(By.Id("audioButton")).GetAttribute("class").ToLower() == "button") d.FindElement(By.Id("audioButton")).Click(); + + ProtectionContext.Free(); } - public static void sendMessage(string text) { - sendMessage(text, _G.driver); + public static void sendMessage(string text, bool protect = true) { + sendMessage(text, _G.driver, protect); } - public static void sendMessage(string text, FirefoxDriver d) { - // TODO protection context corrections + public static void sendMessage(string text, FirefoxDriver d, bool protect = true) { + if(protect) + while(!ProtectionContext.Protect()) ; + if(isChatting(d)) { d.FindElement(By.Id("inputField")).SendKeys(text); d.FindElement(By.Id("submitButton")).Click(); try { Thread.Sleep(500); } catch(Exception e) { } } + + if(protect) + ProtectionContext.Free(); } public static bool isChatting(FirefoxDriver d) { diff --git a/bot/bot/ProtectionContext.cs b/bot/bot/ProtectionContext.cs new file mode 100644 index 0000000..aec82d7 --- /dev/null +++ b/bot/bot/ProtectionContext.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bot { + class ProtectionContext { + private static bool isWriteable = true; + private static DateTime timeOfWriteProtection = new DateTime(0); + private static int maxProtectionTime = 45; + + public static bool Protect() { + if(isWriteable == true || (DateTime.Now-timeOfWriteProtection).TotalSeconds > maxProtectionTime) { + isWriteable = false; + timeOfWriteProtection = DateTime.Now; + return true; + } else return false; + } + + public static void Free() { + isWriteable = true; + } + } +} diff --git a/bot/bot/bot.csproj b/bot/bot/bot.csproj index 23edd6c..919c403 100644 --- a/bot/bot/bot.csproj +++ b/bot/bot/bot.csproj @@ -87,6 +87,7 @@ + diff --git a/bot/bot/conditions/msgcntword.cs b/bot/bot/conditions/msgcntword.cs index abc4eec..ce4a194 100644 --- a/bot/bot/conditions/msgcntword.cs +++ b/bot/bot/conditions/msgcntword.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace bot.conditions { @@ -11,7 +12,8 @@ namespace bot.conditions { } static public bool performCheck(Message msg, string parameter) { - return false; // implement + Regex matcher = new Regex("\\b"+ parameter.ToLower() +"\\b"); + return matcher.IsMatch(msg.msg.ToLower()); } } } diff --git a/bot/responses/Class1.cs b/bot/responses/Class1.cs new file mode 100644 index 0000000..24961f0 --- /dev/null +++ b/bot/responses/Class1.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace responses +{ + public class Class1 + { + } +} diff --git a/bot/responses/Properties/AssemblyInfo.cs b/bot/responses/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ec4914f --- /dev/null +++ b/bot/responses/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("responses")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Hewlett-Packard")] +[assembly: AssemblyProduct("responses")] +[assembly: AssemblyCopyright("Copyright © Hewlett-Packard 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dd73d63c-48bf-4a83-a3db-8f13dc5d70ad")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/bot/responses/responses.csproj b/bot/responses/responses.csproj new file mode 100644 index 0000000..c05dbb2 --- /dev/null +++ b/bot/responses/responses.csproj @@ -0,0 +1,53 @@ + + + + + Debug + AnyCPU + {5CC66C93-279D-4E00-9FE1-FAFF54FC4D6F} + Library + Properties + responses + responses + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/www/auto.php b/www/auto.php index 0123b46..894ae63 100644 --- a/www/auto.php +++ b/www/auto.php @@ -6,17 +6,18 @@ if($_GET['del']) { } if($_POST["editId"]) { - // TODO update this - mysql_query("UPDATE `autonomous` SET `conditions`='". mysql_real_escape_string($c) ."', `respid`=". $_POST['resptype'] .", `parameters`='". mysql_real_escape_string($_POST['parameters']) ."', `cooldown`=". (($_POST['cdd']==0)?-1:$_POST['cooldown']) ." WHERE `id`=". $_POST['editId']) or die(mysql_error()); + $stime = ($_POST['starttimehour'] == -1 || $_POST['starttimemin'] == -1 || $_POST['startday'] == -2) ? "-1,-1" : $_POST['starttimehour'] .",". $_POST['starttimemin']; + mysql_query("UPDATE `autonomous` SET `name`='". mysql_real_escape_string($_POST['arname']) ."', `startday`=". $_POST['startday'] .", `starttime`='". $stime ."', `periodicity`=". $_POST['period'] .", `randomness`=". $_POST['randomness'] .", `respid`=". $_POST['resptype'] .", `parameters`='". mysql_real_escape_string($_POST['parameters']) ."', `autolink`=". $_POST['autolink'] .", `linkrespond`=". (($_POST["respond"]?"1":"0")) .", `timeout`=". $_POST['timeout'] .", `torandomness`=". $_POST['torandom'] ." WHERE `id`=". $_POST['editId']) or die(mysql_error()); mysql_query("UPDATE `updater` SET `autonomous`=1 WHERE `id`=1"); header("Location: auto.php"); } if($_POST["resptype"] && !$_POST["editId"]) { + $stime = ($_POST['starttimehour'] == -1 || $_POST['starttimemin'] == -1 || $_POST['startday'] == -2) ? "-1,-1" : $_POST['starttimehour'] .",". $_POST['starttimemin']; if($_POST["autolink"] == -1) - mysql_query("INSERT INTO `autonomous` (`conditions`,`respid`,`parameters`,`cooldown`) VALUES ('". mysql_real_escape_string($c) ."',". $_POST['resptype'] .",'". mysql_real_escape_string($_POST['parameters']) ."',". (($_POST['ccd']==0)?-1:$_POST['cooldown']) .")") or die(mysql_error()); + mysql_query("INSERT INTO `autonomous` (`name`,`startday`,`starttime`,`periodicity`,`randomness`,`respid`,`parameters`) VALUES ('". mysql_real_escape_string($_POST['arname']) ."',". $_POST['startday'] .",'". $stime ."',". $_POST['period'] .",". $_POST['randomness'] .",". $_POST['resptype'] .",'". mysql_real_escape_string($_POST['parameters']) ."')") or die(mysql_error()); else - // do query + mysql_query("INSERT INTO `autonomous` (`name`,`startday`,`starttime`,`periodicity`,`randomness`,`respid`,`parameters`,`autolink`,`linkrespond`,`timeout`,`torandomness`) VALUES ('". mysql_real_escape_string($_POST['arname']) ."',". $_POST['startday'] .",'". $stime ."',". $_POST['period'] .",". $_POST['randomness'] .",". $_POST['resptype'] .",'". mysql_real_escape_string($_POST['parameters']) ."',". $_POST['autolink'] .",". (($_POST["respond"]?"1":"0")) .",". $_POST['timeout'] .",". $_POST['torandom'] .")") or die(mysql_error()); mysql_query("UPDATE `updater` SET `autonomous`=1 WHERE `id`=1"); header("Location: auto.php"); } @@ -27,7 +28,7 @@ include("header.php"); /*var defaultCool = cooldown; ?>;*/ function confirmDeletion(id) { - var q = confirm("Are you sure you want to delete this response?"); + var q = confirm("Are you sure you want to delete this autonomous routine?"); if(q) window.location.href = "auto.php?del="+id; } @@ -51,16 +52,18 @@ include("header.php"); function evaluateCondition() { if(document.getElementById("arname").value.trim() != "") { - if(doTimeTest("Periodicity",document.getElementById("period").value)) { - if(doTimeTest("Randomness",document.getElementById("randomness").value)) { - if(document.getElementById("autolink").selectedIndex != 0) { - if(doTimeTest("Link timeout",document.getElementById("timeout").value)) { - if(doTimeTest("Link randomness",document.getElementById("torandom").value)) { - document.getElementById("auto").submit(); + if(document.getElementById("startday").selectedIndex <= 2 || (document.getElementById("startday").selectedIndex > 2 && document.getElementById("sth").selectedIndex != 0 && document.getElementById("stm").selectedIndex != 0)) { + if(doTimeTest("Periodicity",document.getElementById("period").value)) { + if(doTimeTest("Randomness",document.getElementById("randomness").value,true)) { + if(document.getElementById("autolink").selectedIndex != 0) { + if(doTimeTest("Link timeout",document.getElementById("timeout").value)) { + if(doTimeTest("Link randomness",document.getElementById("torandom").value,true)) { + document.getElementById("auto").submit(); + } } + } else { + document.getElementById("auto").submit(); } - } else { - document.getElementById("auto").submit(); } } } @@ -79,6 +82,13 @@ include("header.php"); } } + function handleStartDayChange() { + if(document.getElementById("startday").selectedIndex > 1) + document.getElementById("stdisp").style.display = "inline"; + else + document.getElementById("stdisp").style.display = "none"; + } + /*function coolChange() { if(document.getElementById("cdd").selectedIndex == 0) { document.getElementById("cooldown").disabled = true; @@ -94,22 +104,21 @@ include("header.php");

New Autonomous Routine

- +   - ". parseConditionString($resp->conditions, mysql_fetch_object(mysql_query("SELECT * FROM `resptypes` WHERE `id`=". $resp->respid))->friendlyname) ." + ". $resp->name ." "; - }*/ + } ?>
@@ -120,8 +129,10 @@ include("header.php");

Trigger first routine on - + + + @@ -130,17 +141,18 @@ include("header.php"); +

After first trigger, @@ -198,7 +211,7 @@ include("header.php"); (for future reference) +

+

+ Trigger first routine on + + startday == -2) { ?> style="display: none;"> + at + + : + + +

+

+ After first trigger, + + + +
    continue triggering every seconds
    with a randomness of± seconds.
+ +

+

+ On trigger, ". $desc ."

"; $i++; @@ -272,34 +332,66 @@ include("header.php");

- respid))->description; - ?> - - Parameters: -

- -
+ + Parameters: +
+ +

- Cooldown: - - cooldown == -1) { ?> disabled="disabled" /> seconds + After triggering, + + + + + + + + autolink == -1) { ?> style="display: none;"> + + + + + + autolink == -1) { ?> style="display: none;"> + + + + + + autolink == -1) { ?> style="display: none;"> + + + + + +
    Force routine to trigger
after + seconds +
with a randomness of± + seconds. +
While waiting to trigger, + . +

- +      - +

-