diff --git a/Shoko.Server/API/v3/Controllers/DebugController.cs b/Shoko.Server/API/v3/Controllers/DebugController.cs index bf25e6f89..81c01bcdd 100644 --- a/Shoko.Server/API/v3/Controllers/DebugController.cs +++ b/Shoko.Server/API/v3/Controllers/DebugController.cs @@ -122,7 +122,7 @@ public async Task 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', @@ -234,6 +234,18 @@ public bool IsPing } } + /// + /// Indicates that this request is a ping request. + /// + [JsonIgnore] + public bool IsLogout + { + get + { + return string.Equals(Action, "LOGOUT", StringComparison.InvariantCultureIgnoreCase); + } + } + /// /// Indicates the request needs authentication. /// @@ -242,7 +254,7 @@ public bool NeedAuth { get { - return !IsPing && (!Payload.ContainsKey("s")); + return !IsPing && !Payload.ContainsKey("s"); } } diff --git a/Shoko.Server/Providers/AniDB/AniDBRateLimiter.cs b/Shoko.Server/Providers/AniDB/AniDBRateLimiter.cs index 870825fa9..aaa27e88e 100644 --- a/Shoko.Server/Providers/AniDB/AniDBRateLimiter.cs +++ b/Shoko.Server/Providers/AniDB/AniDBRateLimiter.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; @@ -43,14 +43,14 @@ private void ResetRate() _logger.LogTrace("Rate is reset. Active time was {Time} ms", elapsedTime); } - public async Task EnsureRateAsync(Func> action) + public async Task EnsureRateAsync(Func> 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) { diff --git a/Shoko.Server/Providers/AniDB/Interfaces/IUDPConnectionHandler.cs b/Shoko.Server/Providers/AniDB/Interfaces/IUDPConnectionHandler.cs index 5a534906a..bcb6eec91 100644 --- a/Shoko.Server/Providers/AniDB/Interfaces/IUDPConnectionHandler.cs +++ b/Shoko.Server/Providers/AniDB/Interfaces/IUDPConnectionHandler.cs @@ -22,7 +22,7 @@ public interface IUDPConnectionHandler : IConnectionHandler Task Init(string username, string password, string serverName, ushort serverPort, ushort clientPort); Task TestLogin(string username, string password); - Task SendDirectly(string command, bool needsUnicode = true, bool resetPingTimer = true, bool resetLogoutTimer = true); + Task SendDirectly(string command, bool needsUnicode = true, bool isPing = false, bool isLogout = false); Task Send(string command, bool needsUnicode = true); } diff --git a/Shoko.Server/Providers/AniDB/UDP/AniDBUDPConnectionHandler.cs b/Shoko.Server/Providers/AniDB/UDP/AniDBUDPConnectionHandler.cs index 6b68b6183..a18f0e00e 100644 --- a/Shoko.Server/Providers/AniDB/UDP/AniDBUDPConnectionHandler.cs +++ b/Shoko.Server/Providers/AniDB/UDP/AniDBUDPConnectionHandler.cs @@ -243,35 +243,39 @@ public async Task Send(string command, bool needsUnicode = true) return await SendDirectly(command, needsUnicode); } - public Task SendDirectly(string command, bool needsUnicode = true, bool resetPingTimer = true, bool resetLogoutTimer = true) + public Task 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 SendInternal(string command, bool needsUnicode = true) + private async Task 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(e => e is { SocketErrorCode: SocketError.TimedOut }) .Or() @@ -280,7 +284,7 @@ private async Task 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) { @@ -289,7 +293,6 @@ private async Task 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); diff --git a/Shoko.Server/Providers/AniDB/UDP/Connection/RequestLogout.cs b/Shoko.Server/Providers/AniDB/UDP/Connection/RequestLogout.cs index 8cccf9c94..3fb4a8027 100644 --- a/Shoko.Server/Providers/AniDB/UDP/Connection/RequestLogout.cs +++ b/Shoko.Server/Providers/AniDB/UDP/Connection/RequestLogout.cs @@ -21,7 +21,7 @@ public override UDPResponse 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; diff --git a/Shoko.Server/Providers/AniDB/UDP/Connection/RequestPing.cs b/Shoko.Server/Providers/AniDB/UDP/Connection/RequestPing.cs index 3ff54ecf3..11d59cd5b 100644 --- a/Shoko.Server/Providers/AniDB/UDP/Connection/RequestPing.cs +++ b/Shoko.Server/Providers/AniDB/UDP/Connection/RequestPing.cs @@ -28,7 +28,7 @@ protected override void PreExecute(string sessionID) public override UDPResponse 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;