using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace Tango.SharedUI.Components
{
/// <summary>
/// Represents an MVVM TextBox controller
/// </summary>
/// <seealso cref="System.Windows.DependencyObject" />
public class TextController : DependencyObject
{
private TextBox _textBox;
private bool _isMouseDown;
/// <summary>
/// Determines whether an element is Controller.
/// </summary>
public static readonly DependencyProperty ControllerProperty =
DependencyProperty.RegisterAttached("Controller",
typeof(TextController), typeof(TextController),
new FrameworkPropertyMetadata(null,ControllerChanged));
/// <summary>
/// On controller changed.
/// </summary>
/// <param name="d">The d.</param>
/// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
/// <exception cref="System.ArgumentException">The text controller component can only handle elements of type TextBox.</exception>
private static void ControllerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d != null && e.NewValue != null)
{
if (!(d is TextBox))
{
throw new ArgumentException("The text controller component can only handle elements of type TextBox.");
}
(e.NewValue as TextController).pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */using FluentFTP;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Entities;
using Tango.Core;
using Tango.Core.DB;
using Tango.Core.ExtensionMethods;
using Tango.Core.Helpers;
using Tango.Core.IO;
using Tango.Integration.Operation;
using Tango.Logging;
using Tango.PMR.Synchronization;
using Tango.PPC.Common.Application;
using Tango.PPC.Common.Connection;
using Tango.PPC.Common.OS;
using Tango.PPC.Common.RemoteAssistance;
using Tango.PPC.Common.UWF;
using Tango.PPC.Common.Web;
using Tango.Settings;
using Tango.SharedUI.Helpers;
using Tango.SQLExaminer;
using Tango.Transport.Web;
using System.Data.Entity;
namespace Tango.PPC.Common.MachineSetup
{
/// <summary>
/// Represents the PPC machine setup manager.
/// </summary>
/// <seealso cref="Tango.Core.ExtendedObject" />
/// <seealso cref="Tango.PPC.Common.MachineSetup.IMachineSetupManager" />
public class MachineSetupManager : ExtendedObject, IMachineSetupManager
{
private IRemoteAssistanceProvider _remoteAssistance;
private IUnifiedWriteFilterManager _uwf;
private IOperationSystemManager _windows_manager;
private PPCWebClient _client;
private List<LogItemBase> _logs;
private bool _isUpdating;
private DateTime _setupStartDate;
#region Events
/// <summary>
/// Occurs when there is a text log message available.
/// </summary>
public event EventHandler<string> ProgressLog;
/// <summary>
/// Occurs when the <see cref="CurrentStep" /> has changed.
/// </summary>
public event EventHandler<MachineSetupProgress> Progress;
#endregion
#region Properties
private MachineSetupProgress _status;
public MachineSetupProgress Status
{
get { return _status; }
private set { _status = value; RaisePropertyChangedAuto(); }
}
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="MachineSetupManager"/> class.
/// </summary>
/// <param name="remoteAssistance">The remote assistance.</param>
public MachineSetupManager(PPCWebClient ppcWebClient, IRemoteAssistanceProvider remoteAssistance, IUnifiedWriteFilterManager unifiedWriterFilterManager, IOperationSystemManager operationSystemManager)
{
_client = ppcWebClient;
_remoteAssistance = remoteAssistance;
_uwf = unifiedWriterFilterManager;
_windows_manager = operationSystemManager;
_logs = new List<LogItemBase>();
LogManager.NewLog += LogManager_NewLog;
}
#endregion
#region Event Handlers
private void LogManager_NewLog(object sender, LogItemBase e)
{
if (_isUpdating)
{
_logs.Add(e);
}
}
#endregion
#region Private Methods
private Task Login(String serialNumber)
{
return Task.Factory.StartNew(() =>
{
return _client.Login(new LoginRequest()
{
Mode = LoginMode.Machine,
SerialNumber = serialNumber,
}).Result;
});
}
private async void OnFailed(Exception ex, TaskCompletionSource<MachineSetupResult> completionSource, MachineSetupResponse response)
{
LogManager.Log(ex, "An error occurred in machine setup.");
completionSource.SetException(ex);
if (response != null)
{
try
{
var result = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.SetupFailed,
FailedReason = ex.FlattenMessage(),
FailedLog = GetLogsStringAndClear(),
});
}
catch (Exception xx)
{
LogManager.Log(xx, "Error notifying setup completed.");
}
}
_isUpdating = false;
}
private async void OnCompleted(MachineSetupResult result, TaskCompletionSource<MachineSetupResult> completionSource, MachineSetupResponse response)
{
completionSource.SetResult(result);
if (response != null)
{
try
{
var r = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.SetupCompleted,
});
}
catch (Exception xx)
{
LogManager.Log(xx, "Error notifying setup completed.");
}
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = response.Version;
update.FirmwareVersion = response.FirmwareVersion;
update.MachineGuid = (await db.Machines.FirstAsync()).Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.SetupCompleted;
update.StartDate = _setupStartDate;
update.EndDate = DateTime.UtcNow;
await db.SaveChangesAsync();
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error saving tango setup information to database.");
}
}
_isUpdating = false;
}
private String GetLogsStringAndClear()
{
String logsString = String.Join(Environment.NewLine, _logs.ToList().Select(x => x.ToString()));
_logs.Clear();
return logsString;
}
#endregion
#region Public Methods
/// <summary>
/// Performs a machine setup using the specified serial number and machine service address.
/// </summary>
/// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
public async Task<MachineSetupResult> Setup(string serialNumber)
{
_logs.Clear();
TaskCompletionSource<MachineSetupResult> result = new TaskCompletionSource<MachineSetupResult>();
MachineSetupResponse setup_response = null;
_setupStartDate = DateTime.UtcNow;
try
{
_isUpdating = true;
LogManager.Log($"Starting machine setup for serial number {serialNumber}...");
var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress();
IMachineOperator op = null;
var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
//Connect to machine service and get matching packages for this machine.
UpdateProgress("Validating serial number", "Connecting to machine service...");
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
Login(serialNumber).Wait();
String deviceName = $"Tango-{serialNumber}-{settings.DeploymentSlot.ToString()}";
LogManager.Log($"Settings device name: '{deviceName}'...");
try
{
await _windows_manager.SetDeviceName(deviceName);
}
catch
{
throw new IOException("Error setting device name.");
}
MachineSetupRequest request = new MachineSetupRequest();
request.SerialNumber = serialNumber;
request.DeviceID = await _windows_manager.GetDeviceId();
request.DeviceName = deviceName;
try
{
LogManager.Log($"Sending setup request...\n{request.ToJsonString()}");
setup_response = await _client.MachineSetup(request);
}
catch (Exception ex)
{
throw LogManager.Log(ex, $"An error occurred while trying to contact machine service: {ex.FlattenMessage()}");
}
LogManager.Log($"Machine setup response received: {Environment.NewLine}{setup_response.ToJsonString()}");
if (!String.IsNullOrWhiteSpace(setup_response.DeviceComPort))
{
settings.EmbeddedComPort = setup_response.DeviceComPort;
settings.Save();
}
if (setup_response.SetupFirmware)
{
//Connecting to machine...
LogManager.Log("Initiating machine connection...");
UpdateProgress("Connecting to machine", "Connecting...");
op = await DefaultMachineProvider.CreateMinimalMachineOperator((msg) =>
{
UpdateProgress("Connecting to machine", msg);
});
}
if (settings.ApplicationState == ApplicationStates.PreSetup)
{
if (setup_response.SetupActivation)
{
LogManager.Log("Activating windows license...");
UpdateProgress("Activating operation system license", "Activating...");
await _windows_manager.Activate(setup_response.OSKey);
}
}
if (setup_response.SetupRemoteAssistance)
{
LogManager.Log("Installing remote assistance...");
UpdateProgress("Installing remote assistance", "Installing...");
await _remoteAssistance.InstallRemoteAssistance(serialNumber, setup_response.Organization, settings.DeploymentSlot.ToString());
}
if (setup_response.SetupUWF)
{
LogManager.Log("Activating unified write filter...");
UpdateProgress("Activating disk protection", "Activating...");
await _uwf.Setup();
}
//Create temporary folders for packages.
var _newPackageTempFolder = TemporaryManager.CreateFolder();
_newPackageTempFolder.Persist = true;
LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}.");
//Download software package.
var tempFile = TemporaryManager.CreateFile(".zip");
LogManager.Log($"Temporary package zip file created: {tempFile}.");
LogManager.Log("Downloading software package...");
using (AutoFileDownloader downloader = new AutoFileDownloader(setup_response.BlobAddress, setup_response.CdnAddress, tempFile))
{
await downloader.ResolveMode();
if (downloader.Mode == AutoFileDownloader.DownloadMode.Standard)
{
LogManager.Log($"Connecting to storage CDN with address {downloader.Address}");
}
else
{
LogManager.Log($"Connecting to storage blob with address {downloader.Address}");
}
downloader.Progress += (x, e) =>
{
UpdateProgress("Downloading software package", "Downloading...", false, e.Current, e.Total);
};
var size = await downloader.GetFileSize();
LogManager.Log("Download size: " + size + " bytes.");
LogManager.Log("Starting file download...");
await downloader.Download();
}
UpdateProgress("Downloading software package", "Extracting package...");
LogManager.Log("Extracting downloaded zip file...");
//Extract software package.
ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder);
LogManager.Log("Copying latest updater utility to application path...");
//Copy new updater utility to app path.
File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true);
//Synchronize database
UpdateProgress("Updating Database", "Initializing...");
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
LogManager.Log($"Synchronizing database '{setup_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
UpdateProgress("Updating Database", "Connecting to local database...");
LogManager.Log($"Connecting to local database at {localDataSource}...");
DbManager db = DbManager.FromAddress(localDataSource.Address);
LogManager.Log($"Ensuring {localDataSource.Catalog} database exists on the local machine...");
if (!db.Exists(localDataSource.Catalog))
{
UpdateProgress("Updating Database", "Creating new database...");
LogManager.Log("Database does not exist. Creating new database...");
db.Create(localDataSource.Catalog);
}
else
{
LogManager.Log("Database exists.");
}
db.Dispose();
LogManager.Log("Initializing database manager...");
db = DbManager.FromDataSource(localDataSource);
UpdateProgress("Updating Database", "Clearing current database...");
LogManager.Log("Clearing database...");
db.ClearDb();
LogManager.Log("Disposing database manager.");
db.Dispose();
LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}...");
UpdateProgress("Updating Database", "Initializing provisioning sequence...");
ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner(
Path.Combine(_newPackageTempFolder, "Provision Scripts", "config.xml"),
Path.Combine(_newPackageTempFolder, "Provision Scripts"),
setup_response.DataSource,
localDataSource,
serialNumber);
runner.Log += (x, msg) =>
{
LogManager.Log(msg);
ProgressLog?.Invoke(this, msg);
};
runner.ScriptExecuting += (x, item) =>
{
LogManager.Log($"Executing script {item.ToString()}...");
UpdateProgress("Updating Database", item.Name + "...");
};
LogManager.Log("Starting synchronization process...");
try
{
await runner.Run();
LogManager.Log("Synchronization completed successfully!");
UpdateProgress("Updating Database", "Database synchronization completed successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Setup manager error while trying to synchronize database.");
}
if (setup_response.SetupFirmware)
{
//Updating firmware
UpdateProgress("Updating Firmware", "Connecting to firmware device...");
LogManager.Log("");
LogManager.Log("-------------------------------------------------------------------------");
LogManager.Log("Updating Firmware...");
UpdateProgress("Updating Firmware", "Loading firmware package...");
var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp");
var stream = new FileStream(tfpPath, FileMode.Open);
var handler = await op.UpgradeFirmware(stream);
handler.Failed += (_, ex) =>
{
stream.Dispose();
OnFailed(ex, result, setup_response);
};
handler.Completed += (_, __) =>
{
UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
stream.Dispose();
OnCompleted(new MachineSetupResult()
{
UpdatePackagePath = _newPackageTempFolder,
}, result, setup_response);
};
handler.Canceled += (_, __) =>
{
stream.Dispose();
OnFailed(new Exception("The operation has been canceled."), result, setup_response);
};
handler.Progress += (_, e) =>
{
UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total);
};
}
else
{
OnCompleted(new MachineSetupResult()
{
UpdatePackagePath = _newPackageTempFolder,
}, result, setup_response);
}
}
catch (Exception ex)
{
OnFailed(ex, result, setup_response);
}
return await result.Task;
}
#endregion
#region Protected Methods
protected virtual void UpdateProgress(String name, String message = "", bool isIntermediate = true, double progress = 0, double total = 0)
{
InvokeUINow(() =>
{
Status = new MachineSetupProgress()
{
Name = name,
Message = message,
IsIntermediate = isIntermediate,
Progress = progress,
Total = total,
};
Progress?.Invoke(this, Status);
});
UIHelper.DoEvents();
}
#endregion
}
}