aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Publisher.UI/PublisherSettings.cs
blob: dda722765f445c6c6d785d2a3d30064bd415d656 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.MachineStudio.Common.Publish;
using Tango.Settings;

namespace Tango.MachineStudio.Publisher.UI
{
    public class PublisherSettings : SettingsBase
    {
        public PublishOptions Options { get; set; }

        public PublisherSettings()
        {
            Options = new PublishOptions();
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf;
using Tango.BL.Entities;
using Tango.Integration.Operation;
using Tango.PMR;
using Tango.PMR.Common;
using Tango.Transport;
using Tango.Transport.Transporters;
using Tango.PMR.Integration;
using Tango.Transport.Discovery;
using Tango.Transport.Servers;
using Tango.Transport.Adapters;
using Tango.PMR.Connection;
using Tango.PMR.Diagnostics;
using Tango.PMR.Debugging;

namespace Tango.Integration.ExternalBridge
{
    public class ExternalBridgeService : BasicTransporter, IExternalBridgeService
    {
        private UdpDiscoveryService<ExternalBridgeUdpDiscoveryPacket> _discoverySevice;
        private TcpServer _tcpServer;

        #region Events

        /// <summary>
        /// Occurs when a new client is waiting for authentication.
        /// </summary>
        public event EventHandler<ExternalBridgeClientConnectedEventArgs> ConnectionRequest;

        /// <summary>
        /// Occurs when the last client has been disconnected.
        /// </summary>
        public event EventHandler ClientDisconnected;

        #endregion

        #region Properties

        private IMachineOperator _machineOperator;
        /// <summary>
        /// Gets or sets the machine operator.
        /// </summary>
        public IMachineOperator MachineOperator
        {
            get { return _machineOperator; }
            set { _machineOperator = value; OnMachineOperatorChanged(); }
        }

        private Machine _machine;
        /// <summary>
        /// Gets or sets the machine.
        /// </summary>
        public Machine Machine
        {
            get { return _machine; }
            set { _machine = value; OnMachineChanged(); }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is started.
        /// </summary>
        public bool IsStarted { get; private set; }

        private bool _enabled;
        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="IExternalBridgeService" /> is enabled.
        /// </summary>
        public bool Enabled
        {
            get { return _enabled; }
            set
            {
                _enabled = value;

                if (_enabled)
                {
                    Start();
                }
                else
                {
                    Stop();
                }

                RaisePropertyChangedAuto();
            }
        }

        private bool _isInSession;
        /// <summary>
        /// Gets a value indicating whether a remote client is authenticated and in session.
        /// </summary>
        public bool IsInSession
        {
            get { return _isInSession; }
            private set { _isInSession = value; RaisePropertyChangedAuto(); }
        }

        /// <summary>
        /// Gets the current session login intent.
        /// </summary>
        public ExternalBridgeLoginIntent SessionIntent { get; private set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ExternalBridgeService"/> class.
        /// </summary>
        public ExternalBridgeService()
        {
            _tcpServer = new TcpServer(1984);
            _tcpServer.ClientConnected += _tcpServer_ClientConnected;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExternalBridgeService"/> class.
        /// </summary>
        /// <param name="machineOperator">The machine operator.</param>
        /// <param name="machine">The machine.</param>
        public ExternalBridgeService(IMachineOperator machineOperator, Machine machine) : this()
        {
            Machine = machine;
            MachineOperator = machineOperator;
        }


        #endregion

        #region Properties Changes

        /// <summary>
        /// Called when the machine has been changed
        /// </summary>
        protected virtual void OnMachineChanged()
        {
            if (_discoverySevice != null && _discoverySevice.IsStarted)
            {
                _discoverySevice.Stop();
            }

            _discoverySevice = new UdpDiscoveryService<ExternalBridgeUdpDiscoveryPacket>(8888, new ExternalBridgeUdpDiscoveryPacket()
            {
                SerialNumber = Machine.SerialNumber,
            });
        }

        /// <summary>
        /// Called when the machine operator has been changed
        /// </summary>
        protected virtual void OnMachineOperatorChanged()
        {
            if (MachineOperator != null)
            {
                MachineOperator.StateChanged -= MachineOperator_StateChanged;
                MachineOperator.StateChanged += MachineOperator_StateChanged;
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Handles the ClientConnected event of the _tcpServer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="ClientConnectedEventArgs"/> instance containing the event data.</param>
        private async void _tcpServer_ClientConnected(object sender, ClientConnectedEventArgs e)
        {
            LogManager.Log("External bridge client connected from: " + e.Socket.GetIPAddress());

            Adapter = new TcpTransportAdapter(e.Socket);
            await Connect();
        }

        /// <summary>
        /// Machines the operator state changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The e.</param>
        private void MachineOperator_StateChanged(object sender, TransportComponentState e)
        {
            //Do nothing right now.
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Starts this instance.
        /// </summary>
        public void Start()
        {
            if (!IsStarted)
            {
                _tcpServer.Start();
                _discoverySevice.Start();

                IsStarted = true;
                _enabled = true;
                RaisePropertyChanged(nameof(Enabled));
            }
        }

        /// <summary>
        /// Stops this instance.
        /// </summary>
        public async void Stop()
        {
            if (IsStarted)
            {
                _tcpServer.Stop();
                _discoverySevice.Stop();

                IsStarted = false;
                IsInSession = false;
                _enabled = false;
                RaisePropertyChanged(nameof(Enabled));

                try
                {
                    await Disconnect();
                }
                catch { }
            }
        }

        /// <summary>
        /// Disconnects the current remote client session.
        /// </summary>
        public async void DisconnectSession()
        {
            await Disconnect();
        }

        #endregion

        #region Override Methods

        protected override void OnRequestReceived(MessageContainer container)
        {
            base.OnRequestReceived(container);

            try
            {
                if (Enabled)
                {
                    if (container.Type == MessageType.ConnectRequest || container.Type == MessageType.DisconnectRequest)
                    {
                        //Do nothing !
                    }
                    else if (container.Type == MessageType.ExternalBridgeLoginRequest)
                    {
                        OnExternalBridgeLoginRequest(container);
                    }
                    else if (container.Type == MessageType.ExternalBridgeLogoutRequest)
                    {
                        OnExternalBridgeLogoutRequest(container);
                    }
                    else
                    {
                        if (IsInSession && SessionIntent == ExternalBridgeLoginIntent.Override)
                        {
                            OnAnyRequest(container);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, String.Format("An error occurred while processing a request message '{0}' from the remote host.", container.Type));
            }
        }

        public async override Task Disconnect()
        {
            try
            {
                if (IsInSession)
                {
                    ClearQueues();
                    await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutRequest());
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "Error sending an external bridge log out request.");
            }

            OnClientDisconnected();
        }

        #endregion

        #region Virtual Methods

        protected async virtual void OnClientDisconnected()
        {
            IsInSession = false;

            try
            {
                await MachineOperator.SendRequest(new StopDiagnosticsRequest());
            }
            catch (Exception ex)
            {
                LogManager.Log(ex);
            }

            try
            {
                await MachineOperator.SendRequest(new StopDebugLogRequest());
            }
            catch (Exception ex)
            {
                LogManager.Log(ex);
            }

            ClientDisconnected?.Invoke(this, new EventArgs());

            try
            {
                await base.Disconnect();
            }
            catch (Exception ex)
            {
                LogManager.Log(ex);
            }

            LogManager.Log("External bridge client disconnected.");
        }

        #endregion

        #region Message Handlers

        protected virtual async void OnAnyRequest(MessageContainer container)
        {
            if (!container.Continuous)
            {
                var response = await MachineOperator.SendRequest(container);
                await SendResponse(response);
            }
            else
            {
                MachineOperator.SendContinuousRequest(container).Subscribe((response) =>
                {
                    if (Enabled && IsInSession)
                    {
                        SendResponse(response);
                    }

                }, (ex) =>
                {
                    if (Enabled)
                    {
                        if (ex is ResponseErrorException)
                        {
                            SendResponse((ex as ResponseErrorException).Container);
                        }
                    }
                });
            }
        }

        protected async virtual void OnExternalBridgeLogoutRequest(MessageContainer container)
        {
            try
            {
                ClearQueues();
                await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token);
            }
            catch (Exception ex)
            {
                LogManager.Log(ex);
            }

            OnClientDisconnected();
        }

        protected async virtual void OnExternalBridgeLoginRequest(MessageContainer container)
        {

            var request = MessageFactory.ParseTangoMessageFromContainer<ExternalBridgeLoginRequest>(container);

            LogManager.Log(String.Format("External bridge login attempt:{0}{1}", Environment.NewLine, request.Message.ToJsonString()));

            if (MachineOperator.Status != MachineStatuses.Printing || request.Message.Intent != ExternalBridgeLoginIntent.Override)
            {
                ExternalBridgeClientConnectedEventArgs args = new ExternalBridgeClientConnectedEventArgs();
                args.Request = request;
                args.IpAddress = Adapter.Address;
                ConnectionRequest?.Invoke(this, args);

                var response = new ExternalBridgeLoginResponse();
                response.Authenticated = args.Confirmed;
                response.SerialNumber = Machine.SerialNumber;
                response.DeviceInformation = MachineOperator.DeviceInformation;

                IsInSession = args.Confirmed;

                if (IsInSession)
                {
                    LogManager.Log("External bridge client has logged-in successfully.");
                    MachineOperator.EnableDiagnostics = false;
                    MachineOperator.EnableEmbeddedDebugging = false;
                    SessionIntent = request.Message.Intent;
                }
                else
                {
                    LogManager.Log("External bridge client login failed, invalid password.");
                }

                await SendResponse<ExternalBridgeLoginResponse>(response, container.Token);
            }
            else
            {
                LogManager.Log("External bridge client login failed because the machine is currently printing.");
                await SendResponse<ExternalBridgeLoginResponse>(new ExternalBridgeLoginResponse(), container.Token, false, ErrorCode.GeneralError, "Machine connection override is not permitted while printing.");
            }
        }

        #endregion
    }
}