Merge branch 'feature-6-timers' into feature-3-lodestone-linkup
This commit is contained in:
commit
20a0c41d1e
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ obj/
|
|||||||
.idea/
|
.idea/
|
||||||
/ChaosBot/appsettings.json
|
/ChaosBot/appsettings.json
|
||||||
/ChaosBot/ChaosBotSQL.db
|
/ChaosBot/ChaosBotSQL.db
|
||||||
|
*.sln.DotSettings.user
|
||||||
|
|||||||
19
ChaosBot.UnitTests/ChaosBot.UnitTests.csproj
Normal file
19
ChaosBot.UnitTests/ChaosBot.UnitTests.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="nunit" Version="3.12.0" />
|
||||||
|
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ChaosBot\ChaosBot.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
90
ChaosBot.UnitTests/TimerTests.cs
Normal file
90
ChaosBot.UnitTests/TimerTests.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using Antlr4.Runtime;
|
||||||
|
using ChaosBot.Services;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace ChaosBot.UnitTests
|
||||||
|
{
|
||||||
|
public class TimerTests
|
||||||
|
{
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RunAt_RunningTimerAtTimestamp_True()
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
DateTime runAt = current + new TimeSpan(TimeSpan.TicksPerSecond * 10);
|
||||||
|
DateTime testAt = current + new TimeSpan(TimeSpan.TicksPerSecond * 2);
|
||||||
|
|
||||||
|
int totalRuns = 0;
|
||||||
|
|
||||||
|
void ToRun()
|
||||||
|
{
|
||||||
|
totalRuns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerId = Timer.RunAt(ToRun, runAt);
|
||||||
|
|
||||||
|
Assert.AreEqual(totalRuns, 0);
|
||||||
|
// Wait for the timer to finish
|
||||||
|
Timer.Join(timerId);
|
||||||
|
Assert.AreEqual(totalRuns, 1);
|
||||||
|
Assert.GreaterOrEqual(DateTime.Now, testAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RunIn_RunningTimerInTimeSpan_True()
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
TimeSpan runIn = new TimeSpan(TimeSpan.TicksPerSecond * 10);
|
||||||
|
DateTime testAt = current + new TimeSpan(TimeSpan.TicksPerSecond * 2);
|
||||||
|
|
||||||
|
int totalRuns = 0;
|
||||||
|
|
||||||
|
void ToRun()
|
||||||
|
{
|
||||||
|
totalRuns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerId = Timer.RunIn(ToRun, runIn);
|
||||||
|
|
||||||
|
Assert.AreEqual(totalRuns, 0);
|
||||||
|
// Wait for the timer to finish
|
||||||
|
Timer.Join(timerId);
|
||||||
|
Assert.AreEqual(totalRuns, 1);
|
||||||
|
Assert.GreaterOrEqual(DateTime.Now, testAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RunTimer_RunningTimerCountingExecutions_True()
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
TimeSpan interval = new TimeSpan(TimeSpan.TicksPerSecond * 2);
|
||||||
|
DateTime testAt = current + new TimeSpan(TimeSpan.TicksPerSecond * 11);
|
||||||
|
|
||||||
|
int totalRuns = 0;
|
||||||
|
|
||||||
|
void ToRun()
|
||||||
|
{
|
||||||
|
totalRuns++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerId = Timer.RunTimer(ToRun, interval, offset: interval);
|
||||||
|
|
||||||
|
void CancelCallback()
|
||||||
|
{
|
||||||
|
Timer.CancelTimer(timerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cancelTimerId = Timer.RunAt(CancelCallback, testAt);
|
||||||
|
|
||||||
|
Assert.AreEqual(totalRuns, 0);
|
||||||
|
// Wait for the cancel timer to finish
|
||||||
|
Timer.Join(cancelTimerId);
|
||||||
|
Assert.AreEqual(totalRuns, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChaosBot", "ChaosBot\ChaosBot.csproj", "{0222079F-84D7-4EEF-A2A6-D5AD67546D61}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChaosBot", "ChaosBot\ChaosBot.csproj", "{0222079F-84D7-4EEF-A2A6-D5AD67546D61}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChaosBot.UnitTests", "ChaosBot.UnitTests\ChaosBot.UnitTests.csproj", "{A4678BAA-93AF-4A10-8548-1921236BC57E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -12,5 +14,9 @@ Global
|
|||||||
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Release|Any CPU.Build.0 = Release|Any CPU
|
{0222079F-84D7-4EEF-A2A6-D5AD67546D61}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A4678BAA-93AF-4A10-8548-1921236BC57E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A4678BAA-93AF-4A10-8548-1921236BC57E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A4678BAA-93AF-4A10-8548-1921236BC57E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A4678BAA-93AF-4A10-8548-1921236BC57E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
117
ChaosBot/Services/Timer.cs
Normal file
117
ChaosBot/Services/Timer.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ChaosBot.Services
|
||||||
|
{
|
||||||
|
public static class Timer
|
||||||
|
{
|
||||||
|
private static Dictionary<int, System.Threading.Timer> _timers = new Dictionary<int, System.Threading.Timer>();
|
||||||
|
|
||||||
|
private static int _nextTimerIndex = 0;
|
||||||
|
private static int NextTimerIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_nextTimerIndex++;
|
||||||
|
return _nextTimerIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int RunAt(Action toRun, DateTime deadlineTime)
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
TimeSpan timeToGo = deadlineTime - current;
|
||||||
|
if (timeToGo < TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return -1; //time already passed
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerIndex = NextTimerIndex;
|
||||||
|
_timers.Add(timerIndex, new System.Threading.Timer(x =>
|
||||||
|
{
|
||||||
|
toRun();
|
||||||
|
_timers.Remove(timerIndex);
|
||||||
|
}, null, timeToGo, Timeout.InfiniteTimeSpan));
|
||||||
|
|
||||||
|
return timerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int RunIn(Action toRun, TimeSpan dueTime)
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
if (dueTime < TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return -1; //time already passed
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerIndex = NextTimerIndex;
|
||||||
|
_timers.Add(timerIndex, new System.Threading.Timer(x =>
|
||||||
|
{
|
||||||
|
toRun();
|
||||||
|
_timers.Remove(timerIndex);
|
||||||
|
}, null, dueTime, Timeout.InfiniteTimeSpan));
|
||||||
|
|
||||||
|
return timerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int RunTimer(Action toRun, TimeSpan interval)
|
||||||
|
{
|
||||||
|
return RunTimer(toRun, interval, TimeSpan.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int RunTimer(Action toRun, TimeSpan interval, TimeSpan offset)
|
||||||
|
{
|
||||||
|
DateTime current = DateTime.Now;
|
||||||
|
if (offset < TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
return -1; //time already passed
|
||||||
|
}
|
||||||
|
|
||||||
|
int timerIndex = NextTimerIndex;
|
||||||
|
|
||||||
|
void Callback()
|
||||||
|
{
|
||||||
|
toRun();
|
||||||
|
|
||||||
|
if (_timers.ContainsKey(timerIndex))
|
||||||
|
_timers.Remove(timerIndex);
|
||||||
|
_timers.Add(timerIndex, new System.Threading.Timer(x => { Callback(); }, null, interval, Timeout.InfiniteTimeSpan));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
_timers.Add(timerIndex, new System.Threading.Timer(x => { Callback(); }, null, offset, Timeout.InfiniteTimeSpan));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
return timerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CancelTimer(int id)
|
||||||
|
{
|
||||||
|
if (id < 0) return;
|
||||||
|
|
||||||
|
if (!_timers.ContainsKey(id)) return;
|
||||||
|
|
||||||
|
_timers.GetValueOrDefault(id)?.Dispose();
|
||||||
|
|
||||||
|
if (_timers.ContainsKey(id))
|
||||||
|
_timers.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Join(int id)
|
||||||
|
{
|
||||||
|
if (id < 0) return;
|
||||||
|
|
||||||
|
while (_timers.ContainsKey(id))
|
||||||
|
{
|
||||||
|
Thread.Sleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user