From ae9b9caeb90451c860e5be7fe19e51f81267c9f8 Mon Sep 17 00:00:00 2001 From: runebaas Date: Wed, 23 Sep 2020 16:05:43 +0200 Subject: [PATCH] Add random.org for random number generation. --- src/Bot/Commands/Utils/Quote/Quote.cs | 2 +- src/Bot/Program.cs | 2 +- src/Core/Core.csproj | 1 + .../RandomNumberGenerator.cs | 57 +++++++++++++++++-- tests/Core/DiceParser/DiceParser.test.cs | 6 +- tests/Core/DiceParser/SingleDie.test.cs | 6 +- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/Bot/Commands/Utils/Quote/Quote.cs b/src/Bot/Commands/Utils/Quote/Quote.cs index a7d3ff1..6f4cd1c 100644 --- a/src/Bot/Commands/Utils/Quote/Quote.cs +++ b/src/Bot/Commands/Utils/Quote/Quote.cs @@ -46,7 +46,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote return; } - var random = _randomNumberGenerator.Next(0, s.Count); + var random = _randomNumberGenerator.Next(0, s.Count - 1); var quote = s[random]; var embed = QuoteBuilder(quote); diff --git a/src/Bot/Program.cs b/src/Bot/Program.cs index 5a4b456..5994f8c 100644 --- a/src/Bot/Program.cs +++ b/src/Bot/Program.cs @@ -164,7 +164,7 @@ namespace Geekbot.Bot var emojiConverter = new EmojiConverter(); var mtgManaConverter = new MtgManaConverter(); var wikipediaClient = new WikipediaClient(); - var randomNumberGenerator = new RandomNumberGenerator(); + var randomNumberGenerator = new RandomNumberGenerator(_globalSettings); var mediaProvider = new MediaProvider(_logger, randomNumberGenerator); var kvMemoryStore = new KvInInMemoryStore(); var errorHandler = new ErrorHandler(_logger, _runParameters, () => Localization.Internal.SomethingWentWrong); diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 7b273fd..0b3ff44 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs b/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs index 63381b5..db990a7 100644 --- a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs +++ b/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs @@ -1,25 +1,69 @@ using System; using System.Security.Cryptography; +using Anemonis.RandomOrg; +using Geekbot.Core.GlobalSettings; namespace Geekbot.Core.RandomNumberGenerator { public class RandomNumberGenerator : IRandomNumberGenerator { - readonly RNGCryptoServiceProvider csp; + private readonly RNGCryptoServiceProvider csp; + private readonly bool _canUseRandomOrg; + private readonly RandomOrgClient _randomOrgClient; - public RandomNumberGenerator() + public RandomNumberGenerator(IGlobalSettings globalSettings) { csp = new RNGCryptoServiceProvider(); + + var randomOrgApiKey = globalSettings.GetKey("RandomOrgApiKey"); + if (!string.IsNullOrEmpty(randomOrgApiKey)) + { + _canUseRandomOrg = true; + _randomOrgClient = new RandomOrgClient(randomOrgApiKey); + } } - public int Next(int minValue, int maxExclusiveValue) + public int Next(int minValue, int maxInclusiveValue) { - if (minValue >= maxExclusiveValue) + if (minValue == maxInclusiveValue) + { + return maxInclusiveValue; + } + + if (minValue >= maxInclusiveValue) { throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue"); } + + if (_canUseRandomOrg) + { + try + { + return GetFromRandomOrg(minValue, maxInclusiveValue); + } + catch + { + // ignore + } + } - var diff = (long)maxExclusiveValue - minValue; + return GetFromCrypto(minValue, maxInclusiveValue); + } + + private int GetFromRandomOrg(int minValue, int maxInclusiveValue) + { + return _randomOrgClient + .GenerateIntegersAsync(1, minValue, maxInclusiveValue, false) + .Result + .Random + .Data[0]; + } + + private int GetFromCrypto(int minValue, int maxInclusiveValue) + { + var maxExclusiveValue = maxInclusiveValue + 1; + + var diff = (long) maxExclusiveValue - minValue; var upperBound = uint.MaxValue / diff * diff; uint ui; @@ -27,7 +71,8 @@ namespace Geekbot.Core.RandomNumberGenerator { ui = GetRandomUInt(); } while (ui >= upperBound); - return (int)(minValue + (ui % diff)); + + return (int) (minValue + (ui % diff)); } private uint GetRandomUInt() diff --git a/tests/Core/DiceParser/DiceParser.test.cs b/tests/Core/DiceParser/DiceParser.test.cs index 8a9163a..ed9425f 100644 --- a/tests/Core/DiceParser/DiceParser.test.cs +++ b/tests/Core/DiceParser/DiceParser.test.cs @@ -1,15 +1,17 @@ using System.Collections.Generic; using System.Text.Json; using Geekbot.Core.DiceParser; +using Geekbot.Core.GlobalSettings; using Geekbot.Core.RandomNumberGenerator; +using Moq; using Xunit; namespace Tests.Core.DiceParser { public class DiceParserTest { - private static readonly RandomNumberGenerator _randomNumberGenerator = new RandomNumberGenerator(); - + private static readonly RandomNumberGenerator _randomNumberGenerator = new RandomNumberGenerator(new Mock().Object); + public struct DiceParserTestDto { public string Input { get; set; } diff --git a/tests/Core/DiceParser/SingleDie.test.cs b/tests/Core/DiceParser/SingleDie.test.cs index 813a33b..5173902 100644 --- a/tests/Core/DiceParser/SingleDie.test.cs +++ b/tests/Core/DiceParser/SingleDie.test.cs @@ -1,5 +1,7 @@ using Geekbot.Core.DiceParser; +using Geekbot.Core.GlobalSettings; using Geekbot.Core.RandomNumberGenerator; +using Moq; using Xunit; namespace Tests.Core.DiceParser @@ -43,7 +45,7 @@ namespace Tests.Core.DiceParser [Theory, MemberData(nameof(SingleDieNameTestData))] public void SingleDieNameTestFunc(string testName, SingleDieNameTestDto testData) { - var die = new SingleDie(new RandomNumberGenerator()) {AdvantageType = testData.AdvantageType}; + var die = new SingleDie(new RandomNumberGenerator(new Mock().Object)) {AdvantageType = testData.AdvantageType}; Assert.Equal(die.DiceName, testData.Expected); } @@ -106,7 +108,7 @@ namespace Tests.Core.DiceParser [Theory, MemberData(nameof(SingleDieValidationTestData))] public void SingleDieValidationTestFunc(string testName, SingleDieValidationTestDto testData) { - var die = new SingleDie(new RandomNumberGenerator()) + var die = new SingleDie(new RandomNumberGenerator(new Mock().Object)) { Amount = testData.Amount, Sides = testData.Sides