in sources/Google.Solutions.IapDesktop.Core/ResourceModel/ProjectWorkspace.cs [127:284]
private static async Task<State> LoadStateAsync(
IProjectWorkspaceSettings context,
IAncestryCache ancestryCache,
IResourceManagerClient resourceManager,
CancellationToken cancellationToken)
{
//
// NB. The Compute Engine project.get resource does not include the
// project name, so we have to use the Resource Manager API instead.
//
var getProjectTasks = context
.Projects
.EnsureNotNull()
.Select(p => new {
Locator = p,
Task = resourceManager.GetProjectAsync(p, cancellationToken)
})
.ToList();
var projects = new List<ProjectWithAncestry>();
foreach (var task in getProjectTasks)
{
//
// NB. Some projects might not be accessible anymore,
// either because they have been deleted or the user
// lost access.
//
try
{
var project = new ProjectWithAncestry(task.Locator)
{
CrmProject = await task.Task.ConfigureAwait(false)
};
projects.Add(project);
//
// Add cached ancestry, if available.
//
ancestryCache.TryGetAncestry(project.Locator, out project.OrganizationLocator);
CoreTraceSource.Log.TraceVerbose(
"Successfully loaded project {0}", project.Locator);
}
catch (Exception e) when (e.IsReauthError())
{
//
// Propagate reauth errors so that the reauth logic kicks in.
//
throw e.Unwrap();
}
catch (Exception e)
{
//
// Add as inaccessible project and continue.
//
projects.Add(new ProjectWithAncestry(task.Locator));
CoreTraceSource.Log.TraceError(
"Failed to load project {0}: {1}",
task.Locator,
e);
}
}
Debug.Assert(projects.Count == getProjectTasks.Count);
//
// At this point, we have all projects, but we might not know the
// org ID for all projects yet.
//
var findOrgIdsTasks = projects
.Where(p => p.IsAccessible && p.OrganizationLocator == null)
.Select(p => new {
Project = p,
Task = resourceManager.FindOrganizationAsync(
p.Locator,
cancellationToken)
})
.ToList();
foreach (var task in findOrgIdsTasks)
{
//
// Amend ancestry (if available).
//
task.Project.OrganizationLocator = await task.Task.ConfigureAwait(false);
if (task.Project.OrganizationLocator != null)
{
//
// Cache ancestry information to speed up future lookups.
//
ancestryCache.SetAncestry(task.Project.Locator, task.Project.OrganizationLocator);
}
}
//
// Finally, resolve all org IDs.
//
var findOrgTasks = projects
.Where(p => p.OrganizationLocator != null)
.Select(p => p.OrganizationLocator)
.Distinct()
.Select(loc => new {
Organization = loc!,
Task = resourceManager.GetOrganizationAsync(loc!, cancellationToken)
})
.ToList();
var organizations = new Dictionary<OrganizationLocator, Organization>();
foreach (var task in findOrgTasks)
{
try
{
var org = await task.Task.ConfigureAwait(false);
organizations[task.Organization] = new Organization(
task.Organization,
org.DisplayName);
}
catch (Exception e) when (e.IsReauthError())
{
//
// Propagate reauth errors so that the reauth logic kicks in.
//
throw e.Unwrap();
}
catch
{
//
// Organization inaccessible (even though we do have its ID),
// use default.
//
organizations[task.Organization] = Organization.Default;
}
}
if (projects.Any(p => p.OrganizationLocator == null))
{
//
// Include default org.
//
organizations[Organization.Default.Locator] = Organization.Default;
}
return new State(
organizations,
projects.ToDictionary(
p => p.Locator,
p => new Project(
p.OrganizationLocator ?? Organization.Default.Locator,
p.Locator,
p.CrmProject != null
? p.CrmProject.Name // Actual name.
: p.Locator.Name, // Project inaccessible, use ID.
p.CrmProject != null)));
}