public static async Task InitializeJournalDownloadersAsync(PerformContext context) { context.WriteLine("Looking for journals do download!"); using (var scope = Startup.ServiceProvider.CreateScope()) { MSSQLDB db = scope.ServiceProvider.GetRequiredService<MSSQLDB>(); IConfiguration configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>(); var usersToDownloadJournalsFor = await db.ExecuteListAsync<Shared.Models.User.Profile>( @"SELECT * FROM user_profile WHERE DATEDIFF(MINUTE, GETUTCDATE(), CAST(JSON_VALUE(user_settings, '$.TokenExpiration') as DATETIMEOFFSET)) > 10 AND last_notification_mail IS NULL AND skip_download = 0 AND deleted = 0" ); if (usersToDownloadJournalsFor.Count > 0) { await SSEActivitySender.SendGlobalActivityAsync("Fetching journals from Elite", $"Downloading journals for {usersToDownloadJournalsFor.Count} users"); } foreach (var user in usersToDownloadJournalsFor) { if (RedisJobLock.IsLocked($"JournalDownloader.DownloadJournal.{user.UserIdentifier}")) continue; BackgroundJob.Schedule(() => JournalDownloader.DownloadJournalAsync(user.UserIdentifier, null), TimeSpan.Zero); } } context.WriteLine("All done!"); }
public static async Task DownloadJournalAsync(Guid userIdentifier, PerformContext context) { using (var rlock = new RedisJobLock($"JournalDownloader.DownloadJournal.{userIdentifier}")) { if (!rlock.TryTakeLock()) { return; } context.WriteLine($"Looking for journals for user {userIdentifier}"); using (var scope = Startup.ServiceProvider.CreateScope()) { MSSQLDB db = scope.ServiceProvider.GetRequiredService <MSSQLDB>(); IConfiguration configuration = scope.ServiceProvider.GetRequiredService <IConfiguration>(); MinioClient minioClient = scope.ServiceProvider.GetRequiredService <MinioClient>(); var discordClient = scope.ServiceProvider.GetRequiredService <DiscordWebhook>(); var user = await db.ExecuteSingleRowAsync <Profile>( @"SELECT * FROM user_profile WHERE user_identifier = @user_identifier AND last_notification_mail IS NULL AND deleted = 0 AND skip_download = 0", new SqlParameter("user_identifier", userIdentifier) ); if (user == null) { return; } var authToken = user.UserSettings.AuthToken; var hc = SharedSettings.GetHttpClient(scope); hc.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authToken); hc.BaseAddress = new Uri("https://companion.orerve.net"); var profile = await GetProfileAsync(hc); var profileJson = await profile.Content.ReadAsStringAsync(); if (!profile.IsSuccessStatusCode || string.IsNullOrWhiteSpace(profileJson)) { context.WriteLine($"Invalid statuscode: {profile.StatusCode} {profile.ReasonPhrase}"); bool resetAuth = false; switch (profile.StatusCode) { case HttpStatusCode.BadRequest: // User does not potentially own the game resetAuth = true; break; case HttpStatusCode.Unauthorized: // Invalid token (or Epic games) resetAuth = true; break; } if (string.IsNullOrWhiteSpace(profileJson)) { resetAuth = true; } if (resetAuth) { await SSEActivitySender.SendUserActivityAsync(user.UserIdentifier, "Could not authorize you", "Sorry, but there seems to be something wrong with your account. Please contact us so we can try and figure out what's wrong!" ); context.WriteLine("Bailing out early, user doesn't own Elite or has issues with cAPI auth"); if (!string.IsNullOrWhiteSpace(user.NotificationEmail)) { context.WriteLine("User cannot be fetched, asking them to reauthenticate"); await SendLoginNotificationMethod.SendLoginNotification(db, configuration, user); } } return; } var profileData = JsonSerializer.Deserialize <EliteProfile>(profileJson); context.WriteLine(profileJson); if (profileJson == "{}") { if (!string.IsNullOrWhiteSpace(user.NotificationEmail)) { context.WriteLine("User cannot be fetched, asking them to reauthenticate"); await SendLoginNotificationMethod.SendLoginNotification(db, configuration, user); } return; } context.WriteLine($"Downloading journals for {profileData.Commander.Name}"); DateTime journalDate = DateTime.Today.AddDays(-25); await SSEActivitySender.SendUserActivityAsync(user.UserIdentifier, "Downloading your journals", "We're beginning to download your journals now, a few notifications may pop up." ); while (journalDate.Date != DateTime.Today) { context.WriteLine($"Fetching data for {journalDate.ToString("yyyy-MM-dd")}"); var req = await TryGetJournalAsync(discordClient, journalDate, user, db, hc, minioClient, context); if (req.shouldBail) { // Failed to get loop journal context.WriteLine($"Bailing because of errors"); return; } journalDate = journalDate.AddDays(1); } context.WriteLine($"Fetching data for {journalDate.ToString("yyyy-MM-dd")}"); var reqOut = await TryGetJournalAsync(discordClient, journalDate, user, db, hc, minioClient, context); if (reqOut.shouldBail) { // Failed to get loop journal context.WriteLine($"Bailing because of errors"); return; } if (user.SendToEDDN && !RedisJobLock.IsLocked($"EDDNUserUploader.UploadAsync.{user.UserIdentifier}")) { var userJournals = await db.ExecuteScalarAsync <long>( "SELECT COUNT_BIG(journal_id) FROM user_journal WHERE user_identifier = @user_identifier AND sent_to_eddn = 0 AND last_processed_line_number >= sent_to_eddn_line", new SqlParameter("user_identifier", userIdentifier) ); if (userJournals > 0) { context.WriteLine($"Sending {userJournals} journals to EDDN"); BackgroundJob.Enqueue(() => EDDNUserUploader.UploadAsync(user.UserIdentifier, profileData.Commander.Name, null)); } } if (user.IntegrationSettings.ContainsKey("EDSM") && user.IntegrationSettings["EDSM"].GetTypedObject <EDSMIntegrationSettings>().Enabled) { var userJournals = await db.ExecuteScalarAsync <long>( "SELECT COUNT_BIG(journal_id) FROM user_journal WHERE user_identifier = @user_identifier AND ISNULL(JSON_VALUE(integration_data, '$.EDSM.lastSentLineNumber'), '0') < last_processed_line_number AND last_processed_line_number > 0 AND ISNULL(JSON_VALUE(integration_data, '$.EDSM.fullySent'), 'false') = 'false'", new SqlParameter("user_identifier", userIdentifier) ); if (userJournals > 0) { if (!RedisJobLock.IsLocked($"EDSMUserUploader.UploadAsync.{user.UserIdentifier}")) { context.WriteLine($"Sending {userJournals} journals to EDSM"); BackgroundJob.Enqueue(() => EDSMUserUploader.UploadAsync(user.UserIdentifier, null)); } } } if (user.IntegrationSettings.ContainsKey("Canonn R&D") && user.IntegrationSettings["Canonn R&D"].GetTypedObject <CanonnRDIntegrationSettings>().Enabled) { var userJournals = await db.ExecuteScalarAsync <long>( "SELECT COUNT_BIG(journal_id) FROM user_journal WHERE user_identifier = @user_identifier AND ISNULL(JSON_VALUE(integration_data, '$.\"Canonn R\\u0026D\".lastSentLineNumber'), '0') <= last_processed_line_number AND last_processed_line_number > 0 AND ISNULL(JSON_VALUE(integration_data, '$.\"Canonn R\\u0026D\".fullySent'), 'false') = 'false'", new SqlParameter("user_identifier", userIdentifier) ); if (userJournals > 0) { if (!RedisJobLock.IsLocked($"CanonnRDUserUploader.UploadAsync.{user.UserIdentifier}")) { context.WriteLine($"Sending {userJournals} journals to Canonn"); BackgroundJob.Enqueue(() => CanonnRDUserUploader.UploadAsync(user.UserIdentifier, profileData.Commander.Name, null)); } } } context.WriteLine("All done!"); } } }