Skip to content

Commit 1ba498a

Browse files
committed
Improve InaraService response validation
1 parent ca56c4c commit 1ba498a

1 file changed

Lines changed: 74 additions & 46 deletions

File tree

EddiInaraService/InaraService.cs

Lines changed: 74 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
using System;
66
using System.Collections.Concurrent;
77
using System.Collections.Generic;
8-
using System.Diagnostics;
98
using System.Linq;
9+
using System.Net;
1010
using System.Net.Http;
1111
using System.Net.Http.Headers;
1212
using System.Runtime.CompilerServices;
@@ -261,70 +261,98 @@ internal List<InaraAPIEvent> IndexAndFilterAPIEvents(List<InaraAPIEvent> events,
261261
return indexedEvents;
262262
}
263263

264-
private bool validateResponse(InaraResponse inaraResponse, List<InaraAPIEvent> indexedEvents, bool header = false)
264+
private bool validateResponse ( InaraResponse inaraResponse, List<InaraAPIEvent> indexedEvents,
265+
bool header = false )
265266
{
266-
// 200 - Ok
267-
if (inaraResponse.eventStatus == 200) { return true; }
267+
// Guard against null parameters
268+
ArgumentNullException.ThrowIfNull( inaraResponse );
269+
ArgumentNullException.ThrowIfNull( indexedEvents );
268270

269-
// Anything else - something is wrong.
270-
var data = new Dictionary<string, object>()
271+
// 200 - Success
272+
if ( inaraResponse.eventStatus == HttpStatusCode.OK ) { return true; }
273+
274+
var debugData = new Dictionary<string, object>()
271275
{
272-
{ "InaraAPIEvent", indexedEvents.Find(e => e.eventCustomID == inaraResponse.eventCustomID) },
273-
{ "InaraResponse", inaraResponse },
274-
{ "Stacktrace", new StackTrace() }
276+
{ "InaraAPIEvent", indexedEvents.Find( e => e.eventCustomID == inaraResponse.eventCustomID ) },
277+
{ "InaraResponse", inaraResponse }
275278
};
279+
280+
// 202 and 204 - Success with warnings
281+
if ( inaraResponse.eventStatus is HttpStatusCode.Accepted or HttpStatusCode.NoContent )
282+
{
283+
Logging.Warn(
284+
$"Inara warning/soft error reported (status {inaraResponse.eventStatus}): " +
285+
( inaraResponse.eventStatusText ?? "(No response)" ), JsonConvert.SerializeObject( debugData ) );
286+
return true;
287+
}
288+
289+
// Other status codes - log and handle based on context
276290
try
277291
{
278-
// 202 - Warning (everything is OK, but there may be multiple results for the input properties, etc.)
279-
// 204 - 'Soft' error (everything was formally OK, but there are no results for the properties set, etc.)
280-
if (inaraResponse.eventStatus is 202 or 204)
281-
{
282-
Logging.Warn("Inara warning or soft error reported: " + (inaraResponse.eventStatusText ?? "(No response)"), JsonConvert.SerializeObject(data));
283-
}
284-
// Other errors
285-
else if (!string.IsNullOrEmpty(inaraResponse.eventStatusText))
292+
if ( !string.IsNullOrEmpty( inaraResponse.eventStatusText ) )
286293
{
287-
if (header)
294+
if ( header )
288295
{
289-
Logging.Warn("Inara sending error: " + (inaraResponse.eventStatusText ?? "(No response)"), JsonConvert.SerializeObject(data));
290-
if (inaraResponse.eventStatusText.Contains("Invalid API key"))
291-
{
292-
ReEnqueueAPIEvents(indexedEvents);
293-
// The Inara API key has been rejected. We'll note and remember that.
294-
var inaraConfiguration = ConfigService.Instance.inaraConfiguration;
295-
inaraConfiguration.isAPIkeyValid = false;
296-
ConfigService.Instance.inaraConfiguration = inaraConfiguration;
297-
// Send internal events to the Inara Responder and the UI to handle the invalid API key appropriately
298-
invalidAPIkey?.Invoke(inaraConfiguration, EventArgs.Empty);
299-
}
300-
else if (inaraResponse.eventStatusText.Contains("access to API was temporarily revoked"))
301-
{
302-
// Note: This can be thrown by over-use of the readonly API key.
303-
ReEnqueueAPIEvents(indexedEvents);
304-
tooManyRequests = true;
305-
}
296+
HandleHeaderError( inaraResponse, indexedEvents, debugData );
306297
}
307298
else
308299
{
309-
// There may be an issue with a specific API event.
310-
// We'll add that API event to a list and omit sending that event again in this instance.
311-
Logging.Error("Inara event error: " + inaraResponse.eventStatusText, data);
312-
var eventName = indexedEvents.Find(e => e.eventCustomID == inaraResponse.eventCustomID)?.eventName;
313-
if ( !string.IsNullOrEmpty( eventName ) )
314-
{
315-
invalidAPIEvents.Add( eventName );
316-
}
300+
HandleEventError( inaraResponse, indexedEvents, debugData );
317301
}
318302
}
303+
319304
return false;
320305
}
321-
catch (Exception e)
306+
catch ( ArgumentException e )
322307
{
323-
Logging.Error("Failed to handle Inara server response", e);
308+
Logging.Error( "Failed to handle Inara server response", e );
324309
return false;
325310
}
326311
}
327312

313+
private void HandleHeaderError ( InaraResponse response, List<InaraAPIEvent> indexedEvents,
314+
Dictionary<string, object> debugData )
315+
{
316+
Logging.Warn(
317+
$"Inara sending error (status {response.eventStatus}): " +
318+
( response.eventStatusText ?? "(No response)" ),
319+
JsonConvert.SerializeObject( debugData ) );
320+
321+
if ( response.eventStatusText.Contains( "Invalid API key", StringComparison.OrdinalIgnoreCase ) )
322+
{
323+
ReEnqueueAPIEvents( indexedEvents );
324+
// The Inara API key has been rejected. We'll note and remember that.
325+
var inaraConfiguration = ConfigService.Instance.inaraConfiguration;
326+
inaraConfiguration.isAPIkeyValid = false;
327+
ConfigService.Instance.inaraConfiguration = inaraConfiguration;
328+
// Send internal events to the Inara Responder and the UI to handle the invalid API key appropriately
329+
invalidAPIkey?.Invoke( inaraConfiguration, EventArgs.Empty );
330+
}
331+
else if ( response.eventStatusText.Contains( "access to API was temporarily revoked",
332+
StringComparison.OrdinalIgnoreCase ) )
333+
{
334+
// Note: This can be thrown by over-use of the readonly API key.
335+
ReEnqueueAPIEvents( indexedEvents );
336+
tooManyRequests = true;
337+
}
338+
}
339+
340+
private void HandleEventError ( InaraResponse response, List<InaraAPIEvent> indexedEvents,
341+
Dictionary<string, object> debugData )
342+
{
343+
// There may be an issue with a specific API event.
344+
// We'll add that API event to a list and omit sending that event again in this instance.
345+
Logging.Error(
346+
$"Inara event error (status {response.eventStatus}): " + response.eventStatusText,
347+
JsonConvert.SerializeObject( debugData ) );
348+
349+
var eventName = indexedEvents.Find( e => e.eventCustomID == response.eventCustomID )?.eventName;
350+
if ( !string.IsNullOrEmpty( eventName ) )
351+
{
352+
invalidAPIEvents.Add( eventName );
353+
}
354+
}
355+
328356
public bool checkAPIcredentialsOk(InaraConfiguration inaraConfiguration)
329357
{
330358
// Check for a valid API key
@@ -395,7 +423,7 @@ internal class InaraResponses
395423

396424
public class InaraResponse
397425
{
398-
[UsedImplicitly] public int eventStatus { get; set; }
426+
[UsedImplicitly] public HttpStatusCode eventStatus { get; set; }
399427

400428
[UsedImplicitly] public string eventStatusText { get; set; } // Optional status text. Typically not set unless there was a problem.
401429

0 commit comments

Comments
 (0)