Check if AWS Lambda function completed the job - c#

I am currently sending a file to be transcoded to my AWS lambda function. After I send the file, I send a notification to the SQS for some external aplication to start downloading the transcoded files.
The problem is, sometimes, the download of the files happen before the Lambda function completed.
How can I only send the notification to SQS after the Lambda completed.
I tried getting the Job.Status as follow, but not sure how to query it again if Status is not Complete.
Here is my code:
using (var eClient = new AmazonElasticTranscoderClient())
{
var response = await this.S3Client.GetObjectMetadataAsync(s3Event.Bucket.Name, s3Event.Object.Key);
var videoPresets = new List<Preset>();
var presetRequest = new ListPresetsRequest();
ListPresetsResponse presetResponse;
do
{
presetResponse = await eClient.ListPresetsAsync(presetRequest);
videoPresets.AddRange(presetResponse.Presets);
presetRequest.PageToken = presetResponse.NextPageToken;
} while (presetResponse.NextPageToken != null);
var pipelines = new List<Pipeline>();
var pipelineRequest = new ListPipelinesRequest();
ListPipelinesResponse pipelineResponse;
do
{
pipelineResponse = await eClient.ListPipelinesAsync(pipelineRequest);
pipelines.AddRange(pipelineResponse.Pipelines);
pipelineRequest.PageToken = pipelineResponse.NextPageToken;
} while (pipelineResponse.NextPageToken != null);
var pipeLine = s3Event.Bucket.Name.ToLower().Contains("test") ? pipelines.First(p => p.Name.ToLower().Contains("test")) : pipelines.First(p => !p.Name.ToLower().Contains("test"));
//HLS Stuff for Apple
var usablePreset = videoPresets.Where(p => p.Name.Contains("HLS") && !p.Name.Contains("HLS Video")).ToList();
var hlsPresets = new List<Preset>();
foreach (var preset in usablePreset)
{
var resolution = preset.Name.Replace("System preset: HLS ", "");
switch (resolution)
{
case "2M":
case "1M":
case "400k":
hlsPresets.Add(preset);
break;
}
}
var jobReq = new CreateJobRequest
{
PipelineId = pipeLine.Id,
Input = new JobInput() { Key = fileName, },
OutputKeyPrefix = outPutPrefix
//OutputKeyPrefix = "LambdaTest/" + playlistName + "/"
};
var outputs = new List<CreateJobOutput>();
var playlistHLS = new CreateJobPlaylist() { Name = "HLS_" + playlistName, Format = "HLSv3" };
foreach (var preset in hlsPresets)
{
var resolution = preset.Name.Replace("System preset: HLS ", "").Replace(".", "");
var newName = resolution + "_" + playlistName;
var output = new CreateJobOutput() { Key = newName, PresetId = preset.Id, SegmentDuration = "10" };
outputs.Add(output);
playlistHLS.OutputKeys.Add(newName);
}
jobReq.Playlists.Add(playlistHLS);
jobReq.Outputs = outputs;
//var temp = JsonConvert.SerializeObject(jobReq);
var reply = eClient.CreateJobAsync(jobReq);
var transcodingCompleted = reply.Result.Job.Status == "Complete" ? true : false;
do {
//somehow need to query status again
} while (!transcodingCompleted);
if (transcodingCompleted)
await SendAsync(jobReq.OutputKeyPrefix, pipeLine.OutputBucket);
}
The part I am interested in:
var reply = eClient.CreateJobAsync(jobReq);
var transcodingCompleted = reply.Result.Job.Status == "Complete" ? true : false;
do {
//somehow need to query status again
} while (!transcodingCompleted);
if (transcodingCompleted)
await SendAsync(jobReq.OutputKeyPrefix, pipeLine.OutputBucket);

Related

Importing files into SQLite database not using all cores

Context
I am importing IMDB database files into an SQLite database with the help of EntityFrameworkCore. In fact, two files, the titles.basics and the titles.akas (which is linked to basics via its movie ID).
At first, I had a single thread reading lines from basics and loop through akas until it changes of ID. Though, there was an issue there and most of all, it was too slow. So, I decided to create a multithread code that would read both files at the same time and another combining akas with the appropriate movie.
I am currently importing so I still do not know if my issue is fixed (probably it is). Though, it is still too much slow for me.
Issue
The combining part is still very slow, but more importantly, I can see my process is only using around 12% of CPU which corresponds to only 1/8 of total usage and I have 8 physical cores. So, it really seems the process is only using 1 core.
I am not giving any code here, as having a minimal testable code wouldn't mean anything. Though, you can see both versions here:
https://cints.net/public/Imdb-MultiThread.cs.txt
using com.cyberinternauts.all.MediaRecognizer.Database;
using com.cyberinternauts.all.MediaRecognizer.Models.Metas;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace com.cyberinternauts.all.MediaRecognizer.MetaSources
{
class Imdb : MediaSource
{
private const string TITLES_FILE = "title.basics.tsv.gz";
private const string AKAS_FILE = "title.akas.tsv.gz";
private readonly string temporaryFolder = #"c:\temp\";
private readonly string baseUrl = "https://datasets.imdbws.com/";
private readonly WebClient webClient = new();
MediaRecognizerContext db = new();
private IQueryable<MetaMovie> imdbMovies = null;
private async Task<bool> GatherFilesAsync()
{
var totalFilesGathered = 0;
var filesToDownload = new string[] { AKAS_FILE, TITLES_FILE };
foreach(var fileToDownload in filesToDownload)
{
var compressedFile = temporaryFolder + fileToDownload;
if (!File.Exists(compressedFile) || !File.GetLastWriteTime(compressedFile).Date.Equals(DateTime.Today))
{
await GatherFileAsync(fileToDownload);
totalFilesGathered++;
}
}
return totalFilesGathered != 0;
}
private async Task GatherFileAsync(string fileName)
{
var compressedFile = temporaryFolder + fileName;
var uncompressedFile = temporaryFolder + Path.GetFileNameWithoutExtension(compressedFile);
await webClient.DownloadFileTaskAsync(baseUrl + fileName, compressedFile);
using Stream fd = File.Create(uncompressedFile);
using Stream fs = File.OpenRead(compressedFile);
using Stream csStream = new GZipStream(fs, CompressionMode.Decompress);
var buffer = new byte[1024];
int nRead;
while ((nRead = await csStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fd.WriteAsync(buffer, 0, nRead);
}
}
private async Task LoadMetaDataAsync()
{
//return; //TODO: Remove this line
//TODO: Reactivate this line
//if (!await GatherFilesAsync()) return;
var titlesFile = temporaryFolder + Path.GetFileNameWithoutExtension(TITLES_FILE);
var akasFile = temporaryFolder + Path.GetFileNameWithoutExtension(AKAS_FILE);
var dbLock = new SemaphoreSlim(1);
var akasLock = new SemaphoreSlim(1);
var currentTitlesAkasLock = new SemaphoreSlim(1);
var associateLock = new SemaphoreSlim(1);
using (var db = new MediaRecognizerContext())
{
db.ChangeTracker.AutoDetectChangesEnabled = false;
var titles = new ConcurrentDictionary<string, MetaMovie>();
var readTitles = Task.Factory.StartNew(() =>
{
Parallel.ForEach(File.ReadLines(titlesFile), (titleLine, _, readingIndex) =>
{
if (readingIndex == 0) return; // Skipping columns titles line
var movieInfos = titleLine.Split("\t", StringSplitOptions.None);
dbLock.Wait();
MetaMovie metaMovie = db.MetaMovies.Where(m => m.ExternalId == movieInfos[0]).Include(m => m.Titles).FirstOrDefault();
dbLock.Release();
if (metaMovie == null)
{
int totalMinutes = -1;
if (!int.TryParse(movieInfos[7], out totalMinutes))
{
totalMinutes = -1;
}
metaMovie = new MetaMovie
{
ExternalId = movieInfos[0],
MetaSource = nameof(Imdb),
MovieType = movieInfos[1],
Title = movieInfos[3],
TotalMinutes = totalMinutes,
Genres = movieInfos[8]
};
metaMovie.Titles = new List<MetaTitle>();
if (int.TryParse(movieInfos[5], out int startYear))
{
metaMovie.StartYear = new DateTime(startYear, 1, 1);
}
else
{
metaMovie.StartYear = new DateTime(9999, 1, 1);
}
if (int.TryParse(movieInfos[6], out int endYear))
{
metaMovie.EndYear = new DateTime(endYear, 1, 1);
}
else
{
metaMovie.EndYear = metaMovie.StartYear;
}
}
titles.TryAdd(metaMovie.ExternalId, metaMovie);
});
});
var akas = new Dictionary<string, List<MetaTitle>>();
var currentTitlesAkas = new ConcurrentDictionary<string, int>();
var readAkas = Task.Factory.StartNew(() =>
{
Parallel.ForEach(File.ReadLines(akasFile), (akaLine, _, readingIndex) =>
{
if (readingIndex == 0) return; // Skipping columns titles line
currentTitlesAkasLock.Wait();
var titleInfos = akaLine.Split("\t", StringSplitOptions.None);
var externalId = titleInfos[0];
if (!currentTitlesAkas.ContainsKey(externalId))
{
currentTitlesAkas.TryAdd(externalId, 1);
}
else
{
currentTitlesAkas[externalId]++;
}
currentTitlesAkasLock.Release();
var metaTitle = new MetaTitle
{
MetaMovie = null,
Text = titleInfos[2],
Region = titleInfos[3],
Language = titleInfos[4]
};
akasLock.Wait();
List<MetaTitle> titleAkas;
if (!akas.ContainsKey(externalId))
{
titleAkas = new List<MetaTitle>();
akas.Add(externalId, titleAkas);
}
else
{
titleAkas = akas[externalId];
}
titleAkas.Add(metaTitle);
akasLock.Release();
currentTitlesAkasLock.Wait();
currentTitlesAkas[externalId]--;
currentTitlesAkasLock.Release();
});
});
var savingCounter = 0;
var associate = Task.Factory.StartNew(() =>
{
Parallel.For(1, Environment.ProcessorCount * 10, async (_) =>
{
var isAssociating = true;
do
{
var externalId = string.Empty;
var currentTitleAkaRemoved = false;
currentTitlesAkasLock.Wait();
foreach (var curExternalId in currentTitlesAkas.Keys.OrderBy(t => t))
{
if (currentTitlesAkas[curExternalId] == 0)
{
externalId = curExternalId;
break;
}
}
if (externalId != String.Empty)
{
currentTitleAkaRemoved = currentTitlesAkas.TryRemove(externalId, out int useless0); // Removing so other threads won't take it
}
isAssociating = !readAkas.IsCompleted || !readTitles.IsCompleted || !currentTitlesAkas.IsEmpty;
currentTitlesAkasLock.Release();
if (String.IsNullOrEmpty(externalId) || !currentTitleAkaRemoved) continue;
if (titles.TryGetValue(externalId, out MetaMovie metaMovie))
{
akasLock.Wait();
var titleAkas = akas[externalId];
akas.Remove(externalId);
akasLock.Release();
var changedMovie = false;
var movieAkas = metaMovie.Titles.Select(t => t).ToList(); // Clone list
foreach (var metaTitle in titleAkas)
{
var existingTitle = movieAkas.Where(t => t.Text == metaTitle.Text && t.Region == metaTitle.Region && t.Language == metaTitle.Language).FirstOrDefault();
if (existingTitle == null)
{
changedMovie = true;
metaMovie.Titles.Add(metaTitle);
}
else
{
movieAkas.Remove(existingTitle);
}
}
foreach (var movieTitle in movieAkas)
{
changedMovie = true;
metaMovie.Titles.Remove(movieTitle);
}
dbLock.Wait();
if (metaMovie.Id == 0)
{
db.Add(metaMovie);
}
else if (changedMovie)
{
db.Update(metaMovie);
}
dbLock.Release();
currentTitlesAkasLock.Wait();
currentTitlesAkas.TryRemove(externalId, out int uselessOut); // Free memory
isAssociating = !readAkas.IsCompleted || !readTitles.IsCompleted || !currentTitlesAkas.IsEmpty;
currentTitlesAkasLock.Release();
titles.TryRemove(externalId, out MetaMovie uselessOut2); // Free memory
associateLock.Wait();
savingCounter++;
var localSavingCounter = savingCounter;
associateLock.Release();
if (localSavingCounter != 0 && localSavingCounter % 1000 == 0)
{
var ttt = currentTitlesAkas.Where(t => t.Value > 0);
dbLock.Wait();
await db.SaveChangesAsync();
dbLock.Release();
Console.WriteLine("Saved " + localSavingCounter);
}
}
else if (!readTitles.IsCompleted) // If reading titles is not ended, then maybe it was not read yet... otherwise, it doesn't exist
{
currentTitlesAkasLock.Wait();
currentTitlesAkas.TryAdd(externalId, 0); // Readd because still no movie associated
currentTitlesAkasLock.Release();
}
} while (isAssociating);
});
});
Task.WaitAll(readTitles, readAkas, associate);
await db.SaveChangesAsync();
}
}
public async override Task<IEnumerable<MetaMovie>> FindMediasAsync(DirectoryInfo directory)
{
await LoadMetaDataAsync();
var movie = await ExtractInfosAsync(directory);
if (movie == null) return null;
if (imdbMovies == null)
{
imdbMovies = db.MetaMovies.Where(m => m.MetaSource == nameof(Imdb) && m.MovieType == "movie");
}
return FindCorrespondances(imdbMovies, movie);
}
}
}
https://cints.net/public/Imdb-SingleThread.cs.txt
using com.cyberinternauts.all.MediaRecognizer.Database;
using com.cyberinternauts.all.MediaRecognizer.Models.Metas;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace com.cyberinternauts.all.MediaRecognizer.MetaSources
{
class Imdb : MediaSource
{
private const string TITLES_FILE = "title.basics.tsv.gz";
private const string AKAS_FILE = "title.akas.tsv.gz";
private readonly string temporaryFolder = #"c:\temp\";
private readonly string baseUrl = "https://datasets.imdbws.com/";
private readonly WebClient webClient = new();
MediaRecognizerContext db = new();
private IQueryable<MetaMovie> imdbMovies = null;
private async Task<bool> GatherFilesAsync()
{
var totalFilesGathered = 0;
var filesToDownload = new string[] { AKAS_FILE, TITLES_FILE };
foreach(var fileToDownload in filesToDownload)
{
var compressedFile = temporaryFolder + fileToDownload;
if (!File.Exists(compressedFile) || !File.GetLastWriteTime(compressedFile).Date.Equals(DateTime.Today))
{
await GatherFileAsync(fileToDownload);
totalFilesGathered++;
}
}
return totalFilesGathered != 0;
}
private async Task GatherFileAsync(string fileName)
{
var compressedFile = temporaryFolder + fileName;
var uncompressedFile = temporaryFolder + Path.GetFileNameWithoutExtension(compressedFile);
await webClient.DownloadFileTaskAsync(baseUrl + fileName, compressedFile);
using Stream fd = File.Create(uncompressedFile);
using Stream fs = File.OpenRead(compressedFile);
using Stream csStream = new GZipStream(fs, CompressionMode.Decompress);
var buffer = new byte[1024];
int nRead;
while ((nRead = await csStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fd.WriteAsync(buffer, 0, nRead);
}
}
private async Task LoadMetaDataAsync()
{
//return; //TODO: Remove this line
//TODO: Reactivate this line
//if (!await GatherFilesAsync()) return;
var titlesFile = temporaryFolder + Path.GetFileNameWithoutExtension(TITLES_FILE);
var akasFile = temporaryFolder + Path.GetFileNameWithoutExtension(AKAS_FILE);
var titlesLines = File.ReadLines(titlesFile);
var akasLines = File.ReadLines(akasFile);
var titlesIterator = titlesLines.GetEnumerator();
titlesIterator.MoveNext(); // Skip columns headers
var akasIterator = akasLines.GetEnumerator();
akasIterator.MoveNext();
akasIterator.MoveNext(); // Done twice to skip columns headers
var currentAka = akasIterator.Current;
var savingCounter = 0;
using (var db = new MediaRecognizerContext())
{
db.ChangeTracker.AutoDetectChangesEnabled = false;
while (titlesIterator.MoveNext())
{
var titleLine = titlesIterator.Current;
var movieInfos = titleLine.Split("\t", StringSplitOptions.None);
MetaMovie metaMovie = db.MetaMovies.Where(m => m.ExternalId == movieInfos[0]).FirstOrDefault();
var isNewMovie = false;
if (metaMovie == null)
{
int totalMinutes = -1;
if (!int.TryParse(movieInfos[7], out totalMinutes))
{
totalMinutes = -1;
}
isNewMovie = true;
metaMovie = new MetaMovie
{
ExternalId = movieInfos[0],
MetaSource = nameof(Imdb),
MovieType = movieInfos[1],
Title = movieInfos[3],
TotalMinutes = totalMinutes,
Genres = movieInfos[8]
};
metaMovie.Titles = new List<MetaTitle>();
if (int.TryParse(movieInfos[5], out int startYear))
{
metaMovie.StartYear = new DateTime(startYear, 1, 1);
}
else
{
metaMovie.StartYear = new DateTime(9999, 1, 1);
}
if (int.TryParse(movieInfos[6], out int endYear))
{
metaMovie.EndYear = new DateTime(endYear, 1, 1);
}
else
{
metaMovie.EndYear = metaMovie.StartYear;
}
}
var movieAkasIds = metaMovie.Titles.Select(t => t.Id).ToList();
var titleInfos = currentAka?.Split("\t", StringSplitOptions.None);
while (currentAka != null && int.Parse(titleInfos[0][2..]) <= int.Parse(metaMovie.ExternalId[2..]))
{
if (titleInfos[0] == metaMovie.ExternalId)
{
var metaTitle = new MetaTitle
{
MetaMovie = metaMovie,
Text = titleInfos[2],
Region = titleInfos[3],
Language = titleInfos[4]
};
var existingTitle = metaMovie.Titles.Where(t => t.Text == metaTitle.Text && t.Region == metaTitle.Region && t.Language == metaTitle.Language).FirstOrDefault();
if (existingTitle == null)
{
metaMovie.Titles.Add(metaTitle);
}
else
{
movieAkasIds.Remove(existingTitle.Id);
}
}
else
{
var a = 1;
}
akasIterator.MoveNext();
currentAka = akasIterator.Current;
titleInfos = currentAka.Split("\t", StringSplitOptions.None);
}
foreach(var movieTitleId in movieAkasIds)
{
metaMovie.Titles.Remove(metaMovie.Titles.Where(t => t.Id == movieTitleId).FirstOrDefault());
}
if (isNewMovie)
{
db.Add(metaMovie);
}
else
{
db.Update(metaMovie);
}
savingCounter++;
if (savingCounter % 10000 == 0)
{
await db.SaveChangesAsync();
Console.WriteLine("Saved " + savingCounter);
}
}
await db.SaveChangesAsync();
}
}
public async override Task<IEnumerable<MetaMovie>> FindMediasAsync(DirectoryInfo directory)
{
await LoadMetaDataAsync();
var movie = await ExtractInfosAsync(directory);
if (movie == null) return null;
if (imdbMovies == null)
{
imdbMovies = db.MetaMovies.Where(m => m.MetaSource == nameof(Imdb) && m.MovieType == "movie");
}
return FindCorrespondances(imdbMovies, movie);
}
}
}
In the multithread version, the slow part is in the method LoadMetaDataAsync and more precisely in var associate = Task.Factory.StartNew(() => code part.
This is in development and cleaning, splitting will done after I have the appropriate result/speed.
Case closed. I returned to the single thread version and I found my initial issue (my code was supposing the files were in order, which they were partially).
Thank you for all people that participated.

Linq call to stored procedure returning to quickly

I'm attempting to call this method:
private async Task<int> RemoveAllCurrentEntries()
{
using (var ent = new WebPortalEntities())
{
// remove all existing price file entries based on a corporationid
var NewOrderIdOut = new SqlParameter(Settings.Default.CorporationId.ToString(),
System.Data.SqlDbType.UniqueIdentifier);
NewOrderIdOut.Direction = System.Data.ParameterDirection.Output;
return await ent.Database.ExecuteSqlCommandAsync(
"exec [dbo].[DeleteAllCorpCustomersFromCustomerPrice] #NewOrderIdOut output",
NewOrderIdOut);
}
}
From this method:
private async Task ExecutePriceFile()
{
try
{
var pricefile = Path.Combine(
Settings.Default.PriceFileDirectory,
Settings.Default.PriceFileName);
// verify file exists other no point in running the rest of the code
if (!File.Exists(pricefile)) return;
var parsedfile = ParsePriceFile(pricefile);
if (!parsedfile.Any()) return;
using (var ent = new WebnPortalEntities())
{
var deleteEntries = RemoveAllCurrentEntries();
if (deleteEntries == Task.CompletedTask)
{
foreach (var priceFile in parsedfile)
{
var pf = new CustomerPrice();
pf.CorporationId = Settings.Default.CorporationId;
pf.CustomerPriceId = Guid.NewGuid();
pf.AccountNumber = priceFile.AccountNumber;
pf.BranchNumber = priceFile.BranchNumber;
pf.BudgetBalance = priceFile.BudgetBalance;
pf.BudgetRate = priceFile.BudgetRate;
pf.ContractDepositQuantity = priceFile.ContractDepositQuantity;
pf.ContractGasPercent = priceFile.ContractGasPercent;
pf.ContractGasQuantity = priceFile.ContractGasQuantity;
pf.ContractGasTenths = priceFile.ContractGasTenths;
pf.CreditLimit = priceFile.CreditLimit;
pf.CurrentDate = priceFile.CurrentDate;
pf.CurrentDiscountDays = priceFile.CurrentDiscountDays;
pf.CurrentDiscountRate = priceFile.CurrentDiscountRate;
//pf.CurrentDiscountRate2 = columns[22].ToDecimal();
pf.CurrentDiscountRateDays = priceFile.CurrentDiscountRateDays;
pf.CurrentDiscountRateType = priceFile.CurrentDiscountType;
pf.CurrentDiscountType = priceFile.CurrentDiscountType;
// pf.CurrentPrice2 = columns[19];
pf.CurrentPrice = priceFile.CurrentPrice;
pf.LastPaymentDate = priceFile.LastPaymentDate;
pf.NonBudgetBalance = priceFile.NonBudgetBalance;
pf.OldestDiscountDays = priceFile.OldestDiscountDays;
pf.OldestDiscountRate = priceFile.OldestDiscountRate;
pf.OldestDiscountType = priceFile.OldestDiscountType;
pf.OldestPrice = priceFile.OldestPrice;
pf.PastDueBalance = priceFile.PastDueBalance;
pf.PaymentAmount = priceFile.PaymentAmount;
pf.PreviousDate = priceFile.PreviousDate;
pf.PreviousDiscountDays = priceFile.PreviousDiscountDays;
pf.PreviousDiscountRate = priceFile.PreviousDiscountRate;
pf.PreviousDiscountType = priceFile.PreviousDiscountType;
pf.PreviousPrice = priceFile.PreviousPrice;
pf.ProductCode = priceFile.ProductCode;
pf.IsActive = priceFile.Status.ToActive();
pf.UnitOfIssue = priceFile.UnitOfIssue;
ent.CustomerPrices.Add(pf);
}
ent.SaveChanges();
}
else
{
throw new Exception(deleteEntries.Result.ToString());
}
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
}
I'm not having the code wait until the task completes, it immediately returns and issues this message:
Id = 11, Status = WaitingForActivation, Method = "{null}", Result =
"{Not yet computed}"
I want it to wait until it's complete then return. Any ideas what I am doing wrong?
await RemoveAllCurrentEntries();
Or (if ur main function is not async)
Var _task = RemoveAllCurrentEntries();
_task.Wait();
Var result = _task.Result;

AndroidPublisherService - Play Developer API Client - Upload aab failes due to bad credentials

Trying to make use of the AndroidPublisherService from Play Developer API Client.
I can list active tracks and the releases in those tracks, but when I try to upload a new build there seems to be no way of attaching the authentication already made previously to read data.
I've authenticated using var googleCredentials = GoogleCredential.FromStream(keyDataStream) .CreateWithUser(serviceUsername); where serviceUsername is the email for my service account.
private static void Execute(string packageName, string aabfile, string credfile, string serviceUsername)
{
var credentialsFilename = credfile;
if (string.IsNullOrWhiteSpace(credentialsFilename))
{
// Check env. var
credentialsFilename =
Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS",
EnvironmentVariableTarget.Process);
}
Console.WriteLine($"Using credentials {credfile} with package {packageName} for aab file {aabfile}");
var keyDataStream = File.OpenRead(credentialsFilename);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = edit.Execute();
Console.WriteLine($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = tracksList.Execute();
foreach (var track in tracksResponse.Tracks)
{
Console.WriteLine($"Track: {track.TrackValue}");
Console.WriteLine("Releases: ");
foreach (var rel in track.Releases)
Console.WriteLine($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
using var fileStream = File.OpenRead(aabfile);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
var uploadProgress = upload.Upload();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
Console.WriteLine($"Upload {uploadProgress.Status}");
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = "Roswell - Grenis Dev Test",
Status = "completed",
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = tracksUpdate.Execute();
Console.WriteLine($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
Console.WriteLine($"{commitResult.EditId} has been committed");
}
And as the code points out, all action objects such as tracksList.Credential = credentials; can be given the credentials generated from the service account.
BUT the actual upload action var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream"); does not expose a .Credential object, and it always fails with:
The service androidpublisher has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project. [401]
Errors [
Message[Login Required.] Location[Authorization - header] Reason[required] Domain[global]
]
at Google.Apis.Upload.ResumableUpload`1.InitiateSessionAsync(CancellationToken cancellationToken)
at Google.Apis.Upload.ResumableUpload.UploadAsync(CancellationToken cancellationToken)
So, how would I go about providing the actual Upload action with the given credentials here?
Managed to figure this out during the day, I was missing one call to CreateScoped() when creating the GoogleCredential object as well as a call to InitiateSession() on the upload object.
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
Once that was done I could then get a valid oauth token by calling
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
And I can now use that oauth token in the upload request:
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
The full code example for successfully uploading a new aab file to google play store internal test track thus looks something like this:
private async Task UploadGooglePlayRelease(string fileToUpload, string changeLogFile, string serviceUsername, string packageName)
{
var serviceAccountFile = ResolveServiceAccountCertificateInfoFile();
if (!serviceAccountFile.Exists)
throw new ApplicationException($"Failed to find the service account certificate file. {serviceAccountFile.FullName}");
var keyDataStream = File.OpenRead(serviceAccountFile.FullName);
var googleCredentials = GoogleCredential.FromStream(keyDataStream)
.CreateWithUser(serviceUsername)
.CreateScoped(AndroidPublisherService.Scope.Androidpublisher);
var credentials = googleCredentials.UnderlyingCredential as ServiceAccountCredential;
var oauthToken = credentials?.GetAccessTokenForRequestAsync(AndroidPublisherService.Scope.Androidpublisher).Result;
var service = new AndroidPublisherService();
var edit = service.Edits.Insert(new AppEdit { ExpiryTimeSeconds = "3600" }, packageName);
edit.Credential = credentials;
var activeEditSession = await edit.ExecuteAsync();
_logger.LogInformation($"Edits started with id {activeEditSession.Id}");
var tracksList = service.Edits.Tracks.List(packageName, activeEditSession.Id);
tracksList.Credential = credentials;
var tracksResponse = await tracksList.ExecuteAsync();
foreach (var track in tracksResponse.Tracks)
{
_logger.LogInformation($"Track: {track.TrackValue}");
_logger.LogInformation("Releases: ");
foreach (var rel in track.Releases)
_logger.LogInformation($"{rel.Name} version: {rel.VersionCodes.FirstOrDefault()} - Status: {rel.Status}");
}
var fileStream = File.OpenRead(fileToUpload);
var upload = service.Edits.Bundles.Upload(packageName, activeEditSession.Id, fileStream, "application/octet-stream");
upload.OauthToken = oauthToken;
_ = await upload.InitiateSessionAsync();
var uploadProgress = await upload.UploadAsync();
if (uploadProgress == null || uploadProgress.Exception != null)
{
Console.WriteLine($"Failed to upload. Error: {uploadProgress?.Exception}");
return;
}
_logger.LogInformation($"Upload {uploadProgress.Status}");
var releaseNotes = await File.ReadAllTextAsync(changeLogFile);
var tracksUpdate = service.Edits.Tracks.Update(new Track
{
Releases = new List<TrackRelease>(new[]
{
new TrackRelease
{
Name = $"{upload?.ResponseBody?.VersionCode}",
Status = "completed",
InAppUpdatePriority = 5,
CountryTargeting = new CountryTargeting { IncludeRestOfWorld = true },
ReleaseNotes = new List<LocalizedText>(new []{ new LocalizedText { Language = "en-US", Text = releaseNotes } }),
VersionCodes = new List<long?>(new[] {(long?) upload?.ResponseBody?.VersionCode})
}
})
}, packageName, activeEditSession.Id, "internal");
tracksUpdate.Credential = credentials;
var trackResult = await tracksUpdate.ExecuteAsync();
_logger.LogInformation($"Track {trackResult?.TrackValue}");
var commitResult = service.Edits.Commit(packageName, activeEditSession.Id);
commitResult.Credential = credentials;
await commitResult.ExecuteAsync();
_logger.LogInformation($"{commitResult.EditId} has been committed");
}

if else conditions not checking properly in c#?

I am coming to a problem where I am checking if some of the elements key values are valid in order to proceed with the QR code scanning. For example: If my Active attribute is true, and completed is false and the schedule time is current time +- 30 minutes of start window then proceed with the scanning. If not, let me show them an error. I tried implementing the checking part with a simple if - but only checking the active, and completed key values. Can anyone check and help me solve this issue. thanks for the help.
here is my code:
public void ScanQrCode()
{
BarcodeScanner.Scan(async (barCodeType, barCodeValue) =>
{
BarcodeScanner.Stop();
var results = JsonConvert.DeserializeObject<dynamic>(barCodeValue);
var gettingTheName = (string) results.Evaluation.Value;
TextHeader.text = gettingTheName;
var qrCodeString = $"***************.firebaseio.com/Evaluations/.json?orderBy=\"$key\"&startAt=\"{gettingTheName}\"&limitToFirst=1";
Debug.Log(barCodeValue);
var qrCodeObj = JsonConvert.DeserializeObject<dynamic>(qrCodeString);
try
{
bool parseSuccessful = DateTime.TryParse("ScheduleStartTime", out var scheduledStartTime);
if (results.Contains("Active").Equals(true) &&
results.Contains("Completed").Equals(false) &&
DateTime.Now < scheduledStartTime.AddMinutes(30) &&
DateTime.Now > scheduledStartTime.AddMinutes(-30)) {
var matchingLink = new WebClient().DownloadString(qrCodeString);
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(matchingLink);
var candidateId = obj.First.First["CandiateID"].ToString();
string page = $"https://***********.firebaseio.com/Candidates/.json?orderBy=\"$key\"&startAt=\"{candidateId}\"&limitToFirst=1";
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(page))
using (HttpContent content = response.Content)
{
// Reading the string.
Dictionary<string, Candidates> evaluationDictionary = new Dictionary<string, Candidates>();
string result = await content.ReadAsStringAsync();
evaluationDictionary = JsonConvert.DeserializeObject<Dictionary<string, Candidates>>(result);
Debug.Log(evaluationDictionary);
foreach (Candidates candidates in evaluationDictionary.Values)
{
string evaluationMessage = candidates.FirstName + " " + candidates.LastName;
candidateMessage = GetComponent<Text>();
candidateMessage.text = evaluationMessage;
}
// Getting a reference to the text component.
candidateMessage = GetComponent<Text>();
candidateMessage.text = matchingLink.ToString();
candidateMessage.text = matchingLink.Trim(new char[] {'"'});
}
}
else
{
EditorUtility.DisplayDialog("Incorrect credentials", "Please scan a valid QR code", "OK");
}
}
catch (Exception e)
{
Console.WriteLine(e);
SceneManager.LoadScene("Verify");
throw;
}
});
}
}
JSON:
{
"Active": true,
"Completed": false,
"ScheduleStartTime": "2019-12-16T20:10:57.649418-08:00"
}
Yeah. I was kind of stuck on that part too. I tried doing it by adding
&& qrCodeString.Contains("ScheduleStartTime").Equals(I GOT STUCK IN
HERE)
I'd accomplish this portion by parsing the date string to a DateTime object, then comparing the current time with your new DateTime shifted in both directions.
I might do something like this:
try {
bool parseSuccessful = DateTime.TryParse( ScheduledStartTimeFromJSON, out var scheduledStartTime );
if ( qrCodeString.Contains( "Active" ).Equals( true ) &&
qrCodeString.Contains( "CompletedMessage" ).Equals( false ) &&
DateTime.Now < scheduledStartTime.AddMinutes(30) &&
DateTime.Now > scheduledStartTime.AddMinutes( -30 ) ) {
var matchingLink = new WebClient().DownloadString( qrCodeString );
...
}
}
You should also check to make sure the date was parsed successfully before comparing it to anything.
According to your JSON example:
First i think you should check for Completed value insted of CompletedMessage.
Secound with this code qrCodeString.Contains("Active").Equals(true) you are just checking if Active is contained in the string. I think you should be looking for the value of it.
In my vision the right way to do the check you need is to first deserialize the JSON like this
var qrCodeObj = JsonConvert.DeserializeObject<dynamic>(qrCodeString);
And then check for the respectives values
if (qrCodeObj["Active"] == true && qrCodeObj["Completed"] == false)
{
var matchingLink = new WebClient().DownloadString(qrCodeString);
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject (matchingLink);
var candidateId = obj.First.First["CandiateID"].ToString();
string page = $"https://*********.firebaseio.com/Candidates/.json?orderBy=\"$key\"&startAt=\"{candidateId}\"&limitToFirst=1";
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(page))
using (HttpContent content = response.Content)
{
// Reading the string.
Dictionary<string, Candidates> evaluationDictionary = new Dictionary<string, Candidates>();
string result = await content.ReadAsStringAsync();
evaluationDictionary = JsonConvert.DeserializeObject<Dictionary<string, Candidates>>(result);
Debug.Log(evaluationDictionary);
foreach (Candidates candidates in evaluationDictionary.Values)
{
string evaluationMessage = candidates.FirstName + " " + candidates.LastName;
candidateMessage = GetComponent<Text>();
candidateMessage.text = evaluationMessage;
}
// Getting a reference to the text component.
candidateMessage = GetComponent<Text>();
candidateMessage.text = matchingLink.ToString();
candidateMessage.text = matchingLink.Trim(new char[] {'"'});
}
}
else
{
EditorUtility.DisplayDialog("Incorrect Credentials ",
"Please scan a valid QR code. " , "OK");
}

call back query data from inline keyboard

I'm trying to get the data from an inline keyboard, I've searched a lot but unfortunately didn't get my answer and non of codes worked for me. Here's my code please help me
static void Main(string[] args){
InlineKeyboardButton[][] buttons =
new InlineKeyboardButton[][]{
new InlineKeyboardButton[]{newInlineKeyboardButton() { Text = "show Channel", CallbackData = "Data1" }},
new InlineKeyboardButton[]{new InlineKeyboardButton() { Text = "show Website", CallbackData = "Data2" }}};
inlineKeyboardMarkup = new InlineKeyboardMarkup() { InlineKeyboard = buttons };
Task.Run(() => RunBot());
Console.ReadLine();
} // End of main method
public static async Task RunBot(){
while (true){
var u = await bot.MakeRequestAsync(new GetUpdates() { Offset
= offset });
foreach (var update in u)
{
offset = update.UpdateId + 1;
var text = update.Message.Text;
// here I want to get the data like this, but it doesn't work
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
switch(text){
case "Something":{
var req = new SendMessage(update.Message.Chat.Id, "راهنما") { ReplyMarkup = inlineKeyboardMarkup };
await bot.MakeRequestAsync(req);
break;
}
}
}
}
}
you must replace this
if (update.ChosenInlineResult != null){
Console.WriteLine("Chosen Inline Result: " +
update.ChosenInlineResult.ToString());
}
with something like This :
if (update.CallbackQuery != null)
{
Console.WriteLine(val.CallbackQuery.Message+"-"+val.CallbackQuery.Data);
}

Categories