Skip to content

Commit

Permalink
fix: always use short delay for anidb ping commands
Browse files Browse the repository at this point in the history
  • Loading branch information
revam committed Oct 30, 2024
1 parent f06a89b commit 963a641
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 21 deletions.
16 changes: 14 additions & 2 deletions Shoko.Server/API/v3/Controllers/DebugController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public async Task<AnidbUdpResponse> CallAniDB([FromBody] AnidbUdpRequest request
}

var fullResponse = request.Unsafe ?
await _udpHandler.SendDirectly(request.Command, resetPingTimer: request.IsPing) :
await _udpHandler.SendDirectly(request.Command, isPing: request.IsPing, isLogout: request.IsLogout) :
await _udpHandler.Send(request.Command);
var decodedParts = fullResponse.Split('\n');
var decodedResponse = string.Join('\n',
Expand Down Expand Up @@ -234,6 +234,18 @@ public bool IsPing
}
}

/// <summary>
/// Indicates that this request is a ping request.
/// </summary>
[JsonIgnore]
public bool IsLogout
{
get
{
return string.Equals(Action, "LOGOUT", StringComparison.InvariantCultureIgnoreCase);
}
}

/// <summary>
/// Indicates the request needs authentication.
/// </summary>
Expand All @@ -242,7 +254,7 @@ public bool NeedAuth
{
get
{
return !IsPing && (!Payload.ContainsKey("s"));
return !IsPing && !Payload.ContainsKey("s");
}
}

Expand Down
6 changes: 3 additions & 3 deletions Shoko.Server/Providers/AniDB/AniDBRateLimiter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -43,14 +43,14 @@ private void ResetRate()
_logger.LogTrace("Rate is reset. Active time was {Time} ms", elapsedTime);
}

public async Task<T> EnsureRateAsync<T>(Func<Task<T>> action)
public async Task<T> EnsureRateAsync<T>(Func<Task<T>> action, bool forceShortDelay = false)
{
await _lock.WaitAsync();
try
{
var delay = _requestWatch.ElapsedMilliseconds;
if (delay > ResetPeriod) ResetRate();
var currentDelay = _activeTimeWatch.ElapsedMilliseconds > ShortPeriod ? LongDelay : ShortDelay;
var currentDelay = !forceShortDelay && _activeTimeWatch.ElapsedMilliseconds > ShortPeriod ? LongDelay : ShortDelay;

if (delay > currentDelay)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface IUDPConnectionHandler : IConnectionHandler
Task<bool> Init(string username, string password, string serverName, ushort serverPort, ushort clientPort);
Task<bool> TestLogin(string username, string password);

Task<string> SendDirectly(string command, bool needsUnicode = true, bool resetPingTimer = true, bool resetLogoutTimer = true);
Task<string> SendDirectly(string command, bool needsUnicode = true, bool isPing = false, bool isLogout = false);

Task<string> Send(string command, bool needsUnicode = true);
}
29 changes: 16 additions & 13 deletions Shoko.Server/Providers/AniDB/UDP/AniDBUDPConnectionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -243,35 +243,39 @@ public async Task<string> Send(string command, bool needsUnicode = true)
return await SendDirectly(command, needsUnicode);
}

public Task<string> SendDirectly(string command, bool needsUnicode = true, bool resetPingTimer = true, bool resetLogoutTimer = true)
public Task<string> SendDirectly(string command, bool needsUnicode = true, bool isPing = false, bool isLogout = false)
{
try
{
// we want to reset the logout timer anyway
if (resetPingTimer) _pingTimer?.Stop();
if (resetLogoutTimer) _logoutTimer?.Stop();
if (!isLogout && !isPing)
{
_pingTimer?.Stop();
_logoutTimer?.Stop();
}

return SendInternal(command, needsUnicode);
return SendInternal(command, needsUnicode, isPing);
}
finally
{
if (resetPingTimer) _pingTimer?.Start();
if (resetLogoutTimer) _logoutTimer?.Start();
if (!isLogout && !isPing)
{
_pingTimer?.Start();
_logoutTimer?.Start();
}
}
}

private async Task<string> SendInternal(string command, bool needsUnicode = true)
private async Task<string> SendInternal(string command, bool needsUnicode = true, bool isPing = false)
{
ObjectDisposedException.ThrowIf(_socketHandler is not { IsConnected: true }, "The connection was closed by shoko");

// 1. Call AniDB
// 2. Decode the response, converting Unicode and decompressing, as needed
// 3. Check for an Error Response
// 4. Return a pretty response object, with a parsed return code and trimmed string
var encoding = needsUnicode ? new UnicodeEncoding(true, false) : Encoding.ASCII;

if (_socketHandler is not { IsConnected: true }) throw new ObjectDisposedException("The connection was closed by shoko");

var sendByteAdd = encoding.GetBytes(command);

var timeoutPolicy = Policy
.Handle<SocketException>(e => e is { SocketErrorCode: SocketError.TimedOut })
.Or<OperationCanceledException>()
Expand All @@ -280,7 +284,7 @@ private async Task<string> SendInternal(string command, bool needsUnicode = true
Logger.LogWarning("AniDB request timed out. Checking Network and trying again");
await _connectivityService.CheckAvailability();
});
var result = await timeoutPolicy.ExecuteAndCaptureAsync(async () => await RateLimiter.EnsureRateAsync(async () =>
var result = await timeoutPolicy.ExecuteAndCaptureAsync(async () => await RateLimiter.EnsureRateAsync(forceShortDelay: isPing, action: async () =>
{
if (_connectivityService.NetworkAvailability < NetworkAvailability.PartialInternet)
{
Expand All @@ -289,7 +293,6 @@ private async Task<string> SendInternal(string command, bool needsUnicode = true
}

var start = DateTime.Now;

Logger.LogTrace("AniDB UDP Call: (Using {Unicode}) {Command}", needsUnicode ? "Unicode" : "ASCII", MaskLog(command));
var byReceivedAdd = await _socketHandler.Send(sendByteAdd);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public override UDPResponse<Void> Send()
}

PreExecute(Handler.SessionID);
var rawResponse = Handler.SendDirectly(Command, resetPingTimer: false, resetLogoutTimer: false).Result;
var rawResponse = Handler.SendDirectly(Command, isLogout: true).Result;
var response = ParseResponse(rawResponse);
var parsedResponse = ParseResponse(response);
return parsedResponse;
Expand Down
2 changes: 1 addition & 1 deletion Shoko.Server/Providers/AniDB/UDP/Connection/RequestPing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected override void PreExecute(string sessionID)

public override UDPResponse<Void> Send()
{
var rawResponse = Handler.SendDirectly(BaseCommand, resetPingTimer: false, resetLogoutTimer: false).Result;
var rawResponse = Handler.SendDirectly(BaseCommand, isPing: true).Result;
var response = ParseResponse(rawResponse, true);
var parsedResponse = ParseResponse(response);
return parsedResponse;
Expand Down

0 comments on commit 963a641

Please sign in to comment.