sources/Google.Solutions.IapDesktop.Extensions.Session/InitializeSessionExtension.cs (214 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.Diagnostics;
using Google.Solutions.IapDesktop.Application;
using Google.Solutions.IapDesktop.Application.Data;
using Google.Solutions.IapDesktop.Application.Host;
using Google.Solutions.IapDesktop.Application.ToolWindows.ProjectExplorer;
using Google.Solutions.IapDesktop.Application.Windows;
using Google.Solutions.IapDesktop.Application.Windows.Dialog;
using Google.Solutions.IapDesktop.Core.ClientModel.Protocol;
using Google.Solutions.IapDesktop.Core.ClientModel.Traits;
using Google.Solutions.IapDesktop.Core.ObjectModel;
using Google.Solutions.IapDesktop.Core.ProjectModel;
using Google.Solutions.IapDesktop.Extensions.Session.Protocol;
using Google.Solutions.IapDesktop.Extensions.Session.Protocol.App;
using Google.Solutions.IapDesktop.Extensions.Session.Settings;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.App;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.Settings;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.Credentials;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.Session;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.SshKeys;
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.Tunnels;
using Google.Solutions.Mvvm.Binding.Commands;
using System;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Google.Solutions.Common.Linq;
#if DEBUG
using Google.Solutions.IapDesktop.Extensions.Session.ToolWindows.Diagnostics;
#endif
namespace Google.Solutions.IapDesktop.Extensions.Session
{
/// <summary>
/// Main class of the extension, instantiated on load.
/// </summary>
[Service(ServiceLifetime.Singleton, DelayCreation = false)]
public class InitializeSessionExtension
{
private readonly IServiceProvider serviceProvider;
/// <summary>
/// Load the default app protocols embedded into the assembly.
/// </summary>
internal static async Task LoadAndRegisterDefaultAppProtocolsAsync(
ProtocolRegistry protocolRegistry)
{
var assembly = typeof(InitializeSessionExtension).Assembly;
var loadTasks = assembly
.GetManifestResourceNames()
.Where(s => s.EndsWith(AppProtocolConfigurationFile.FileExtension))
.Select(async resourceName =>
{
using (var stream = assembly.GetManifestResourceStream(resourceName))
{
var protocol = await AppProtocolConfigurationFile
.ReadStreamAsync(stream)
.ConfigureAwait(false);
protocolRegistry.RegisterProtocol(protocol);
}
})
.ToList();
await Task
.WhenAll(loadTasks)
.ConfigureAwait(false);
}
/// <summary>
/// Load user-defined app protocols from the file system.
/// </summary>
internal static async Task LoadAndRegisterCustomAppProtocolsAsync(
string protocolsPath,
ProtocolRegistry protocolRegistry)
{
if (!Directory.Exists(protocolsPath))
{
return;
}
//
// Load and register custom app protocols in parallel.
//
var loadTasks = new DirectoryInfo(protocolsPath)
.GetFiles($"*{AppProtocolConfigurationFile.FileExtension}")
.EnsureNotNull()
.Select(async file =>
{
try
{
ApplicationTraceSource.Log.TraceInformation(
"Loading protocol configuration from {0}...", file.Name);
var protocol = await AppProtocolConfigurationFile
.ReadFileAsync(file.FullName)
.ConfigureAwait(false);
protocolRegistry.RegisterProtocol(protocol);
}
catch (Exception e)
{
ApplicationTraceSource.Log.TraceError(
"Loading protocol configuration from {0} failed", file.Name);
ApplicationTraceSource.Log.TraceError(e);
throw;
}
})
.ToList();
await Task
.WhenAll(loadTasks)
.ConfigureAwait(false);
}
private async Task LoadAndRegisterAppProtocolsAsync(
IWin32Window window,
ProtocolRegistry protocolRegistry)
{
try
{
var protocolsPath = Path.Combine(
this.serviceProvider.GetService<IInstall>().BaseDirectory,
"Config");
await Task
.WhenAll(
LoadAndRegisterDefaultAppProtocolsAsync(protocolRegistry),
LoadAndRegisterCustomAppProtocolsAsync(
protocolsPath,
protocolRegistry))
.ConfigureAwait(true); // Back to UI thread (for exception dialog).
}
catch (Exception e)
{
//
// Show error message, but resume startup.
//
this.serviceProvider
.GetService<IExceptionDialog>()
.Show(window, "Invalid protocol configuration", e);
}
}
//---------------------------------------------------------------------
// Setup
//---------------------------------------------------------------------
public InitializeSessionExtension(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
var mainForm = serviceProvider.GetService<IMainWindow>();
//
// Register protocols.
//
var protocolRegistry = serviceProvider.GetService<ProtocolRegistry>();
protocolRegistry.RegisterProtocol(
new AppProtocol(
"SQL Server Management Studio",
Enumerable.Empty<ITrait>(),
Ssms.DefaultServerPort,
null,
new SsmsClient()));
_ = LoadAndRegisterAppProtocolsAsync(mainForm, protocolRegistry);
//
// Let this extension handle all URL activations.
//
var connectCommands = new ConnectCommands(
serviceProvider.GetService<UrlCommands>(),
serviceProvider.GetService<ISessionContextFactory>(),
serviceProvider.GetService<IProjectWorkspace>(),
serviceProvider.GetService<ISessionFactory>(),
serviceProvider.GetService<ISessionBroker>());
Debug.Assert(serviceProvider
.GetService<UrlCommands>()
.LaunchRdpUrl.QueryState(new IapRdpUrl(
new InstanceLocator("project", "zone", "name"),
new NameValueCollection())) == CommandState.Enabled,
"URL command installed");
//
// Connect.
//
var projectExplorer = serviceProvider.GetService<IProjectExplorer>();
projectExplorer.ContextMenuCommands.AddCommand(
connectCommands.ContextMenuActivateOrConnectInstance,
0);
projectExplorer.ContextMenuCommands.AddCommand(
connectCommands.ContextMenuConnectRdpAsUser,
1);
projectExplorer.ContextMenuCommands.AddCommand(
connectCommands.ContextMenuConnectSshInNewTerminal,
2);
//
// App commands.
//
var appCommands = serviceProvider.GetService<AppCommands>();
var connectWithClientCommands = projectExplorer.ContextMenuCommands.AddCommandGroup(
appCommands.ContextMenuConnectWithClient,
3);
var connectTunnelCommands = projectExplorer.ContextMenuCommands.AddCommandGroup(
appCommands.ContextMenuConnectTunnel,
4);
projectExplorer.ToolbarCommands.AddCommand(
connectCommands.ToolbarActivateOrConnectInstance);
//
// Generate credentials (Windows/RDP only).
//
var credentialCommands = new CredentialCommands(
serviceProvider.GetService<IConnectionSettingsService>(),
serviceProvider.GetService<IRdpCredentialEditorFactory>());
projectExplorer.ContextMenuCommands.AddCommand(
credentialCommands.ContextMenuNewCredentials,
5);
projectExplorer.ToolbarCommands.AddCommand(
credentialCommands.ToolbarNewCredentials);
//
// Connection settings.
//
var connectionSettingsCommands = serviceProvider.GetService<ConnectionSettingsCommands>();
projectExplorer.ContextMenuCommands.AddCommand(
connectionSettingsCommands.ContextMenuOpen,
6);
projectExplorer.ToolbarCommands.AddCommand(
connectionSettingsCommands.ToolbarOpen,
3);
//
// Authorized keys.
//
var authorizedKeyCommands = serviceProvider.GetService<AuthorizedPublicKeysCommands>();
projectExplorer.ContextMenuCommands.AddCommand(
authorizedKeyCommands.ContextMenuOpen,
11);
#if DEBUG
projectExplorer.ContextMenuCommands.AddCommand(
serviceProvider.GetService<DiagnosticsCommands>().GenerateHtmlPage);
#endif
//
// View menu.
//
var tunnelsViewCommands = serviceProvider.GetService<TunnelsViewCommands>();
mainForm.ViewMenu.AddCommand(
tunnelsViewCommands.WindowMenuOpen,
1);
mainForm.ViewMenu.AddCommand(authorizedKeyCommands.WindowMenuOpen);
//
// Session menu.
//
var sessionBroker = serviceProvider.GetService<ISessionBroker>();
var sessionCommands = new SessionCommands(sessionBroker);
var menu = sessionBroker.SessionMenu;
menu.AddCommand(sessionCommands.EnterFullScreenOnSingleScreen);
menu.AddCommand(sessionCommands.EnterFullScreenOnAllScreens);
menu.AddCommand(connectCommands.DuplicateSession);
menu.AddSeparator();
menu.AddCommand(sessionCommands.TransferFiles);
menu.AddCommand(sessionCommands.TypeClipboardText);
menu.AddCommand(sessionCommands.ShowSecurityScreen);
menu.AddCommand(sessionCommands.ShowTaskManager);
menu.AddSeparator();
menu.AddCommand(sessionCommands.Logoff);
menu.AddCommand(sessionCommands.Reconnect);
menu.AddSeparator();
menu.AddCommand(sessionCommands.Close);
menu.AddCommand(sessionCommands.CloseAll);
menu.AddCommand(sessionCommands.CloseAllButThis);
}
}
}