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.Settings; using Tango.Transport; using Tango.Transport.Adapters; using Tango.Transport.Transporters; namespace Tango.Integration.ExternalBridge { /// /// Represents a secure external bridge TCP client. /// /// /// public class ExternalBridgeTcpClient : MachineOperator, IExternalBridgeSecureClient { private bool _logs_sent; #region Properties private String _serialNumber; /// /// Gets the machine serial number. /// public String SerialNumber { get { return _serialNumber; } set { _serialNumber = value; RaisePropertyChangedAuto(); } } private String _ipAddress; /// /// Gets or sets the machine IP address. /// public String IPAddress { get { return _ipAddress; } set { _ipAddress = value; RaisePropertyChangedAuto(); } } private bool _enableApplicationLogs; /// /// Gets or sets a value indicating whether to enable receiving application logs. /// public bool EnableApplicationLogs { get { return _enableApplicationLogs; } set { _enableApplicationLogs = value; RaisePropertyChangedAuto(); OnEnableApplicationLogsChanged(value); } } /// /// Gets a value indicating whether this client requires authentication. /// public bool RequiresAuthentication => true; #endregion public override Task Connect() { throw new NotImplementedException("External Bridge TCP client must connect through the dedicated connect method."); } /// /// Connects to a remote external bridge service using the specified login. /// /// The login. /// /// The machine password is invalid. public async Task Connect(ExternalBridgeLoginRequest login) { if (State != TransportComponentState.Connected) { try { Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate().ExternalBridgeServicePort); await Adapter.Connect(); State = TransportComponentState.Connected; StartThreads(); LogManager.Log("External Bridge TCP Client Connected..."); LogRequestSent(login); var response = await SendRequest(login); DeviceInformation = response.Message.DeviceInformation; if (!response.Message.Authenticated) { await Adapter.Disconnect(); throw new AuthenticationException(response.Container.ErrorMessage); } Status = MachineStatuses.ReadyToDye; } catch (Exception ex) { LogRequestFailed(login, ex); try { await Adapter.Disconnect(); } catch { } throw ex; } OnEnableDiagnosticsChanged(EnableDiagnostics); OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); OnEnableEventsNotification(EnableEventsNotification); OnEnableApplicationLogsChanged(EnableApplicationLogs); OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates); } } private async void OnEnableApplicationLogsChanged(bool value) { if (value && State == TransportComponentState.Connected && !_logs_sent) { var request = new StartApplicationLogsRequest(); bool responseLogged = false; _logs_sent = true; SendContinuousRequest(request).ObserveOn(new NewThreadScheduler()) .Subscribe ( (response) => { if (!responseLogged) { LogResponseReceived(response.Message); responseLogged = true; } OnApplicationLogAvailable(response); }, (ex) => { _logs_sent = false; if (!(ex is ContinuousResponseAbortedException)) { LogRequestFailed(request, ex); } }, () => { _logs_sent = false; }); LogRequestSent(request); } else if (_logs_sent) { _logs_sent = false; if (State == TransportComponentState.Connected) { var req = new StopApplicationLogsRequest(); try { LogRequestSent(req); var res = await SendRequest(req); LogResponseReceived(res.Message); } catch (Exception ex) { LogRequestFailed(req, ex); } } } } private void OnApplicationLogAvailable(TangoMessage response) { try { if (response.Message.LogItem.Count() > 0) { LogItemBase log = LogItemBase.Deserialize(response.Message.LogItem.ToArray()); log.LogObject = "External Bridge"; LogManager.Log(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(); LogRequestSent(request); try { var response = await SendRequest(request); LogResponseReceived(response.Message); Status = MachineStatuses.Standby; } catch (Exception ex) { LogRequestFailed(request, ex); } } State = TransportComponentState.Disconnected; if (Adapter != null) { await Adapter.Disconnect(); } LogManager.Log("External Bridge TCP client disconnected."); } /// /// Initializes a new instance of the class. /// /// The machine serial number. /// The machine IP address. public ExternalBridgeTcpClient(String serialNumber, String ipAddress) { SerialNumber = serialNumber; Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == serialNumber); IPAddress = ipAddress; KeepAliveTimeout = TimeSpan.FromSeconds(5); KeepAliveRetries = 2; UseKeepAlive = false; EnableDiagnostics = true; } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return SerialNumber; } /// /// Called when a new request has been received. /// /// The request. protected async override void OnRequestReceived(MessageContainer request) { base.OnRequestReceived(request); if (request.Type == MessageType.ExternalBridgeLogoutRequest) { await SendResponse(new ExternalBridgeLogoutResponse(), request.Token); try { State = TransportComponentState.Disconnected; if (Adapter != null) { await Adapter.Disconnect(); } LogManager.Log("External Bridge TCP client disconnected by the remote host."); } catch { } SessionClosed?.Invoke(this, new EventArgs()); } } /// /// Occurs when the remote host has closed the session. /// public event EventHandler SessionClosed; /// /// Gets the database machine associated with this client. /// public Machine Machine { get; private set; } /// /// Sets the database machine. /// /// The machine. public void SetMachine(Machine machine) { Machine = machine; } } }