public static async Task <(int errorCode, string resultContent, TimeSpan executionTime, bool sentData)> UploadJournalItemToEDSM(HttpClient hc, string journalRow, Guid userIdentifier, EDSMIntegrationSettings edsmSettings, EDGameState gameState, StarSystemChecker starSystemChecker)
        {
            var element = JsonDocument.Parse(journalRow).RootElement;

            if (!element.TryGetProperty("event", out JsonElement journalEvent))
            {
                return(303, string.Empty, TimeSpan.Zero, false);
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();

            try
            {
                element = await SetGamestateProperties(element, gameState, edsmSettings.CommanderName.Trim(), starSystemChecker);

                if (System.Enum.TryParse(typeof(IgnoredEvents), journalEvent.GetString(), false, out _))
                {
                    return(304, string.Empty, TimeSpan.Zero, false);
                }

                if (!gameState.SendEvents)
                {
                    return(104, string.Empty, TimeSpan.Zero, false);
                }

                var formContent = new MultipartFormDataContent();

                var json = JsonSerializer.Serialize(element, new JsonSerializerOptions()
                {
                    WriteIndented = true
                });

                formContent.Add(new StringContent(edsmSettings.CommanderName.Trim()), "commanderName");
                formContent.Add(new StringContent(edsmSettings.ApiKey), "apiKey");
                formContent.Add(new StringContent("Journal Limpet"), "fromSoftware");
                formContent.Add(new StringContent(SharedSettings.VersionNumber), "fromSoftwareVersion");
                formContent.Add(new StringContent(json), "message");

                await SSEActivitySender.SendUserLogDataAsync(userIdentifier, new { fromIntegration = "EDSM", data = element });

                var policy = Policy
                             .HandleResult <HttpResponseMessage>(res => !res.IsSuccessStatusCode)
                             .Or <HttpRequestException>()
                             .WaitAndRetryAsync(30, retryCount => TimeSpan.FromSeconds(retryCount * 5));

                var status = await policy.ExecuteAsync(() => hc.PostAsync("https://www.edsm.net/api-journal-v1", formContent));

                var postResponseBytes = await status.Content.ReadAsByteArrayAsync();

                var postResponse = System.Text.Encoding.UTF8.GetString(postResponseBytes);
                if (!status.IsSuccessStatusCode)
                {
                    return((int)status.StatusCode, postResponse, TimeSpan.FromSeconds(30), true);
                }

                var resp = JsonSerializer.Deserialize <EDSMApiResponse>(postResponse);

                sw.Stop();

                return(resp.ResultCode, postResponse, sw.Elapsed, true);
            }
            catch (InvalidTimestampException)
            {
                return(206, string.Empty, TimeSpan.FromMilliseconds(100), false);
            }
        }
Esempio n. 2
0
        private static async Task <bool> SendEventBatch(Guid userIdentifier, PerformContext context, IConfiguration configuration, DiscordWebhook discordClient, HttpClient hc, string lastLine, UserJournal journalItem, bool loggingEnabled, IntegrationJournalData ijd, List <Dictionary <string, object> > journalEvents)
        {
            var breakJournal = false;
            await SSEActivitySender.SendUserLogDataAsync(userIdentifier, new { fromIntegration = "Canonn R&D", data = journalEvents });

            var json = JsonSerializer.Serialize(journalEvents, new JsonSerializerOptions()
            {
                WriteIndented = true
            });

            if (loggingEnabled)
            {
                context.WriteLine($"Sent event:\n{json}");
            }

            var res = await SendEventsToCanonn(hc, configuration, json, context);

            switch (res.errorCode)
            {
            // These codes are OK
            case 200:
                break;

            // We're sending too many requests at once, let's break out of the loop and wait until next batch
            case 429:
                breakJournal = true;
                context.WriteLine("We're sending stuff too quickly, breaking out of the loop");
                context.WriteLine(lastLine);
                context.WriteLine(res.resultContent);

                await discordClient.SendMessageAsync("**[Canonn R&D Upload]** Rate limited by Canonn", new List <DiscordWebhookEmbed>
                {
                    new DiscordWebhookEmbed
                    {
                        Description = res.resultContent,
                        Fields      = new Dictionary <string, string>()
                        {
                            { "User identifier", userIdentifier.ToString() },
                            { "Last line", lastLine },
                            { "Journal", journalItem.S3Path },
                            { "Current GameState", JsonSerializer.Serialize(ijd.CurrentGameState, new JsonSerializerOptions {
                                    WriteIndented = true
                                }) }
                        }.Select(k => new DiscordWebhookEmbedField {
                            Name = k.Key, Value = k.Value
                        }).ToList()
                    }
                });

                await Task.Delay(30000);

                break;

            // Exceptions and debug
            case 500:     // Exception: %%
            case 501:     // %%
            case 502:     // Broken gateway
            case 503:
                breakJournal = true;
                context.WriteLine("We got an error from the service, breaking off!");
                context.WriteLine(lastLine);
                context.WriteLine(res.resultContent);

                await discordClient.SendMessageAsync("**[Canonn R&D Upload]** Error from the API", new List <DiscordWebhookEmbed>
                {
                    new DiscordWebhookEmbed
                    {
                        Description = res.resultContent,
                        Fields      = new Dictionary <string, string>()
                        {
                            { "User identifier", userIdentifier.ToString() },
                            { "Last line", lastLine },
                            { "Journal", journalItem.S3Path },
                            { "Current GameState", JsonSerializer.Serialize(ijd.CurrentGameState, new JsonSerializerOptions {
                                    WriteIndented = true
                                }) }
                        }.Select(k => new DiscordWebhookEmbedField {
                            Name = k.Key, Value = k.Value
                        }).ToList()
                    }
                });

                break;

            default:
                breakJournal = true;
                context.WriteLine("We got an error from the service, breaking off!");
                context.WriteLine(lastLine);
                context.WriteLine(res.resultContent);

                await discordClient.SendMessageAsync("**[Canonn R&D Upload]** Unhandled response code", new List <DiscordWebhookEmbed>
                {
                    new DiscordWebhookEmbed
                    {
                        Description = res.resultContent,
                        Fields      = new Dictionary <string, string>()
                        {
                            { "User identifier", userIdentifier.ToString() },
                            { "Last line", lastLine },
                            { "Journal", journalItem.S3Path },
                            { "Current GameState", JsonSerializer.Serialize(ijd.CurrentGameState, new JsonSerializerOptions {
                                    WriteIndented = true
                                }) }
                        }.Select(k => new DiscordWebhookEmbedField {
                            Name = k.Key, Value = k.Value
                        }).ToList()
                    }
                });

                break;
            }

            return(breakJournal);
        }