|
5 | 5 | using System; |
6 | 6 | using System.Collections.Concurrent; |
7 | 7 | using System.Collections.Generic; |
8 | | -using System.Diagnostics; |
9 | 8 | using System.Linq; |
| 9 | +using System.Net; |
10 | 10 | using System.Net.Http; |
11 | 11 | using System.Net.Http.Headers; |
12 | 12 | using System.Runtime.CompilerServices; |
@@ -261,70 +261,98 @@ internal List<InaraAPIEvent> IndexAndFilterAPIEvents(List<InaraAPIEvent> events, |
261 | 261 | return indexedEvents; |
262 | 262 | } |
263 | 263 |
|
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 ) |
265 | 266 | { |
266 | | - // 200 - Ok |
267 | | - if (inaraResponse.eventStatus == 200) { return true; } |
| 267 | + // Guard against null parameters |
| 268 | + ArgumentNullException.ThrowIfNull( inaraResponse ); |
| 269 | + ArgumentNullException.ThrowIfNull( indexedEvents ); |
268 | 270 |
|
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>() |
271 | 275 | { |
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 } |
275 | 278 | }; |
| 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 |
276 | 290 | try |
277 | 291 | { |
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 ) ) |
286 | 293 | { |
287 | | - if (header) |
| 294 | + if ( header ) |
288 | 295 | { |
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 ); |
306 | 297 | } |
307 | 298 | else |
308 | 299 | { |
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 ); |
317 | 301 | } |
318 | 302 | } |
| 303 | + |
319 | 304 | return false; |
320 | 305 | } |
321 | | - catch (Exception e) |
| 306 | + catch ( ArgumentException e ) |
322 | 307 | { |
323 | | - Logging.Error("Failed to handle Inara server response", e); |
| 308 | + Logging.Error( "Failed to handle Inara server response", e ); |
324 | 309 | return false; |
325 | 310 | } |
326 | 311 | } |
327 | 312 |
|
| 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 | + |
328 | 356 | public bool checkAPIcredentialsOk(InaraConfiguration inaraConfiguration) |
329 | 357 | { |
330 | 358 | // Check for a valid API key |
@@ -395,7 +423,7 @@ internal class InaraResponses |
395 | 423 |
|
396 | 424 | public class InaraResponse |
397 | 425 | { |
398 | | - [UsedImplicitly] public int eventStatus { get; set; } |
| 426 | + [UsedImplicitly] public HttpStatusCode eventStatus { get; set; } |
399 | 427 |
|
400 | 428 | [UsedImplicitly] public string eventStatusText { get; set; } // Optional status text. Typically not set unless there was a problem. |
401 | 429 |
|
|
0 commit comments