1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
<Window x:Class="Tango.MachineStudio.Updater.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Tango.MachineStudio.Updater"
mc:Ignorable="d"
Title="Machine Studio Update" Height="400" Width="700" ShowInTaskbar="False" WindowStartupLocation="CenterScreen" WindowStyle="None" ResizeMode="NoResize" Foreground="#202020">
<Border BorderThickness="1" BorderBrush="#0288D1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="156*"/>
</Grid.RowDefinitions>
<Grid Background="#0288D1">
<Grid.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="5" Direction="270" Opacity="0.5" />
</Grid.Effect>
<StackPanel Orientation="Horizontal" Margin="8" HorizontalAlignment="Center">
<Image Source="/Images/machine-trans.png" RenderOptions.BitmapScalingMode="Fant"></Image>
<TextBlock Foreground="White" VerticalAlignment="Center" Margin="10 0 0 0" FontSize="23">MACHINE STUDIO</TextBlock>
</StackPanel>
</Grid>
<Grid Grid.Row="1">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="/Images/update.png" Width="100" />
<TextBlock x:Name="txtStatus" Margin="0 20 0 0" FontSize="12" Text="Updating Machine Studio..." HorizontalAlignment="Center"></TextBlock>
<ProgressBar x:Name="prog" Margin="0 30 0 0" Width="500" Height="10" Maximum="100" Value="0" Foreground="#0288D1"></ProgressBar>
</StackPanel>
</Grid>
</Grid>
</Border>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Security.Authentication;
using System.Text;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Entities;
using Tango.Integration.Operation;
using Tango.Logging;
using Tango.PMR;
using Tango.PMR.Common;
using Tango.PMR.Connection;
using Tango.PMR.Integration;
using Tango.PMR.MachineStatus;
using Tango.Settings;
using Tango.Transport;
using Tango.Transport.Adapters;
using Tango.Transport.Transporters;
namespace Tango.Integration.ExternalBridge
{
/// <summary>
/// Represents a secure external bridge TCP client.
/// </summary>
/// <seealso cref="Tango.Transport.Transporters.BasicTransporter" />
/// <seealso cref="Tango.Integration.ExternalBridge.IExternalBridgeSecureClient" />
public class ExternalBridgeTcpClient : MachineOperator, IExternalBridgeSecureClient
{
private bool _logs_sent;
public event EventHandler<LogItemBase> ApplicationLogAvailable;
#region Properties
private String _serialNumber;
/// <summary>
/// Gets the machine serial number.
/// </summary>
public String SerialNumber
{
get { return _serialNumber; }
set
{
_serialNumber = value;
RaisePropertyChangedAuto();
}
}
private String _ipAddress;
/// <summary>
/// Gets or sets the machine IP address.
/// </summary>
public String IPAddress
{
get { return _ipAddress; }
set { _ipAddress = value; RaisePropertyChangedAuto(); }
}
private bool _enableApplicationLogs;
/// <summary>
/// Gets or sets a value indicating whether to enable receiving application logs.
/// </summary>
public bool EnableApplicationLogs
{
get { return _enableApplicationLogs; }
set
{
_enableApplicationLogs = value;
RaisePropertyChangedAuto();
OnEnableApplicationLogsChanged(value);
}
}
public bool InjectApplicationLogsToDefaultLogManager { get; set; } = true;
/// <summary>
/// Gets a value indicating whether this client requires authentication.
/// </summary>
public bool RequiresAuthentication => true;
/// <summary>
/// Gets or sets the login request message when using <see cref="Connect"/>.
/// </summary>
public ExternalBridgeLoginRequest LoginRequest { get; set; }
/// <summary>
/// Gets or sets the configure protocol request message when using <see cref="Connect"/>.
/// </summary>
public ConfigureProtocolRequest ConfigureProtocolRequest { get; set; }
/// <summary>
/// Gets or sets a value indicating to apply the <see cref="ConfigureProtocolRequest"/> even if there is an error with the request.
/// </summary>
public bool ForceProtocolConfiguration { get; set; }
private ApplicationInformation _applicationInformation;
/// <summary>
/// Gets or sets the remote application information (PPC).
/// </summary>
public ApplicationInformation ApplicationInformation
{
get { return _applicationInformation; }
protected set { _applicationInformation = value; RaisePropertyChangedAuto(); }
}
#endregion
/// <summary>
/// Connects to a remote external bridge service using the specified <see cref="LoginRequest"/>.
/// </summary>
/// <param name="login">The login.</param>
/// <returns></returns>
/// <exception cref="AuthenticationException">The machine password is invalid.</exception>
public override Task Connect()
{
if (LoginRequest == null)
{
throw new InvalidOperationException("No LoginRequest was not specified.");
}
return Connect(LoginRequest, ConfigureProtocolRequest);
}
/// <summary>
/// Connects to a remote external bridge service using the specified login.
/// </summary>
/// <param name="login">The login request.</param>
/// <param name="protocol">Optional protocol configuration.</param>
/// <returns></returns>
/// <exception cref="AuthenticationException"></exception>
public virtual async Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null)
{
if (State != TransportComponentState.Connected)
{
try
{
Adapter.EnableCompression = false;
GenericProtocol = GenericMessageProtocol.Json;
await Adapter.Connect();
State = TransportComponentState.Connected;
StartThreads();
LogManager.Log($"{ComponentName}: External Bridge TCP Client Connected...");
TimeSpan? timeout = null;
if (login.RequireSafetyLevelOperations)
{
timeout = TimeSpan.FromSeconds(35);
}
var response = await SendRequest<ExternalBridgeLoginRequest, ExternalBridgeLoginResponse>(login, new TransportRequestConfig() { ShouldLog = true, Timeout = timeout });
if (protocol != null)
{
try
{
var configureResponse = await SendRequest<ConfigureProtocolRequest, ConfigureProtocolResponse>(protocol, new TransportRequestConfig() { ShouldLog = true });
if (configureResponse.Message.Confirmed)
{
await Task.Delay(500);
Adapter.EnableCompression = protocol.EnableCompression;
GenericProtocol = protocol.GenericProtocol;
}
}
catch (Exception ex)
{
if (ForceProtocolConfiguration)
{
LogManager.Log(ex, $"{ComponentName}: Could not configure remote machine protocol. Could be an old PPC version. (forcing protocol configuration)");
Adapter.EnableCompression = protocol.EnableCompression;
GenericProtocol = protocol.GenericProtocol;
}
else
{
LogManager.Log(ex, $"{ComponentName}: Could not configure remote machine protocol. Could be an old PPC version.");
}
}
}
ApplicationInformation = response.Message.ApplicationInformation;
SessionLogger.CreateSession();
DeviceInformation = response.Message.DeviceInformation;
if (!response.Message.Authenticated)
{
await Adapter.Disconnect();
throw new AuthenticationException(response.Container.ErrorMessage);
}
}
catch (Exception ex)
{
try
{
await Adapter.Disconnect();
}
catch { }
throw ex;
}
ApplyContinuousChannelsConfiguration();
}
}
protected virtual void ApplyContinuousChannelsConfiguration()
{
OnEnableDiagnosticsChanged(EnableDiagnostics);
OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging);
OnEnableEventsNotification(EnableEventsNotification);
OnEnableApplicationLogsChanged(EnableApplicationLogs);
OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates);
OnEnableInkFillingStatus(EnableInkFillingStatus);
//TODO: Uncomment this only when Machine Studio enables automatic thread loading (ExternalBridgeTCPClient).
//OnEnableAutomaticThreadLoadingChanged(EnableAutomaticThreadLoading);
}
protected async void OnEnableApplicationLogsChanged(bool value)
{
if (value && State == TransportComponentState.Connected && !_logs_sent)
{
var request = new StartApplicationLogsRequest();
bool responseLogged = false;
_logs_sent = true;
SendContinuousRequest<StartApplicationLogsRequest, StartApplicationLogsResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler())
.Subscribe
(
(response) =>
{
if (!responseLogged)
{
responseLogged = true;
}
OnApplicationLogAvailable(response);
},
(ex) =>
{
_logs_sent = false;
},
() =>
{
_logs_sent = false;
});
}
else if (_logs_sent)
{
_logs_sent = false;
if (State == TransportComponentState.Connected)
{
var req = new StopApplicationLogsRequest();
try
{
var res = await SendRequest<StopApplicationLogsRequest, StopApplicationLogsResponse>(req, new TransportRequestConfig() { ShouldLog = true });
}
catch { }
}
}
}
private void OnApplicationLogAvailable(TangoMessage<StartApplicationLogsResponse> response)
{
try
{
if (response.Message.LogItem.Count() > 0)
{
LogItemBase log = LogItemBase.Deserialize(response.Message.LogItem.ToArray());
log.LogObject = "External Bridge";
if (InjectApplicationLogsToDefaultLogManager)
{
LogManager.Log(log);
}
ApplicationLogAvailable?.Invoke(this, log);
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error deserializing incoming application log item!");
}
}
public async override Task Disconnect()
{
if (State == TransportComponentState.Connected)
{
ExternalBridgeLogoutRequest request = new ExternalBridgeLogoutRequest();
try
{
var response = await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(request, new TransportRequestConfig() { ShouldLog = true });
}
catch { }
Status = MachineStatuses.Standby;
}
State = TransportComponentState.Disconnected;
NotifyContinuousRequestMessagesDisconnection();
SessionLogger.EndSession();
if (Adapter != null)
{
await Adapter.Disconnect();
}
LogManager.Log($"{ComponentName} disconnected.");
}
internal ExternalBridgeTcpClient()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ExternalBridgeTcpClient"/> class.
/// </summary>
/// <param name="serialNumber">The machine serial number.</param>
/// <param name="ipAddress">The machine IP address.</param>
public ExternalBridgeTcpClient(String serialNumber, String ipAddress)
{
ComponentName = $"External Bridge TCP Client {_component_counter++}";
SerialNumber = serialNumber;
if (ObservablesStaticCollections.Instance.IsInitialized)
{
Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == serialNumber);
}
IPAddress = ipAddress;
KeepAliveTimeout = TimeSpan.FromSeconds(5);
KeepAliveRetries = 2;
UseKeepAlive = false;
EnableDiagnostics = true;
Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort);
}
public ExternalBridgeTcpClient(Machine machine, String ipAddress)
{
ComponentName = $"External Bridge TCP Client {_component_counter++}";
Machine = machine;
SerialNumber = Machine.SerialNumber;
IPAddress = ipAddress;
KeepAliveTimeout = TimeSpan.FromSeconds(5);
KeepAliveRetries = 2;
UseKeepAlive = false;
EnableDiagnostics = true;
Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort);
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
return SerialNumber;
}
/// <summary>
/// Called when a new request has been received.
/// </summary>
/// <param name="request">The request.</param>
protected async override void OnRequestReceived(RequestReceivedEventArgs e)
{
base.OnRequestReceived(e);
var container = e.Container;
if (container.Type == MessageType.ExternalBridgeLogoutRequest)
{
try
{
await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token);
}
catch { }
await Task.Delay(2000);
try
{
State = TransportComponentState.Disconnected;
if (Adapter != null)
{
await Adapter.Disconnect();
}
LogManager.Log("External Bridge TCP client disconnected by the remote host.");
}
catch { }
SessionLogger.EndSession();
SessionClosed?.Invoke(this, new EventArgs());
NotifyContinuousRequestMessagesDisconnection();
}
}
protected override void OnMachineStateChanged(MachineState state)
{
//Do Nothing...
}
/// <summary>
/// Occurs when the remote host has closed the session.
/// </summary>
public event EventHandler SessionClosed;
/// <summary>
/// Gets the database machine associated with this client.
/// </summary>
public Machine Machine { get; protected set; }
/// <summary>
/// Sets the database machine.
/// </summary>
/// <param name="machine">The machine.</param>
public void SetMachine(Machine machine)
{
Machine = machine;
}
}
}
|