sources/Google.Solutions.IapDesktop.Extensions.Session/Settings/ConnectionSettingsRepository.cs (145 lines of code) (raw):
//
// Copyright 2020 Google LLC
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
using Google.Solutions.Apis.Locator;
using Google.Solutions.Common.Util;
using Google.Solutions.IapDesktop.Application.Data;
using Google.Solutions.IapDesktop.Application.Profile.Settings;
using Google.Solutions.IapDesktop.Core.ObjectModel;
using Google.Solutions.Settings;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Google.Solutions.IapDesktop.Extensions.Session.Settings
{
/// <summary>
/// Registry-backed repository for connection settings.
///
/// To simplify key managent, a flat structure is used:
///
/// [base-key]
/// + [project-id] => values...
/// + region-[region-id] => values...
/// + zone-[zone-id] => values...
/// + vm-[instance-name] => values...
///
/// </summary>
[Service]
public class ConnectionSettingsRepository
{
private const string ZonePrefix = "zone-";
private const string VmPrefix = "vm-";
private readonly IProjectSettingsRepository projectRepository;
public ConnectionSettingsRepository(IProjectSettingsRepository projectRepository)
{
this.projectRepository = projectRepository.ExpectNotNull(nameof(projectRepository));
}
private ISettingsStore CreateProjectSettingsStore(ProjectLocator project)
{
var key = this.projectRepository.OpenRegistryKey(project.Name);
if (key == null)
{
throw new KeyNotFoundException(project.Name);
}
return new RegistrySettingsStore(key);
}
private ISettingsStore CreateZoneSettingsStore(ZoneLocator zone)
{
var key = this.projectRepository.OpenRegistryKey(
zone.ProjectId,
ZonePrefix + zone.Name);
//
// Return zone settings, applying project settings
// as defaults.
//
return new MergedSettingsStore(new[]
{
CreateProjectSettingsStore(zone.Project),
new RegistrySettingsStore(key)
},
MergedSettingsStore.MergeBehavior.Overlay);
}
private ISettingsStore CreateInstanceSettingsStore(InstanceLocator instance)
{
var key = this.projectRepository.OpenRegistryKey(
instance.ProjectId,
VmPrefix + instance.Name);
//
// Return instance settings, applying zone and
// project settings as defaults.
//
return new MergedSettingsStore(new[]
{
CreateProjectSettingsStore(instance.Project),
CreateZoneSettingsStore(new ZoneLocator(instance.ProjectId, instance.Zone)),
new RegistrySettingsStore(key)
},
MergedSettingsStore.MergeBehavior.Overlay);
}
private static void WriteAllSettings(
ISettingsStore store,
ConnectionSettings settings)
{
foreach (var setting in settings.Settings.Where(s => s.IsDirty))
{
store.Write(setting);
}
}
//---------------------------------------------------------------------
// Projects.
//---------------------------------------------------------------------
public ConnectionSettings GetProjectSettings(ProjectLocator project)
{
using (var store = CreateProjectSettingsStore(project))
{
return new ConnectionSettings(project, store);
}
}
public void SetProjectSettings(ConnectionSettings settings)
{
if (!(settings.Resource is ProjectLocator project))
{
throw new ArgumentException(nameof(settings));
}
using (var store = CreateProjectSettingsStore(project))
{
WriteAllSettings(store, settings);
}
}
//---------------------------------------------------------------------
// Zones.
//---------------------------------------------------------------------
public ConnectionSettings GetZoneSettings(ZoneLocator zone)
{
using (var store = CreateZoneSettingsStore(zone))
{
return new ConnectionSettings(zone, store);
}
}
public void SetZoneSettings(ConnectionSettings settings)
{
if (!(settings.Resource is ZoneLocator zone))
{
throw new ArgumentException(nameof(settings));
}
using (var store = CreateZoneSettingsStore(zone))
{
WriteAllSettings(store, settings);
}
}
//---------------------------------------------------------------------
// Virtual Machines.
//---------------------------------------------------------------------
public ConnectionSettings GetInstanceSettings(InstanceLocator instance)
{
using (var store = CreateInstanceSettingsStore(instance))
{
return new ConnectionSettings(instance, store);
}
}
public void SetInstanceSettings(ConnectionSettings settings)
{
if (!(settings.Resource is InstanceLocator instance))
{
throw new ArgumentException(nameof(settings));
}
using (var store = CreateInstanceSettingsStore(instance))
{
WriteAllSettings(store, settings);
}
}
public ConnectionSettings GetInstanceSettings(
IapRdpUrl url,
out bool foundInInventory)
{
//
// Populate an ephermeral settings store from the
// URL parameters.
//
using (var urlSettingStore = new IapRdpUrlSettingsStore(url))
{
try
{
//
// We have a full set of settings for this VM, so use
// that as basis and apply parameters from URL on top.
//
using (var storedSettingStore = CreateInstanceSettingsStore(url.Instance))
using (var mergedStore = new MergedSettingsStore(
new[] { storedSettingStore, urlSettingStore },
MergedSettingsStore.MergeBehavior.Overlay))
{
foundInInventory = true;
return new ConnectionSettings(url.Instance, mergedStore);
}
}
catch (KeyNotFoundException)
{
//
// Project not found in inventory, all we have is the URL.
//
foundInInventory = false;
return new ConnectionSettings(url.Instance, urlSettingStore);
}
}
}
}
}