private static Command ParseResponse(APIResponse response) { // Make sure there was a tag on the response if (response.Tag == null) { Console.WriteLine($"No tag ({response})"); return(null); } // Find command using tag Command command = CommandsWaitingForResponse[response.Tag]; // Don't need to proceed if this is the response to our KeepAlive ping if (response.Tag == _keepAliveTag) { // TODO do NAT stuff here instead of where we sent this ping, since we have the port the API sees AniDB.InvokeKeepAlivePong(); return(null); } if (command != null) { return(command); } // We should always have a command here, since we set a tag on every command we send // Raise an error saying we're missing a command AniDB.InvokeClientError( new ClientErrorArgs($"Command is null; tag is probably not set on reply\nData: {response}") ); return(null); }
private static ICommandResult WaitForResponse(CommandTag tag) { int waitTime = 0; while (CommandsWithResponse.ContainsKey(tag) == false) { if (waitTime > 20_000) { // Note: I *think* that this should fix itself it it encounters a race condition. lock (rlLock) { _timeOutsSinceLastResponse++; if (_timeOutsSinceLastResponse > 5) { // we're probably rate limited _rateLimited = true; } } return(new CommandResult(ReturnCode.RequestTimedOut)); } Thread.Sleep(50); waitTime += 50; } lock (rlLock) { _timeOutsSinceLastResponse = 0; } AniDB.InvokeCommandResultReceived(new CommandResultReceivedArgs()); tag.Release(); return(CommandsWithResponse[tag]); }
public static Task <ICommandResult> QueueCommand(Command command) { if (Connected == false) { AniDB.InvokeClientError( new ClientErrorArgs( $"Connection must be initialized before queueing commands! {command.CommandBase}")); } CommandQueue.Enqueue(command); return(Task.Run(() => WaitForResponse(command.Tag))); }
private static void KeepConnectionAlive(DateTime lastCommandSentTime) { // Check if last command we sent was more than 5 minutes ago so we can keep connection alive (for NAT) if (lastCommandSentTime < DateTime.Now.AddMinutes(-5) && lastCommandSentTime != DateTime.MinValue) { PingCommand pingCommand = new PingCommand(); bool parameterSet = pingCommand.SetOptionalParameter("nat", "1", out string error); if (parameterSet == false) { AniDB.InvokeClientError(new ClientErrorArgs($"Setting parameter failed ({error})")); return; } _keepAliveTag = pingCommand.Tag; Task <ICommandResult> _ = pingCommand.Send(); AniDB.InvokeKeepAlivePing(); } Thread.Sleep(150); // small timeout }
private static void SendCommand(Command command) { if (ShouldSendCommand(command) == false) { return; } string commandString = $"{command.CommandBase} {command.GetParameters()}".Trim(); if (command.RequiresSession) { commandString += $"&{Session.SessionKey}"; } // TEMP Console.WriteLine("Sending data: " + commandString); AniDB.InvokeCommandSent(new CommandSentArgs(command)); byte[] bytes = Encoding.ASCII.GetBytes(commandString); _connection.Send(bytes, bytes.Length); CommandsWaitingForResponse.Add(command.Tag, command); }