Skip to content

Commit

Permalink
Merge branch 'release/0.14.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jericho committed Jan 12, 2021
2 parents 710ad19 + a9086a7 commit 0386002
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 4 deletions.
16 changes: 14 additions & 2 deletions Source/ZoomNet.IntegrationTests/Tests/Chat.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ZoomNet.Models;
Expand All @@ -17,12 +18,23 @@ public async Task RunAsync(string userId, IZoomClient client, TextWriter log, Ca
var paginatedChannels = await client.Chat.GetAccountChannelsForUserAsync(userId, 100, null, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"There are {paginatedChannels.TotalRecords} account channels for user {userId}").ConfigureAwait(false);

// CLEANUP PREVIOUS INTEGRATION TESTS THAT MIGHT HAVE BEEN INTERRUPTED BEFORE THEY HAD TIME TO CLEANUP AFTER THEMSELVES
var cleanUpTasks = paginatedChannels.Records
.Where(m => m.Name.StartsWith("ZoomNet Integration Testing:"))
.Select(async oldChannel =>
{
await client.Chat.DeleteChannelAsync(oldChannel.Id, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"Channel {oldChannel.Id} deleted").ConfigureAwait(false);
await Task.Delay(250, cancellationToken).ConfigureAwait(false); // Brief pause to ensure Zoom has time to catch up
});
await Task.WhenAll(cleanUpTasks).ConfigureAwait(false);

// CREATE A NEW CHANNEL
var channel = await client.Chat.CreateAccountChannelAsync(userId, "INTEGRATION TESTING: new channel", ChatChannelType.Public, null, cancellationToken).ConfigureAwait(false);
var channel = await client.Chat.CreateAccountChannelAsync(userId, "ZoomNet Integration Testing: new channel", ChatChannelType.Public, null, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"Account channel \"{channel.Name}\" created (Id={channel.Id}").ConfigureAwait(false);

// UPDATE THE CHANNEL
await client.Chat.UpdateAccountChannelAsync(userId, channel.Id, "INTEGRATION TESTING: updated channel", cancellationToken).ConfigureAwait(false);
await client.Chat.UpdateAccountChannelAsync(userId, channel.Id, "ZoomNet Integration Testing: updated channel", cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"Account channel \"{channel.Id}\" updated").ConfigureAwait(false);

// RETRIEVE THE CHANNEL
Expand Down
2 changes: 1 addition & 1 deletion Source/ZoomNet/Resources/Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ private Task DeleteMessageAsync(string messageId, string userId, string recipien
Debug.Assert(recipientEmail == null || channelId == null, "You can't provide both recipientEmail and channelId");

return _client
.PutAsync($"chat/users/{userId}/messages/{messageId}")
.DeleteAsync($"chat/users/{userId}/messages/{messageId}")
.WithArgument("to_contact", recipientEmail)
.WithArgument("to_channel", channelId)
.WithCancellationToken(cancellationToken)
Expand Down
12 changes: 11 additions & 1 deletion Source/ZoomNet/Utilities/Http429RetryStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,17 @@ public TimeSpan GetDelay(int attempt, HttpResponseMessage response)
// QPS stands for "Query Per Second".
// It means that we have exceeded the number of API calls per second.
// Therefore we must wait one second before retrying.
waitTime = TimeSpan.FromSeconds(1);
var waitMilliseconds = 1000;

// Edit January 2021: I introduced randomness in the wait time to avoid retrying too quickly
// and to avoid requests issued in a tight loop to all be retried at the same time.
// Up to one extra second: 250 milliseconds * 4.
for (int i = 0; i < 4; i++)
{
waitMilliseconds += RandomGenerator.RollDice(250);
}

waitTime = TimeSpan.FromMilliseconds(waitMilliseconds);
}

// Make sure the wait time is valid
Expand Down
65 changes: 65 additions & 0 deletions Source/ZoomNet/Utilities/RandomGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Security.Cryptography;

namespace ZoomNet.Utilities
{
/// <summary>
/// Random generator.
/// </summary>
public static class RandomGenerator
{
#region PUBLIC METHODS

/// <summary>
/// This method simulates a roll of the dice. The input parameter is the
/// number of sides of the dice.
/// </summary>
/// <param name="numberSides">Number of sides of the dice.</param>
/// <returns>A random value.</returns>
/// <remarks>
/// From RNGCryptoServiceProvider <a href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.rngcryptoserviceprovider.aspx">documentation</a>.
/// </remarks>
public static byte RollDice(byte numberSides)
{
if (numberSides <= 0)
throw new ArgumentOutOfRangeException(nameof(numberSides));

// Create a byte array to hold the random value.
byte[] randomNumber = new byte[1];
using (var random = RandomNumberGenerator.Create())
{
do
{
// Fill the array with a random value.
random.GetBytes(randomNumber);
}
while (!IsFairRoll(randomNumber[0], numberSides));
}

// Return the random number mod the number of sides.
// The possible values are zero-based, so we add one.
return (byte)((randomNumber[0] % numberSides) + 1);
}

#endregion

#region PRIVATE METHODS

private static bool IsFairRoll(byte roll, byte numSides)
{
// There are MaxValue / numSides full sets of numbers that can come up
// in a single byte. For instance, if we have a 6 sided die, there are
// 42 full sets of 1-6 that come up. The 43rd set is incomplete.
int fullSetsOfValues = byte.MaxValue / numSides;

// If the roll is within this range of fair values, then we let it continue.
// In the 6 sided die case, a roll between 0 and 251 is allowed. (We use
// < rather than <= since the = portion allows through an extra 0 value).
// 252 through 255 would provide an extra 0, 1, 2, 3 so they are not fair
// to use.
return roll < numSides * fullSetsOfValues;
}

#endregion
}
}

0 comments on commit 0386002

Please sign in to comment.