diff options
Diffstat (limited to 'Software/Visual_Studio/Tango.Integration/ExternalBridge')
16 files changed, 524 insertions, 1831 deletions
diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs index e976898ef..2bfe60477 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeClientConnectedEventArgs.cs @@ -9,30 +9,10 @@ namespace Tango.Integration.ExternalBridge { public class ExternalBridgeClientConnectedEventArgs : EventArgs { - private Action _confirmAction; - private Action<String> _declineAction; - public ExternalBridgeLoginRequest Request { get; set; } - public String Address { get; set; } - - public ApplicationInformation ApplicationInformation { get; set; } - - public ExternalBridgeClientConnectedEventArgs(Action confirmAction, Action<String> declineAction) - { - _confirmAction = confirmAction; - _declineAction = declineAction; - ApplicationInformation = new ApplicationInformation(); - } - - public void Confirm() - { - _confirmAction?.Invoke(); - } + public String IpAddress { get; set; } - public void Decline(String reason) - { - _declineAction?.Invoke(reason); - } + public bool Confirmed { get; set; } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs deleted file mode 100644 index 143f21f42..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiver.cs +++ /dev/null @@ -1,710 +0,0 @@ -using Google.Protobuf; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net.Sockets; -using System.Security.Authentication; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Tango.Core; -using Tango.Core.ExtensionMethods; -using Tango.Integration.Operation; -using Tango.PMR; -using Tango.PMR.Common; -using Tango.PMR.Debugging; -using Tango.PMR.Diagnostics; -using Tango.PMR.IFS; -using Tango.PMR.Integration; -using Tango.PMR.MachineStatus; -using Tango.PMR.Power; -using Tango.Transport; -using Tango.Transport.Adapters; -using Tango.Transport.Transporters; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiver : BasicTransporter - { - /// <summary> - /// A dictionary containing the last time a user name has made a request or response. - /// This is used to bypass the safety operations confirmation. - /// FullName, Contact Time - /// </summary> - public static Dictionary<String, DateTime> LastSafetyLevelContactsTimes { get; private set; } - - #region Message Handler - - private class MessageHandler - { - public Action<MessageContainer> Method { get; set; } - public bool RequiresLogin { get; set; } - public ExternalBridgeLoginIntent LoginIntent { get; set; } - - public MessageHandler(Action<MessageContainer> method) - { - Method = method; - } - - public MessageHandler(Action<MessageContainer> method, ExternalBridgeLoginIntent intent) : this(method) - { - RequiresLogin = true; - LoginIntent = intent; - } - } - - #endregion - - private String _eventsToken; - private String _machineStatusToken; - private String _diagnosticsToken; - private String _debugLogsToken; - private String _applicationLogsToken; - private String _inkFillingToken; - - private IMachineOperator _machineOperator; - private Dictionary<MessageType, MessageHandler> _messageHandlers; - - #region Events - - public event EventHandler<ExternalBridgeReceiverLoginRequestEventArgs> LoginRequest; - public event EventHandler<ColorProfileRequestEventArgs> ColorProfileRequest; - public event EventHandler Disconnected; - public event EventHandler<ExternalBridgeReceiverRequestReceivedEventArgs> ReceiverRequestReceived; - - #endregion - - #region Properties - - public bool AllowSafetyLevelOperations { get; set; } - - public bool RequiresDiagnostics { get; private set; } - public bool RequiresDebugLogs { get; private set; } - public bool RequiresEventsNotification { get; private set; } - public bool RequiresMachineStatusUpdate { get; private set; } - public bool RequiresApplicationLogs { get; private set; } - public bool RequiresInkFillingStatus { get; private set; } - - public bool IsLoggedIn { get; private set; } - public ExternalBridgeLoginIntent LoginIntent { get; private set; } - public String UserName { get; private set; } - - private ExternalBridgeLoginRequest _loginInfo; - public ExternalBridgeLoginRequest LoginInfo - { - get { return _loginInfo; } - set { _loginInfo = value; RaisePropertyChangedAuto(); } - } - - public bool IsLoggedInAndRequiresDiagnostics - { - get { return IsLoggedIn && (LoginIntent == ExternalBridgeLoginIntent.Diagnostics || LoginIntent == ExternalBridgeLoginIntent.FullControl); } - } - - - #endregion - - #region Constructors - - static ExternalBridgeReceiver() - { - LastSafetyLevelContactsTimes = new Dictionary<string, DateTime>(); - } - - public ExternalBridgeReceiver(IMachineOperator machineOperator) - { - ComponentName = $"External Bridge Receiver {_component_counter++}"; - - FailsWithAdapter = true; - - _machineOperator = machineOperator; - - _messageHandlers = new Dictionary<MessageType, MessageHandler>(); - UseKeepAlive = false; - KeepAliveTimeout = TimeSpan.FromSeconds(10); - KeepAliveRetries = 4; - - _messageHandlers.Add(MessageType.ExternalBridgeLoginRequest, new MessageHandler(OnExternalBridgeLoginRequest)); - _messageHandlers.Add(MessageType.ExternalBridgeLogoutRequest, new MessageHandler(OnExternalBridgeLogoutRequest)); - - _messageHandlers.Add(MessageType.ColorProfileRequest, new MessageHandler(OnColorProfileRequest)); - - _messageHandlers.Add(MessageType.StartDiagnosticsRequest, new MessageHandler(OnStartDiagnosticsRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopDiagnosticsRequest, new MessageHandler(OnStopDiagnosticsRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartDebugLogRequest, new MessageHandler(OnStartDebugLogRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopDebugLogRequest, new MessageHandler(OnStopDebugLogRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartEventsNotificationRequest, new MessageHandler(OnStartEventsNotificationRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopEventsNotificationRequest, new MessageHandler(OnStopEventsNotificationRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartMachineStatusUpdateRequest, new MessageHandler(OnStartMachineStatusUpdateRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopMachineStatusUpdateRequest, new MessageHandler(OnStopMachineStatusUpdateRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartApplicationLogsRequest, new MessageHandler(OnStartApplicationLogsRequest, ExternalBridgeLoginIntent.Diagnostics)); - _messageHandlers.Add(MessageType.StopApplicationLogsRequest, new MessageHandler(OnStopApplicationLogsRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.JobRequest, new MessageHandler(OnJobRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartPowerDownRequest, new MessageHandler(OnStartPowerDownRequest, ExternalBridgeLoginIntent.Diagnostics)); - - _messageHandlers.Add(MessageType.StartInkFillingStatusRequest, new MessageHandler(OnStartInkFillingStatusRequest, ExternalBridgeLoginIntent.Diagnostics)); - } - - public ExternalBridgeReceiver(TcpClient tcpClient, IMachineOperator machineOperator) : this(machineOperator) - { - Adapter = new TcpTransportAdapter(tcpClient); - } - - public ExternalBridgeReceiver(SignalRTransportAdapter signalRAdapter, IMachineOperator machineOperator) : this(machineOperator) - { - Adapter = signalRAdapter; - } - - #endregion - - #region Override Methods - - protected override void OnRequestReceived(RequestReceivedEventArgs e) - { - base.OnRequestReceived(e); - - if (e.Handled) return; - - var container = e.Container; - - try - { - if (e.Container.Type == MessageType.ConfigureProtocolRequest) - { - var message = MessageFactory.ParseTangoMessageFromContainer<ConfigureProtocolRequest>(container); - SendResponse(new ConfigureProtocolResponse() { Confirmed = true }, container.Token, new TransportResponseConfig() { Immediate = true, Priority = QueuePriority.High }); - - Task.Factory.StartNew(() => - { - Thread.Sleep(200); - Adapter.EnableCompression = message.Message.EnableCompression; - GenericProtocol = message.Message.GenericProtocol; - }); - return; - } - - if (!AllowSafetyLevelOperations) - { - if (ExternalBridgeService.SafetyLevelOperations.Contains(container.Type)) - { - SendErrorResponse(new AuthenticationException("The specified action requires safety level permission that is not granted for the current session."), container.Token); - return; - } - } - else - { - if (UserName != null) - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - } - - if (_messageHandlers.ContainsKey(container.Type)) - { - var handler = _messageHandlers[container.Type]; - - if (handler.RequiresLogin && (!IsLoggedIn || (int)handler.LoginIntent > (int)LoginIntent)) - { - SendErrorResponse(new AuthenticationException("The specified intent does not grant the specified action."), container.Token); - return; - } - - try - { - try - { - handler.Method.Invoke(container); - } - catch (Exception ex) - { - SendErrorResponse(ex, container.Token); - } - } - catch (Exception ex) - { - if (ex is ResponseErrorException) - { - SendResponse((ex as ResponseErrorException).Container); - } - else - { - SendErrorResponse(ex, container.Token); - } - } - } - else - { - if (IsLoggedIn) - { - ExternalBridgeReceiverRequestReceivedEventArgs args = new ExternalBridgeReceiverRequestReceivedEventArgs(); - args.Container = container; - ReceiverRequestReceived?.Invoke(this, args); - - if (!args.Handled) - { - OnAnyRequest(container); - } - } - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error occurred in processing request message on external bridge receiver."); - } - } - - protected override void OnFailed(Exception ex) - { - if (ex is KeepAliveException) - { - LogManager.Log("External bridge client has failed to provide a keep alive response. Disconnecting session..."); - } - - base.OnFailed(ex); - OnDisconnected(); - } - - public async override Task Disconnect() - { - try - { - if (IsLoggedIn) - { - await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutRequest(), new TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(3), ShouldLog = true }); - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error sending an external bridge log out request."); - } - finally - { - ClearQueues(); - } - - try - { - IsLoggedIn = false; - await base.Disconnect(); - } - catch { } - - OnDisconnected(); - } - - #endregion - - #region Virtual Methods - - protected virtual void OnDisconnected() - { - Disconnected?.Invoke(this, new EventArgs()); - } - - #endregion - - #region Message Handlers - - protected virtual void OnExternalBridgeLoginRequest(MessageContainer container) - { - var request = MessageFactory.ParseTangoMessageFromContainer<ExternalBridgeLoginRequest>(container); - - LogManager.Log($"External bridge login attempt:\nIntent: {request.Message.Intent}\nMessage:\n{request.Message.ToJsonString()}"); - - ExternalBridgeReceiverLoginRequestEventArgs args = new ExternalBridgeReceiverLoginRequestEventArgs((machine, deviceInfo, applicationInfo) => - { - //Confirm - LogManager.Log("External bridge client has logged-in successfully."); - - IsLoggedIn = true; - LoginIntent = request.Message.Intent; - UserName = request.Message.UserName; - LoginInfo = request.Message; - - var response = new ExternalBridgeLoginResponse(); - response.Authenticated = true; - response.SerialNumber = machine.SerialNumber; - response.DeviceInformation = deviceInfo; - response.ApplicationInformation = applicationInfo; - - AllowSafetyLevelOperations = request.Message.RequireSafetyLevelOperations; - - SendResponse<ExternalBridgeLoginResponse>(response, container.Token); - - UpdateMachineOperatorStatus((UpdateStatus)_machineOperator.Status); - - UseKeepAlive = true; - - if (AllowSafetyLevelOperations && UserName != null) - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - }, - (reason) => - { - //Decline - SendResponse<ExternalBridgeLoginResponse>(new ExternalBridgeLoginResponse(), container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.GeneralError, ErrorMessage = reason }); - Disconnect().GetAwaiter().GetResult(); - }); - - args.Address = Adapter.Address; - args.Request = request; - - LoginRequest?.Invoke(this, args); - } - - protected virtual void OnExternalBridgeLogoutRequest(MessageContainer container) - { - try - { - SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); - } - catch (Exception ex) - { - LogManager.Log(ex); - } - finally - { - OnDisconnected(); - ClearQueues(); - } - } - - protected async virtual void OnAnyRequest(MessageContainer container) - { - if (!container.Continuous) - { - try - { - var response = await _machineOperator.SendRequest(container); - await SendResponse(response); - } - catch (Exception ex) - { - await SendErrorResponse(ex, container.Token); - } - } - else - { - try - { - _machineOperator.SendContinuousRequest(container).Subscribe((response) => - { - if (State == TransportComponentState.Connected) - { - SendResponse(response); - } - - }, (ex) => - { - if (State == TransportComponentState.Connected) - { - if (ex is ResponseErrorException) - { - SendResponse((ex as ResponseErrorException).Container); - } - else if (ex is ContinuousResponseAbortedException) - { - SendResponse((ex as ContinuousResponseAbortedException).Container); - } - } - }); - } - catch (Exception ex) - { - await SendErrorResponse(ex, container.Token); - } - } - } - - protected virtual void OnColorProfileRequest(MessageContainer container) - { - var request = MessageFactory.ParseTangoMessageFromContainer<ColorProfileRequest>(container); - - ColorProfileRequestEventArgs e = new ColorProfileRequestEventArgs(request, async () => - { - //Approved. - await SendResponse<ColorProfileResponse>(new ColorProfileResponse() - { - Approved = true - }, container.Token); - await Task.Delay(500); - await base.Disconnect(); - }, - async () => - { - //Declined. - await SendResponse<ColorProfileResponse>(new ColorProfileResponse(), container.Token); - await Task.Delay(500); - await base.Disconnect(); - }); - - ColorProfileRequest?.Invoke(this, e); - } - - protected virtual void OnStartDiagnosticsRequest(MessageContainer container) - { - _diagnosticsToken = container.Token; - SendResponse<StartDiagnosticsResponse>(new StartDiagnosticsResponse(), _diagnosticsToken); - RequiresDiagnostics = true; - } - - protected virtual void OnStopDiagnosticsRequest(MessageContainer container) - { - if (_diagnosticsToken != null) - { - RequiresDiagnostics = false; - SendResponse<StartDiagnosticsResponse>(new StartDiagnosticsResponse(), _diagnosticsToken, new TransportResponseConfig() { Completed = true }); - _diagnosticsToken = null; - SendResponse<StopDiagnosticsResponse>(new StopDiagnosticsResponse(), container.Token); - } - } - - protected virtual void OnStartDebugLogRequest(MessageContainer container) - { - _debugLogsToken = container.Token; - SendResponse<StartDebugLogResponse>(new StartDebugLogResponse(), _debugLogsToken); - RequiresDebugLogs = true; - } - - protected virtual void OnStopDebugLogRequest(MessageContainer container) - { - if (_debugLogsToken != null) - { - RequiresDebugLogs = false; - SendResponse<StartDebugLogResponse>(new StartDebugLogResponse(), _debugLogsToken, new TransportResponseConfig() { Completed = true }); - _debugLogsToken = null; - SendResponse<StopDebugLogResponse>(new StopDebugLogResponse(), container.Token); - } - } - - protected virtual void OnStartEventsNotificationRequest(MessageContainer container) - { - _eventsToken = container.Token; - SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsToken); - RequiresEventsNotification = true; - } - - protected virtual void OnStopEventsNotificationRequest(MessageContainer container) - { - if (_eventsToken != null) - { - RequiresEventsNotification = false; - SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsToken, new TransportResponseConfig() { Completed = true }); - _eventsToken = null; - SendResponse<StopEventsNotificationResponse>(new StopEventsNotificationResponse(), container.Token); - } - } - - protected virtual void OnStartMachineStatusUpdateRequest(MessageContainer container) - { - _machineStatusToken = container.Token; - SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusToken); - RequiresMachineStatusUpdate = true; - } - - protected virtual void OnStopMachineStatusUpdateRequest(MessageContainer container) - { - if (_machineStatusToken != null) - { - RequiresMachineStatusUpdate = false; - SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusToken, new TransportResponseConfig() { Completed = true }); - _machineStatusToken = null; - SendResponse<StopMachineStatusUpdateResponse>(new StopMachineStatusUpdateResponse(), container.Token); - } - } - - protected virtual void OnStartApplicationLogsRequest(MessageContainer container) - { - _applicationLogsToken = container.Token; - SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), _applicationLogsToken); - RequiresApplicationLogs = true; - } - - protected virtual void OnStopApplicationLogsRequest(MessageContainer container) - { - if (_applicationLogsToken != null) - { - RequiresApplicationLogs = false; - SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), _applicationLogsToken, new TransportResponseConfig() { Completed = true }); - _applicationLogsToken = null; - SendResponse<StopApplicationLogsResponse>(new StopApplicationLogsResponse(), container.Token); - } - } - - protected virtual void OnJobRequest(MessageContainer container) - { - if (LoginIntent != ExternalBridgeLoginIntent.FullControl) - { - throw new InvalidOperationException($"Job execution is disabled while session intent is '{LoginIntent}'."); - } - if (_machineOperator.IsPrinting) - { - throw new InvalidOperationException($"Could not execute job while machine operator status is '{_machineOperator.Status}'."); - } - else - { - OnAnyRequest(container); - } - } - - protected virtual void OnStartPowerDownRequest(MessageContainer container) - { - SendResponse(new StartPowerDownResponse() { }, container.Token, new TransportResponseConfig() { ErrorCode = ErrorCode.ContinuousResponseAborted, ErrorMessage = "Power down request is not supported via external bridge." }); - } - - protected virtual void OnStartInkFillingStatusRequest(MessageContainer container) - { - _inkFillingToken = container.Token; - UpdateInkFillingStatus(null); - RequiresInkFillingStatus = true; - } - - #endregion - - #region Continuous Updates - - public void UpdateDiagnostics(MessageContainer container) - { - try - { - if (AllowSafetyLevelOperations && UserName != null) //Usually all clients require diagnostics so we will update the last contact time here.. - { - LastSafetyLevelContactsTimes[UserName] = DateTime.Now; - } - - if (_diagnosticsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _diagnosticsToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateDebugLogs(MessageContainer container) - { - try - { - if (_debugLogsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _debugLogsToken; - SendResponse(cloned, new TransportResponseConfig() - { - Priority = QueuePriority.Low, - }); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateEvents(MessageContainer container) - { - try - { - if (_eventsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _eventsToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateMachineStatus(MessageContainer container) - { - try - { - if (_machineStatusToken != null) - { - var cloned = container.Clone(); - cloned.Token = _machineStatusToken; - SendResponse(cloned); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateApplicationLogs(MessageContainer container) - { - try - { - if (_applicationLogsToken != null) - { - var cloned = container.Clone(); - cloned.Token = _applicationLogsToken; - SendResponse(cloned, new TransportResponseConfig() { Priority = QueuePriority.Low }); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateMachineOperatorStatus(UpdateStatus status) - { - try - { - SendRequest<UpdateStatusRequest, UpdateStatusResponse>(new UpdateStatusRequest() - { - Status = status, - }); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - public void UpdateInkFillingStatus(MessageContainer container) - { - try - { - if (_inkFillingToken != null) - { - if (container == null) - { - container = new MessageContainer() - { - Continuous = true, - Type = MessageType.StartInkFillingStatusResponse, - Data = ByteString.CopyFrom((new StartInkFillingStatusResponse() { Status = _machineOperator.InkFillingStatus }).ToBytes()) - }; - } - var cloned = container.Clone(); - cloned.Token = _inkFillingToken; - SendResponse(cloned, new TransportResponseConfig()); - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - #endregion - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs deleted file mode 100644 index 1ea33dbce..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverLoginRequestEventArgs.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.BL.Entities; -using Tango.PMR.Connection; -using Tango.PMR.Integration; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiverLoginRequestEventArgs : EventArgs - { - private Action<Machine, DeviceInformation, ApplicationInformation> _confirm; - private Action<String> _decline; - - public ExternalBridgeReceiverLoginRequestEventArgs(Action<Machine, DeviceInformation, ApplicationInformation> confirm, Action<String> decline) - { - _confirm = confirm; - _decline = decline; - } - - public ExternalBridgeLoginRequest Request { get; set; } - - public String Address { get; set; } - - public void Confirm(Machine machine, DeviceInformation deviceInformation, ApplicationInformation applicationInformation) - { - _confirm(machine, deviceInformation, applicationInformation); - } - - public void Decline(String reason) - { - _decline(reason); - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs deleted file mode 100644 index 682de264c..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeReceiverRequestReceivedEventArgs.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Common; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeReceiverRequestReceivedEventArgs - { - public MessageContainer Container { get; set; } - public bool Handled { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs deleted file mode 100644 index 7ddedb0b9..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeRequestHandlerMethodAttribute.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Common; - -namespace Tango.Integration.ExternalBridge -{ - [AttributeUsage(AttributeTargets.Method)] - public class ExternalBridgeRequestHandlerMethodAttribute : Attribute - { - public Type Type { get; set; } - - public RequestHandlerLoggingMode LoggingMode { get; set; } - - public ExternalBridgeRequestHandlerMethodAttribute(Type type) - { - Type = type; - } - - public ExternalBridgeRequestHandlerMethodAttribute(Type type, RequestHandlerLoggingMode loggingMode) : this(type) - { - LoggingMode = loggingMode; - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs index 694502d2e..b84942643 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeScanner.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNet.SignalR.Client; -using System; +using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; @@ -13,10 +12,8 @@ using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; -using Tango.BL.Entities; using Tango.Core; using Tango.Core.Helpers; -using Tango.Integration.ExternalBridge.Web; using Tango.Logging; using Tango.PMR; using Tango.PMR.Common; @@ -34,15 +31,8 @@ namespace Tango.Integration.ExternalBridge { private Thread _tcpDiscoveryThread; private Thread _usbDiscoveryThread; - private Thread _signalRDiscoveryThread; private UdpClient _server; private IntegrationSettings _settings; - private HubConnection _connection; - private IHubProxy _proxy; - - public event EventHandler<IExternalBridgeClient> MachineDiscovered; - - public event EventHandler<IExternalBridgeClient> MachineLost; private SynchronizedObservableCollection<IExternalBridgeClient> _availableMachines; /// <summary> @@ -54,16 +44,6 @@ namespace Tango.Integration.ExternalBridge private set { _availableMachines = value; RaisePropertyChangedAuto(); } } - /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - public ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - - /// <summary> - /// Gets or sets the known machines. - /// </summary> - public List<Machine> KnownMachines { get; set; } - private bool _isStarted; /// <summary> /// Gets or sets a value indicating whether this instance is started. @@ -80,14 +60,8 @@ namespace Tango.Integration.ExternalBridge public ExternalBridgeScanner() { _settings = SettingsManager.Default.GetOrCreate<IntegrationSettings>(); + _server = new UdpClient(_settings.ExternalBridgeServiceDiscoveryPort); AvailableMachines = new SynchronizedObservableCollection<IExternalBridgeClient>(); - KnownMachines = new List<Machine>(); - SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); - } - - public ExternalBridgeScanner(List<Machine> knownMachines) : this() - { - KnownMachines = knownMachines; } /// <summary> @@ -99,13 +73,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("External bridge scanner started..."); - if (_server == null) - { - _server = new UdpClient(); - _server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - _server.Client.Bind(new IPEndPoint(IPAddress.Any, _settings.ExternalBridgeServiceDiscoveryPort)); - } - IsStarted = true; foreach (var machine in AvailableMachines.OfType<ExternalBridgeTcpClient>().ToList()) @@ -113,11 +80,6 @@ namespace Tango.Integration.ExternalBridge AvailableMachines.Remove(machine); } - foreach (var machine in AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList()) - { - AvailableMachines.Remove(machine); - } - _tcpDiscoveryThread = new Thread(TcpDiscoveryThreadMethod); _tcpDiscoveryThread.IsBackground = true; _tcpDiscoveryThread.Start(); @@ -125,37 +87,6 @@ namespace Tango.Integration.ExternalBridge _usbDiscoveryThread = new Thread(UsbDiscoveryThreadMethod); _usbDiscoveryThread.IsBackground = true; _usbDiscoveryThread.Start(); - - if (SignalRConfiguration.Enabled) - { - try - { - _connection = new HubConnection(SignalRConfiguration.Address); - _proxy = _connection.CreateHubProxy(SignalRConfiguration.Hub); - - bool signalRStarted = false; - - _connection.StateChanged += (x) => - { - if (x.NewState == ConnectionState.Connected) - { - if (!signalRStarted) - { - signalRStarted = true; - _signalRDiscoveryThread = new Thread(SignalRDiscoveryThreadMethod); - _signalRDiscoveryThread.IsBackground = true; - _signalRDiscoveryThread.Start(); - } - } - }; - - _connection.Start(); - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } } } @@ -187,9 +118,7 @@ namespace Tango.Integration.ExternalBridge LogManager.Log("Found a new machine via USB " + device.Description); ThreadsHelper.InvokeUINow(() => { - var machine = new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate); - AvailableMachines.Add(machine); - MachineDiscovered?.Invoke(this, machine); + AvailableMachines.Add(new ExternalBridgeUsbClient(device.Port, device.Description, _settings.EmbeddedSerialBaudRate)); }); } } @@ -202,7 +131,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// TCP discovery thread method. /// </summary> - //[DebuggerStepThrough] + [DebuggerStepThrough] private void TcpDiscoveryThreadMethod() { while (IsStarted) @@ -232,7 +161,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("Disconnected machine detected via TCP: " + disconnected_machine.SerialNumber); AvailableMachines.Remove(disconnected_machine); - MachineLost?.Invoke(this, disconnected_machine); } continue; @@ -240,35 +168,14 @@ namespace Tango.Integration.ExternalBridge if (!AvailableMachines.OfType<ExternalBridgeTcpClient>().ToList().Exists(x => x.SerialNumber == packet.SerialNumber && x.IPAddress == address)) { - ExternalBridgeTcpClient newMachine = null; - var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == packet.SerialNumber); + ExternalBridgeTcpClient newMachine = new ExternalBridgeTcpClient(packet.SerialNumber, address); - if (knownMachine == null && KnownMachines.Count == 0) - { - newMachine = new ExternalBridgeTcpClient(packet.SerialNumber, address); - } - else if (knownMachine != null) - { - newMachine = new ExternalBridgeTcpClient(knownMachine, address); - } + LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); - if (newMachine != null) + ThreadsHelper.InvokeUINow(() => { - LogManager.Log("Found a new machine via TCP " + newMachine.SerialNumber); - - ThreadsHelper.InvokeUINow(() => - { - if (AvailableMachines.Count > 0) - { - AvailableMachines.Insert(1, newMachine); - } - else - { - AvailableMachines.Add(newMachine); - } - MachineDiscovered?.Invoke(this, newMachine); - }); - } + AvailableMachines.Insert(1, newMachine); + }); } } catch (Exception ex) @@ -278,65 +185,6 @@ namespace Tango.Integration.ExternalBridge } } - private void SignalRDiscoveryThreadMethod() - { - while (IsStarted && SignalRConfiguration.Enabled) - { - if (_connection.State == ConnectionState.Connected) - { - try - { - var machines = _proxy.Invoke<List<MachineInfo>>("GetAvailableMachines").Result; - - foreach (var machine in AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList().Where(x => !machines.Exists(y => y.SerialNumber == x.SerialNumber))) - { - AvailableMachines.Remove(machine); - MachineLost?.Invoke(this, machine); - } - - foreach (var machine in machines.Where(x => !AvailableMachines.OfType<ExternalBridgeSignalRClient>().ToList().Exists(y => y.SerialNumber == x.SerialNumber))) - { - ExternalBridgeSignalRClient newMachine = null; - var knownMachine = KnownMachines.FirstOrDefault(x => x.SerialNumber == machine.SerialNumber); - - if (knownMachine == null && KnownMachines.Count == 0) - { - newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, machine); - } - else if (knownMachine != null) - { - newMachine = new ExternalBridgeSignalRClient(SignalRConfiguration.Address, SignalRConfiguration.Hub, knownMachine, machine); - } - - if (newMachine != null) - { - LogManager.Log("Found a new machine via SignalR " + newMachine.SerialNumber); - - ThreadsHelper.InvokeUINow(() => - { - if (AvailableMachines.Count > 0) - { - AvailableMachines.Insert(1, newMachine); - } - else - { - AvailableMachines.Add(newMachine); - } - MachineDiscovered?.Invoke(this, newMachine); - }); - } - } - } - catch (Exception ex) - { - Debug.WriteLine(ex); - } - } - - Thread.Sleep(5000); - } - } - private DateTime ParseDateTime(String dateTime) { try @@ -360,7 +208,6 @@ namespace Tango.Integration.ExternalBridge { LogManager.Log("External bridge client failed or disposed. Removing from available machines..."); AvailableMachines.Remove(sender as IExternalBridgeClient); - MachineLost?.Invoke(this, sender as IExternalBridgeClient); } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs index 4218f9e9a..7ad03f3a7 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs @@ -21,41 +21,23 @@ using System.Security.Authentication; using Tango.Settings; using Tango.Core.ExtensionMethods; using Tango.PMR.MachineStatus; -using Tango.PMR.Power; -using Tango.Core; -using Microsoft.AspNet.SignalR.Client; -using Tango.Integration.ExternalBridge.Web; -using Tango.Core.Threading; -using System.Diagnostics; -using System.Reflection; -using Newtonsoft.Json; -using System.Collections.ObjectModel; namespace Tango.Integration.ExternalBridge { - public class ExternalBridgeService : ExtendedObject, IExternalBridgeService + public class ExternalBridgeService : BasicTransporter, IExternalBridgeService { - private List<ExternalBridgeReceiver> _receivers; private UdpDiscoveryService<ExternalBridgeUdpDiscoveryPacket> _discoveryService; private TcpServer _tcpServer; + private bool _send_app_logs; + private String _app_logs_token; + private Dictionary<MessageType, Action<MessageContainer>> _messageHandlers; private int _discovery_port = 8888; //Will be overridden by settings in constructor.. private int _external_bridge_port = 1984; //Will be overridden by settings in constructor.. - private HubConnection _connection; - private IHubProxy _proxy; - private bool _isSignalRConnected; - private System.Timers.Timer _signalrPingTimer; - private Dictionary<String, RequestHandler> _requestHandlers; - private static JsonSerializerSettings _genericMessageSettings = new JsonSerializerSettings() - { - TypeNameHandling = TypeNameHandling.All - }; - - private class RequestHandler - { - public IExternalBridgeRequestHandler Handler { get; set; } - public MethodInfo Method { get; set; } - public RequestHandlerLoggingMode LoggingMode { get; set; } - } + private String _eventsNotificationsToken; + private String _machineStatusUpdateToken; + private String _diagnosticsNotificationToken; + private String _debugLogsNotificationToken; + private bool _resend_diagnostics_and_debug; #region Events @@ -67,7 +49,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Occurs when the last client has been disconnected. /// </summary> - public event EventHandler FullControlSessionDisconnected; + public event EventHandler ClientDisconnected; /// <summary> /// Occurs when the service has received a new color profile request. @@ -78,29 +60,6 @@ namespace Tango.Integration.ExternalBridge #region Properties - public static HashSet<MessageType> SafetyLevelOperations { get; private set; } - - /// <summary> - /// Gets the collection of logged-in receivers. - /// </summary> - public List<ExternalBridgeReceiver> ActiveReceivers - { - get - { - return _receivers.Where(x => x.IsLoggedIn).ToList(); - } - } - - /// <summary> - /// Gets or sets the TCP transport adapter write mode when creating a TCP receiver. - /// </summary> - public TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; } - - /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - public ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - private IMachineOperator _machineOperator; /// <summary> /// Gets or sets the machine operator. @@ -150,60 +109,45 @@ namespace Tango.Integration.ExternalBridge } } - private bool _hasSessions; + private bool _isInSession; /// <summary> - /// Gets a value indicating whether there are any connected sessions. + /// Gets a value indicating whether a remote client is authenticated and in session. /// </summary> - public bool HasSessions + public bool IsInSession { - get { return _hasSessions; } - private set { _hasSessions = value; RaisePropertyChangedAuto(); } + get { return _isInSession; } + private set { _isInSession = value; RaisePropertyChangedAuto(); } } - private ExternalBridgeReceiver _fullControlSessionReceiver; /// <summary> - /// Gets the current full control session receiver. + /// Gets the current session login intent. /// </summary> - public ExternalBridgeReceiver FullControlSessionReceiver - { - get { return _fullControlSessionReceiver; } - private set { _fullControlSessionReceiver = value; RaisePropertyChangedAuto(); } - } + public ExternalBridgeLoginIntent SessionIntent { get; private set; } #endregion #region Constructors /// <summary> - /// Initializes the <see cref="ExternalBridgeService"/> class. - /// </summary> - static ExternalBridgeService() - { - SafetyLevelOperations = new HashSet<MessageType>(); - } - - /// <summary> /// Initializes a new instance of the <see cref="ExternalBridgeService"/> class. /// </summary> public ExternalBridgeService() { - _requestHandlers = new Dictionary<string, RequestHandler>(); - - SignalRConfiguration = new ExternalBridgeSignalRConfiguration(); - - TcpTransportAdapterWriteMode = TcpTransportAdapterWriteMode.Interval; - - _receivers = new List<ExternalBridgeReceiver>(); - var settings = SettingsManager.Default.GetOrCreate<IntegrationSettings>(); _discovery_port = settings.ExternalBridgeServiceDiscoveryPort; _external_bridge_port = settings.ExternalBridgeServicePort; + _messageHandlers = new Dictionary<MessageType, Action<MessageContainer>>(); + RegisterMessageHandlers(); + _tcpServer = new TcpServer(_external_bridge_port); _tcpServer.ClientConnected += _tcpServer_ClientConnected; LogManager.NewLog += LogManager_NewLog; + + KeepAliveTimeout = TimeSpan.FromSeconds(5); + KeepAliveRetries = 2; } /// <summary> @@ -252,12 +196,12 @@ namespace Tango.Integration.ExternalBridge { if (MachineOperator != null) { + MachineOperator.StateChanged -= MachineOperator_StateChanged; + MachineOperator.StateChanged += MachineOperator_StateChanged; MachineOperator.StatusChanged -= MachineOperator_StatusChanged; MachineOperator.StatusChanged += MachineOperator_StatusChanged; MachineOperator.PendingResponseReceived -= MachineOperator_PendingResponseReceived; MachineOperator.PendingResponseReceived += MachineOperator_PendingResponseReceived; - MachineOperator.EventsNotification -= MachineOperator_EventsNotification; - MachineOperator.EventsNotification += MachineOperator_EventsNotification; } } @@ -272,551 +216,603 @@ namespace Tango.Integration.ExternalBridge /// <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 TCP client connected from: " + e.Socket.GetIPAddress()); - ExternalBridgeReceiver receiver = new ExternalBridgeReceiver(e.Socket, MachineOperator); - (receiver.Adapter as TcpTransportAdapter).WriteMode = TcpTransportAdapterWriteMode; - receiver.LoginRequest += Receiver_LoginRequest; - receiver.ColorProfileRequest += Receiver_ColorProfileRequest; - receiver.Disconnected += Receiver_Disconnected; - receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; - _receivers.Add(receiver); - await receiver.Connect(); - RaisePropertyChanged(nameof(ActiveReceivers)); + if (!IsInSession) + { + UseKeepAlive = false; + LogManager.Log("External bridge client connected from: " + e.Socket.GetIPAddress()); + Adapter = new TcpTransportAdapter(e.Socket); + await Connect(); + } + else + { + e.Socket.Dispose(); + } } - private async void OnSignalRSessionCreated(String sessionID) + /// <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) { - try + //Do nothing right now. + if (e != TransportComponentState.Connected) { - LogManager.Log("External bridge SignalR client connected."); - - var adapter = new SignalRTransportAdapter(SignalRConfiguration.Address, SignalRConfiguration.Hub, SignalRTransportAdapterMode.JoinSession, Machine.SerialNumber, sessionID); ; - - ExternalBridgeReceiver receiver = new ExternalBridgeReceiver(adapter, MachineOperator); - receiver.LoginRequest += Receiver_LoginRequest; - receiver.ColorProfileRequest += Receiver_ColorProfileRequest; - receiver.Disconnected += Receiver_Disconnected; - receiver.ReceiverRequestReceived += Receiver_ReceiverRequestReceived; - _receivers.Add(receiver); - await receiver.Connect(); - RaisePropertyChanged(nameof(ActiveReceivers)); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error initializing SignalR ExternalBridgeReceiver when session created."); + _resend_diagnostics_and_debug = true; } } - private void MachineOperator_StatusChanged(object sender, MachineStatuses status) + private async void MachineOperator_StatusChanged(object sender, MachineStatuses e) { - try + if (e == MachineStatuses.ReadyToDye && _machineOperator.State == TransportComponentState.Connected) { - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics).ToList().ForEach(x => x.UpdateMachineOperatorStatus((UpdateStatus)status)); + if (IsInSession && _resend_diagnostics_and_debug) + { + _resend_diagnostics_and_debug = false; + + if (_diagnosticsNotificationToken != null) + { + var msg = MessageFactory.CreateTangoMessage<StartDiagnosticsRequest>(_diagnosticsNotificationToken); + _machineOperator.SendContinuousRequest<StartDiagnosticsRequest, StartDiagnosticsResponse>(msg); + } + if (_debugLogsNotificationToken != null) + { + var msg = MessageFactory.CreateTangoMessage<StartDebugLogRequest>(_debugLogsNotificationToken); + _machineOperator.SendContinuousRequest<StartDebugLogRequest, StartDebugLogResponse>(msg); + } + } } - catch (Exception ex) + + if (IsInSession) { - LogManager.Log(ex, "Error updating status of external bridge service client."); + try + { + UpdateStatus s = (UpdateStatus)e; + + await SendRequest<UpdateStatusRequest, UpdateStatusResponse>(new UpdateStatusRequest() + { + Status = s, + }); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error updating status of external bridge service client."); + } } } private void LogManager_NewLog(object sender, Tango.Logging.LogItemBase e) { - var toSend = _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresApplicationLogs).ToList(); - - if (_receivers.Count > 0) + if (State == TransportComponentState.Connected && _send_app_logs) { - var msg = MessageFactory.CreateTangoMessage<StartApplicationLogsResponse>(new StartApplicationLogsResponse() + try { - LogItem = ByteString.CopyFrom(e.Serialize()) - }); - - msg.ToBytes(); - - toSend.ToList().Where(x => x.State == TransportComponentState.Connected).ToList().ForEach(x => x.UpdateApplicationLogs(msg.Container)); + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse() + { + LogItem = ByteString.CopyFrom(e.Serialize()) + }, _app_logs_token); + } + catch { } } } + private void MachineOperator_PendingResponseReceived(object sender, MessageContainer container) { OnOperatorResponseReceived(container); } - private void MachineOperator_EventsNotification(object sender, StartEventsNotificationResponse e) + #endregion + + #region Public Methods + + /// <summary> + /// Starts this instance. + /// </summary> + public void Start() { - try + if (!IsStarted) { - MessageContainer container = new MessageContainer(); - container.Type = MessageType.StartEventsNotificationResponse; - container.Continuous = true; - container.Data = e.ToByteString(); + _tcpServer.Start(); + _discoveryService.Start(); - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresEventsNotification).ToList().ForEach(x => x.UpdateEvents(container)); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error on external bridge machine events broadcast."); + IsStarted = true; + _enabled = true; + RaisePropertyChanged(nameof(Enabled)); } } - #endregion - - #region Receiver Events Handlers - - private void Receiver_Disconnected(object sender, EventArgs e) + /// <summary> + /// Stops this instance. + /// </summary> + public async void Stop() { - var receiver = sender as ExternalBridgeReceiver; - - receiver.LoginRequest -= Receiver_LoginRequest; - receiver.ColorProfileRequest -= Receiver_ColorProfileRequest; - receiver.Disconnected -= Receiver_Disconnected; - receiver.ReceiverRequestReceived -= Receiver_ReceiverRequestReceived; - - _receivers.Remove(receiver); - - if (receiver.LoginIntent == ExternalBridgeLoginIntent.FullControl) + if (IsStarted) { - FullControlSessionDisconnected?.Invoke(this, new EventArgs()); - } - - HasSessions = _receivers.Count(x => x.IsLoggedIn) > 0; + _tcpServer.Stop(); + _discoveryService.Stop(); - FullControlSessionReceiver = _receivers.SingleOrDefault(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl); + IsStarted = false; + IsInSession = false; + _enabled = false; + RaisePropertyChanged(nameof(Enabled)); - //Notify request handlers about this receiver disconnected. - foreach (var requestHandler in _requestHandlers.ToList().Select(x => x.Value.Handler)) - { try { - requestHandler.OnReceiverDisconnected(receiver); + await Disconnect(); } - catch { } //Ignore exceptions on handler. + catch { } } - - RaisePropertyChanged(nameof(ActiveReceivers)); } - private void Receiver_ColorProfileRequest(object sender, ColorProfileRequestEventArgs e) + /// <summary> + /// Disconnects the current remote client session. + /// </summary> + public async void DisconnectSession() { - ColorProfileRequest?.Invoke(this, e); + await Disconnect(); } - private void Receiver_LoginRequest(object sender, ExternalBridgeReceiverLoginRequestEventArgs e) - { - var request = e.Request; - - if (request.Intent == ExternalBridgeLoginIntent.FullControl && _receivers.Any(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl)) - { - e.Decline("Only one full control client is allowed."); - return; - } - - if (request.Intent == ExternalBridgeLoginIntent.FullControl && MachineOperator.IsPrinting) - { - e.Decline($"External bridge client login failed because the machine is currently printing and '{ExternalBridgeLoginIntent.FullControl}' intent was requested."); - return; - } - - ExternalBridgeClientConnectedEventArgs args = null; - - args = new ExternalBridgeClientConnectedEventArgs(() => - { - //Confirmed - e.Confirm(Machine, MachineOperator.DeviceInformation, args.ApplicationInformation); - HasSessions = true; - - if (request.Intent == ExternalBridgeLoginIntent.FullControl) - { - FullControlSessionReceiver = sender as ExternalBridgeReceiver; - } - - RaisePropertyChanged(nameof(ActiveReceivers)); - }, (reason) => - { - //Declined - e.Decline(reason); - }); + #endregion - args.Request = request; - args.Address = e.Address; - ConnectionRequest?.Invoke(this, args); - } + #region Override Methods - private void Receiver_ReceiverRequestReceived(object sender, ExternalBridgeReceiverRequestReceivedEventArgs e) + protected override void OnRequestReceived(MessageContainer container) { - ExternalBridgeReceiver receiver = sender as ExternalBridgeReceiver; + base.OnRequestReceived(container); - if (e.Container.Type == MessageType.GenericRequest || _requestHandlers.ContainsKey(e.Container.Type.ToString())) + try { - e.Handled = true; - - ThreadFactory.StartNew(() => + if (Enabled) { - try + if (container.Type == MessageType.ConnectRequest || container.Type == MessageType.DisconnectRequest) { - var message = MessageFactory.ExtractMessageFromContainer(e.Container); - - if (e.Container.Type != MessageType.GenericRequest) //Handle standard PMR messages. + //Do nothing ! + } + else + { + if (IsInSession) { - var handler = _requestHandlers[e.Container.Type.ToString()]; - - if (handler.Method.ReturnType == typeof(Task)) + if (container.Type == MessageType.ExternalBridgeLoginRequest) { - ((Task)handler.Method.Invoke(handler.Handler, new object[] - { - message, - e.Container.Token, - sender, - })).Wait(); + SendErrorResponse(new AuthenticationException("Machine is already in session."), container.Token); + return; } - else - { - handler.Method.Invoke(handler.Handler, new object[] - { - message, - e.Container.Token, - sender, - }); - } - } - else //Handle GenericRequest with inner JSON/BSON formated generic message. - { - var genericType = Type.GetType((message as GenericRequest).Type); - if (genericType != null) + if (_messageHandlers.ContainsKey(container.Type)) { try { - if (_requestHandlers.ContainsKey(genericType.FullName)) + try { - var innerMessage = GenericMessageSerializer.DeserializeFromByteString(genericType, (message as GenericRequest).Data, receiver.GenericProtocol); - - var handler = _requestHandlers[genericType.FullName]; - - if (handler.LoggingMode == RequestHandlerLoggingMode.LogRequestName || handler.LoggingMode == RequestHandlerLoggingMode.LogRequestNameAndContent) - { - String content = "."; - - if (handler.LoggingMode == RequestHandlerLoggingMode.LogRequestNameAndContent) - { - content = $":\n{innerMessage.ToJsonString()}"; - } - - LogManager.Log($"'{innerMessage.GetType().Name}' received on '{handler.Method.DeclaringType.Name}.{handler.Method.Name}'{content}"); - } - - if (handler.Method.ReturnType == typeof(Task)) - { - ((Task)handler.Method.Invoke(handler.Handler, new object[] - { - innerMessage, - e.Container.Token, - sender, - })).Wait(); - } - else - { - handler.Method.Invoke(handler.Handler, new object[] - { - innerMessage, - e.Container.Token, - sender, - }); - } + _messageHandlers[container.Type](container); } - else + catch (Exception ex) { - receiver.SendErrorResponse(new NotSupportedException("Request message not supported on this PPC version."), e.Container.Token); + SendErrorResponse(ex, container.Token); } } catch (Exception ex) { - LogManager.Log(ex.GetFirstIfAggregate(), $"Error invoking external bridge handler for request '{genericType.Name}'."); - - try + if (ex is ResponseErrorException) { - receiver.SendErrorResponse(ex.GetFirstIfAggregate(), e.Container.Token); + SendResponse((ex as ResponseErrorException).Container); + } + else + { + SendErrorResponse(ex, container.Token); } - catch { } } } else { - receiver.SendErrorResponse(new NotSupportedException("Request message not supported on this PPC version."), e.Container.Token); + OnAnyRequest(container); } } - } - catch (Exception ex) - { - LogManager.Log(ex, $"An error occurred while trying or invoking an external bridge request handler for '{e.Container.Type}'."); - try + else { - receiver.SendErrorResponse(ex.GetFirstIfAggregate(), e.Container.Token); + if (container.Type == MessageType.ExternalBridgeLoginRequest) + { + OnExternalBridgeLoginRequest(container); + } + else if (container.Type == MessageType.ColorProfileRequest) + { + OnColorProfileRequest(container); + } } - catch { } } - }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, String.Format("An error occurred while processing a request message '{0}' from the remote host.", container.Type)); } } - #endregion + public async override Task Disconnect() + { + _send_app_logs = false; - #region Public Methods + try + { + if (IsInSession) + { + await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutRequest(), TimeSpan.FromSeconds(0.5)); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending an external bridge log out request."); + } + finally + { + ClearQueues(); + } - /// <summary> - /// Starts this instance. - /// </summary> - public void Start() + OnClientDisconnected(); + } + + protected override void OnFailed(Exception ex) { - if (!IsStarted) + if (ex is KeepAliveException) { - LogManager.Log("Starting external bridge service..."); + LogManager.Log("External bridge client has failed to provide a keep alive response. Disconnecting session..."); + } + + base.OnFailed(ex); + } + #endregion + + #region Virtual Methods + + protected async virtual void OnClientDisconnected() + { + _eventsNotificationsToken = null; + _machineStatusUpdateToken = null; + _diagnosticsNotificationToken = null; + _debugLogsNotificationToken = null; + IsInSession = false; + _send_app_logs = false; - LogManager.Log("Starting TCP server..."); + if (MachineOperator.State == TransportComponentState.Connected) + { try { - _tcpServer.Start(); + await MachineOperator.SendRequest(new StopDiagnosticsRequest()); } catch (Exception ex) { - LogManager.Log(ex, "Error starting external bridge TCP server."); + LogManager.Log(ex); } - LogManager.Log("Starting discovery service..."); try { - _discoveryService.Start(); + await MachineOperator.SendRequest(new StopDebugLogRequest()); } catch (Exception ex) { - LogManager.Log(ex, "Error starting external bridge discovery service."); + LogManager.Log(ex); } + } - if (SignalRConfiguration.Enabled) - { - StartSignalR(); - } + ClientDisconnected?.Invoke(this, new EventArgs()); - IsStarted = true; - _enabled = true; - RaisePropertyChanged(nameof(Enabled)); + try + { + await base.Disconnect(); } + catch (Exception ex) + { + LogManager.Log(ex); + } + + LogManager.Log("External bridge client disconnected."); } - private void StartSignalR() + protected virtual void OnOperatorResponseReceived(MessageContainer container) { - if (!_enabled || _isSignalRConnected) return; - try { - try - { - if (_connection != null) - { - _connection.Dispose(); - } - } - catch { } - - LogManager.Log("Starting SignalR service..."); - - _connection = new HubConnection(SignalRConfiguration.Address); - _proxy = _connection.CreateHubProxy(SignalRConfiguration.Hub); - _proxy.On<String>("OnSessionCreated", OnSignalRSessionCreated); - _connection.Start(); - _connection.StateChanged += (x) => + if (IsInSession) { - if (x.NewState == ConnectionState.Connected) + if (container.Type == MessageType.StartEventsNotificationResponse) { - try + if (_eventsNotificationsToken != null) { - LogManager.Log("External Bridge Service SignalR Connected. Registering machine..."); - - _proxy.Invoke("RegisterMachine", new MachineInfo() - { - SerialNumber = Machine.SerialNumber, - Organization = Machine.Organization.Name, - }); - - _isSignalRConnected = true; - - if (_signalrPingTimer == null) - { - _signalrPingTimer = new System.Timers.Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); - _signalrPingTimer.Elapsed += _signalrPingTimer_Elapsed; - _signalrPingTimer.Start(); - } + container.Token = _eventsNotificationsToken; + SendResponse(container); } - catch (Exception ex) + } + if (container.Type == MessageType.StartMachineStatusUpdateResponse) + { + if (_machineStatusUpdateToken != null) { - LogManager.Log(ex, "Error registering machine via SignalR."); + container.Token = _machineStatusUpdateToken; + SendResponse(container); } } - else if (x.NewState == ConnectionState.Disconnected) + else if (container.Type == MessageType.StartDiagnosticsResponse) { - _isSignalRConnected = false; - - if (Enabled) + if (_diagnosticsNotificationToken != null) { - LogManager.Log("External Bridge Service SignalR Disconnected/Failed. Reconnecting in 1 minute..."); - TimeoutTask.StartNew(StartSignalR, TimeSpan.FromMinutes(1)); + container.Token = _diagnosticsNotificationToken; + SendResponse(container); } } - else if (x.NewState == ConnectionState.Reconnecting) + else if (container.Type == MessageType.StartDebugLogResponse) { - LogManager.Log("External Bridge Service SignalR Connection Lost. Reconnecting..."); - //Will go invoke state change again with "connected" if successful... + if (_debugLogsNotificationToken != null) + { + container.Token = _debugLogsNotificationToken; + SendResponse(container); + } } - }; + } } - catch (Exception ex) - { - LogManager.Log(ex, "Error initializing External Bridge SignalR. Will try again in 5 minutes..."); + catch { } + } - TimeoutTask.StartNew(StartSignalR, TimeSpan.FromMinutes(5)); - } + #endregion + + #region Message Handlers + + private void RegisterMessageHandlers() + { + _messageHandlers.Add(MessageType.ExternalBridgeLogoutRequest, OnExternalBridgeLogoutRequest); + + _messageHandlers.Add(MessageType.StartApplicationLogsRequest, OnStartApplicationLogsRequest); + _messageHandlers.Add(MessageType.StopApplicationLogsRequest, OnStopApplicationLogsRequest); + + _messageHandlers.Add(MessageType.JobRequest, OnJobRequest); + + //Events + _messageHandlers.Add(MessageType.StartEventsNotificationRequest, OnStartEventsNotificationRequest); + _messageHandlers.Add(MessageType.StopEventsNotificationRequest, OnStopEventsNotificationRequest); + + //Machine Status + _messageHandlers.Add(MessageType.StartMachineStatusUpdateRequest, OnStartMachineStatusUpdateRequest); + _messageHandlers.Add(MessageType.StopMachineStatusUpdateRequest, OnStopMachineStatusUpdateRequest); + + //Diagnostics + _messageHandlers.Add(MessageType.StartDiagnosticsRequest, OnStartDiagnosticsRequest); + + //Debug Logs + _messageHandlers.Add(MessageType.StartDebugLogRequest, OnStartDebugLogRequest); } - private async void _signalrPingTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + protected virtual async void OnAnyRequest(MessageContainer container) { - if (Enabled && SignalRConfiguration.Enabled) + if (SessionIntent == ExternalBridgeLoginIntent.ColorProfile) { - if (_proxy != null) - { - try - { - var result = await _proxy.Invoke<String>("Ping"); - } - catch - { - Debug.WriteLine("Error pinging to machine service via SignalR."); - } - } + await SendErrorResponse(new AuthenticationException("The specified intent does not grant the specified action."), container.Token); + return; } - } - /// <summary> - /// Stops this instance. - /// </summary> - public async void Stop() - { - if (IsStarted) + if (!container.Continuous) { try { - _tcpServer.Stop(); - _discoveryService.Stop(); + var response = await MachineOperator.SendRequest(container); + await SendResponse(response); } + //catch (TimeoutException) + //{ + + //} catch (Exception ex) { - LogManager.Log(ex, "Error disposing TCP discovery services."); + await SendErrorResponse(ex, container.Token); } - - foreach (var receiver in _receivers.ToList()) + } + else + { + try { - try + MachineOperator.SendContinuousRequest(container).Subscribe((response) => { - await receiver.Disconnect(); - } - catch (Exception ex) + if (Enabled && IsInSession) + { + SendResponse(response); + } + + }, (ex) => { - LogManager.Log(ex, $"Error disconnecting receiver {receiver.ComponentName}."); - } + if (Enabled) + { + if (ex is ResponseErrorException) + { + SendResponse((ex as ResponseErrorException).Container); + } + } + }); + } + catch (Exception ex) + { + await SendErrorResponse(ex, container.Token); } + } + } - _enabled = false; + protected async virtual void OnExternalBridgeLoginRequest(MessageContainer container) + { + var request = MessageFactory.ParseTangoMessageFromContainer<ExternalBridgeLoginRequest>(container); + + LogManager.Log($"External bridge login attempt:\nIntent: {request.Message.Intent}\nMessage:\n{request.Message.ToJsonString()}"); - if (SignalRConfiguration.Enabled) + if (MachineOperator.Status != MachineStatuses.Printing || request.Message.Intent != ExternalBridgeLoginIntent.FullControl) + { + 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) { - try - { - _isSignalRConnected = false; - await _proxy.Invoke("UnregisterMachine"); - _connection.Stop(); - _connection.Dispose(); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error disposing SignalR connection."); - } + LogManager.Log("External bridge client has logged-in successfully."); + UseKeepAlive = true; + MachineOperator.EnableDiagnostics = false; + MachineOperator.EnableEmbeddedDebugging = false; + SessionIntent = request.Message.Intent; + } + else + { + LogManager.Log("External bridge client login failed, invalid password."); } - IsStarted = false; - HasSessions = false; - RaisePropertyChanged(nameof(Enabled)); + await SendResponse<ExternalBridgeLoginResponse>(response, container.Token, null, null, IsInSession ? null : "Invalid password or intent."); + } + else + { + LogManager.Log($"External bridge client login failed because the machine is currently printing and '{ExternalBridgeLoginIntent.FullControl}' intent was requested."); + await SendResponse<ExternalBridgeLoginResponse>(new ExternalBridgeLoginResponse(), container.Token, false, ErrorCode.GeneralError, $"Machine connection with '{ExternalBridgeLoginIntent.FullControl}' intent is not permitted while printing."); } } - /// <summary> - /// Disconnects the current remote client session. - /// </summary> - public async void DisconnectFullControlSession() + protected async virtual void OnExternalBridgeLogoutRequest(MessageContainer container) { - var sessionReceiver = _receivers.SingleOrDefault(x => x.IsLoggedIn && x.LoginIntent == ExternalBridgeLoginIntent.FullControl); - if (sessionReceiver != null) + try + { + await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); + } + catch (Exception ex) { - await sessionReceiver.Disconnect(); + LogManager.Log(ex); } + finally + { + ClearQueues(); + } + + OnClientDisconnected(); } - #endregion + protected virtual void OnStartApplicationLogsRequest(MessageContainer container) + { + if (SessionIntent == ExternalBridgeLoginIntent.Diagnostics || SessionIntent == ExternalBridgeLoginIntent.FullControl) + { + _app_logs_token = container.Token; + _send_app_logs = true; + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse(), container.Token); + } + else + { + throw new AuthenticationException("The specified intent does not grant the specified action."); + } + } - #region Virtual Methods + protected virtual void OnStopApplicationLogsRequest(MessageContainer container) + { + if (SessionIntent == ExternalBridgeLoginIntent.Diagnostics || SessionIntent == ExternalBridgeLoginIntent.FullControl) + { + _send_app_logs = false; + SendResponse<StopApplicationLogsResponse>(new StopApplicationLogsResponse() { }, container.Token); + SendResponse<StartApplicationLogsResponse>(new StartApplicationLogsResponse() { }, _app_logs_token, true); + } + else + { + throw new AuthenticationException("The specified intent does not grant the specified action."); + } + } - protected virtual void OnOperatorResponseReceived(MessageContainer container) + protected virtual void OnJobRequest(MessageContainer container) { - try + if (SessionIntent != ExternalBridgeLoginIntent.FullControl) { - switch (container.Type) - { - case MessageType.StartDiagnosticsResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresDiagnostics).ToList().ForEach(x => x.UpdateDiagnostics(container)); - break; - case MessageType.StartDebugLogResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresDebugLogs).ToList().ForEach(x => x.UpdateDebugLogs(container)); - break; - case MessageType.StartEventsNotificationResponse: - //_receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresEventsNotification).ToList().ForEach(x => x.UpdateEvents(container)); - break; - case MessageType.StartMachineStatusUpdateResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresMachineStatusUpdate).ToList().ForEach(x => x.UpdateMachineStatus(container)); - break; - case MessageType.StartInkFillingStatusResponse: - _receivers.ToList().Where(x => x.IsLoggedInAndRequiresDiagnostics && x.RequiresInkFillingStatus).ToList().ForEach(x => x.UpdateInkFillingStatus(container)); - break; - } + throw new InvalidOperationException($"Job execution is disabled while session intent is '{SessionIntent}'."); + } + if (MachineOperator.Status != MachineStatuses.ReadyToDye) + { + throw new InvalidOperationException($"Could not execute job while machine operator status is '{MachineOperator.Status}'."); + } + else + { + OnAnyRequest(container); } - catch { } } - #endregion + protected virtual void OnStartEventsNotificationRequest(MessageContainer container) + { + _eventsNotificationsToken = container.Token; + SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), container.Token); + } + + protected virtual void OnStopEventsNotificationRequest(MessageContainer container) + { + if (_eventsNotificationsToken != null) + { + SendResponse<StartEventsNotificationResponse>(new StartEventsNotificationResponse(), _eventsNotificationsToken, true); + _eventsNotificationsToken = null; + SendResponse<StopEventsNotificationResponse>(new StopEventsNotificationResponse(), container.Token); + } + } - #region Handlers Registration + protected virtual void OnStartMachineStatusUpdateRequest(MessageContainer container) + { + _machineStatusUpdateToken = container.Token; + SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), container.Token); + } - public void RegisterRequestHandler(IExternalBridgeRequestHandler handler) + protected virtual void OnStopMachineStatusUpdateRequest(MessageContainer container) { - foreach (var method in handler.GetType().GetMethods()) + if (_machineStatusUpdateToken != null) { - var att = method.GetCustomAttribute<ExternalBridgeRequestHandlerMethodAttribute>(); - if (att != null) - { - _requestHandlers.Add(att.Type is IMessage ? att.Type.Name : att.Type.FullName, new RequestHandler() - { - Handler = handler, - Method = method, - LoggingMode = att.LoggingMode, - }); - } + SendResponse<StartMachineStatusUpdateResponse>(new StartMachineStatusUpdateResponse(), _machineStatusUpdateToken, true); + _machineStatusUpdateToken = null; + SendResponse<StopMachineStatusUpdateResponse>(new StopMachineStatusUpdateResponse(), container.Token); + } + } + + protected virtual void OnStartDiagnosticsRequest(MessageContainer container) + { + if (_diagnosticsNotificationToken == null) + { + _diagnosticsNotificationToken = container.Token; + _machineOperator.SendContinuousRequest(container); } } - public void UnregisterRequestHandler(IExternalBridgeRequestHandler handler) + protected virtual void OnStartDebugLogRequest(MessageContainer container) { - foreach (var h in _requestHandlers.Where(x => x.Value.Handler == handler).ToList()) + if (_debugLogsNotificationToken == null) { - _requestHandlers.Remove(h.Key); + _debugLogsNotificationToken = container.Token; + _machineOperator.SendContinuousRequest(container); } } + private void OnColorProfileRequest(MessageContainer container) + { + var request = MessageFactory.ParseTangoMessageFromContainer<ColorProfileRequest>(container); + + ColorProfileRequestEventArgs e = new ColorProfileRequestEventArgs(request, async () => + { + //Approved. + await SendResponse<ColorProfileResponse>(new ColorProfileResponse() + { + Approved = true + }, container.Token); + await Task.Delay(500); + await base.Disconnect(); + }, + async () => + { + //Declined. + await SendResponse<ColorProfileResponse>(new ColorProfileResponse(), container.Token); + await Task.Delay(500); + await base.Disconnect(); + }); + + ColorProfileRequest?.Invoke(this, e); + } + #endregion } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs deleted file mode 100644 index a8f01437c..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRClient.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Authentication; -using System.Text; -using System.Threading.Tasks; -using Tango.BL; -using Tango.BL.Entities; -using Tango.Integration.ExternalBridge.Web; -using Tango.Integration.Operation; -using Tango.PMR.Integration; -using Tango.Settings; -using Tango.Transport; -using Tango.Transport.Adapters; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeSignalRClient : ExternalBridgeTcpClient - { - public ExternalBridgeSignalRClient(String url, String hub, MachineInfo machineInfo) - { - ComponentName = $"External Bridge SignalR Client {_component_counter++}"; - - SerialNumber = machineInfo.SerialNumber; - IPAddress = machineInfo.IPAddress; - Machine = ObservablesStaticCollections.Instance.Machines.SingleOrDefault(x => x.SerialNumber == SerialNumber); - Adapter = new SignalRTransportAdapter(url, hub, SignalRTransportAdapterMode.CreateSession, SerialNumber, null, IPAddress); - - KeepAliveTimeout = TimeSpan.FromSeconds(5); - KeepAliveRetries = 2; - UseKeepAlive = false; - } - - public ExternalBridgeSignalRClient(String url, String hub, Machine machine, MachineInfo machineInfo) - { - ComponentName = $"External Bridge SignalR Client {_component_counter++}"; - - SerialNumber = machine.SerialNumber; - IPAddress = machineInfo.IPAddress; - Machine = machine; - Adapter = new SignalRTransportAdapter(url, hub, SignalRTransportAdapterMode.CreateSession, SerialNumber, null, IPAddress); - - KeepAliveTimeout = TimeSpan.FromSeconds(5); - KeepAliveRetries = 2; - UseKeepAlive = false; - } - - /// <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 override 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 SignalR 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) - { - 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(); - } - } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs deleted file mode 100644 index cd511aa9b..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeSignalRConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - public class ExternalBridgeSignalRConfiguration - { - public bool Enabled { get; set; } - public String Address { get; set; } - public String Hub { get; set; } - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs index 0b2a0c608..8acff77d4 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeTcpClient.cs @@ -14,7 +14,6 @@ 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; @@ -31,8 +30,6 @@ namespace Tango.Integration.ExternalBridge { private bool _logs_sent; - public event EventHandler<LogItemBase> ApplicationLogAvailable; - #region Properties private String _serialNumber; @@ -74,113 +71,54 @@ namespace Tango.Integration.ExternalBridge } } - 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; } - - 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); + throw new NotImplementedException("External Bridge TCP client must connect through the dedicated connect method."); } /// <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> + /// <param name="login">The login.</param> /// <returns></returns> - /// <exception cref="AuthenticationException"></exception> - public virtual async Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null) + /// <exception cref="AuthenticationException">The machine password is invalid.</exception> + public async Task Connect(ExternalBridgeLoginRequest login) { if (State != TransportComponentState.Connected) { try { - Adapter.EnableCompression = false; - GenericProtocol = GenericMessageProtocol.Json; - + Adapter = new TcpTransportAdapter(IPAddress, SettingsManager.Default.GetOrCreate<IntegrationSettings>().ExternalBridgeServicePort); await Adapter.Connect(); State = TransportComponentState.Connected; StartThreads(); - LogManager.Log($"{ComponentName}: External Bridge TCP Client Connected..."); + LogManager.Log("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) - { - LogManager.Log(ex, $"{ComponentName}: Could not configure remote machine protocol. Could be an old PPC version."); - } - } - - ApplicationInformation = response.Message.ApplicationInformation; - - SessionLogger.CreateSession(); + LogRequestSent(login); + var response = await SendRequest<ExternalBridgeLoginRequest, ExternalBridgeLoginResponse>(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(); @@ -190,23 +128,15 @@ namespace Tango.Integration.ExternalBridge throw ex; } - ApplyContinuousChannelsConfiguration(); + OnEnableDiagnosticsChanged(EnableDiagnostics); + OnEnableEmbeddedDebuggingChanged(EnableEmbeddedDebugging); + OnEnableEventsNotification(EnableEventsNotification); + OnEnableApplicationLogsChanged(EnableApplicationLogs); + OnEnableMachineStatusUpdatesChanged(EnableMachineStatusUpdates); } } - 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) + private async void OnEnableApplicationLogsChanged(bool value) { if (value && State == TransportComponentState.Connected && !_logs_sent) { @@ -215,13 +145,14 @@ namespace Tango.Integration.ExternalBridge bool responseLogged = false; _logs_sent = true; - SendContinuousRequest<StartApplicationLogsRequest, StartApplicationLogsResponse>(request, new TransportContinuousRequestConfig() { ShouldLog = true }).ObserveOn(new NewThreadScheduler()) + SendContinuousRequest<StartApplicationLogsRequest, StartApplicationLogsResponse>(request).ObserveOn(new NewThreadScheduler()) .Subscribe ( (response) => { if (!responseLogged) { + LogResponseReceived(response.Message); responseLogged = true; } @@ -230,11 +161,18 @@ namespace Tango.Integration.ExternalBridge (ex) => { _logs_sent = false; + + if (!(ex is ContinuousResponseAbortedException)) + { + LogRequestFailed(request, ex); + } }, () => { _logs_sent = false; }); + + LogRequestSent(request); } else if (_logs_sent) { @@ -246,9 +184,14 @@ namespace Tango.Integration.ExternalBridge try { - var res = await SendRequest<StopApplicationLogsRequest, StopApplicationLogsResponse>(req, new TransportRequestConfig() { ShouldLog = true }); + LogRequestSent(req); + var res = await SendRequest<StopApplicationLogsRequest, StopApplicationLogsResponse>(req); + LogResponseReceived(res.Message); + } + catch (Exception ex) + { + LogRequestFailed(req, ex); } - catch { } } } } @@ -261,13 +204,7 @@ namespace Tango.Integration.ExternalBridge { LogItemBase log = LogItemBase.Deserialize(response.Message.LogItem.ToArray()); log.LogObject = "External Bridge"; - - if (InjectApplicationLogsToDefaultLogManager) - { - LogManager.Log(log); - } - - ApplicationLogAvailable?.Invoke(this, log); + LogManager.Log(log); } } catch (Exception ex) @@ -281,32 +218,27 @@ namespace Tango.Integration.ExternalBridge if (State == TransportComponentState.Connected) { ExternalBridgeLogoutRequest request = new ExternalBridgeLogoutRequest(); + LogRequestSent(request); try { - var response = await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(request, new TransportRequestConfig() { ShouldLog = true }); - } - catch { } + var response = await SendRequest<ExternalBridgeLogoutRequest, ExternalBridgeLogoutResponse>(request); + LogResponseReceived(response.Message); - Status = MachineStatuses.Standby; + Status = MachineStatuses.Standby; + } + catch (Exception ex) + { + LogRequestFailed(request, ex); + } } State = TransportComponentState.Disconnected; - - NotifyContinuousRequestMessagesDisconnection(); - - SessionLogger.EndSession(); - if (Adapter != null) { await Adapter.Disconnect(); } - LogManager.Log($"{ComponentName} disconnected."); - } - - internal ExternalBridgeTcpClient() - { - + LogManager.Log("External Bridge TCP client disconnected."); } /// <summary> @@ -316,34 +248,13 @@ namespace Tango.Integration.ExternalBridge /// <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; + 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); } /// <summary> @@ -361,22 +272,13 @@ namespace Tango.Integration.ExternalBridge /// Called when a new request has been received. /// </summary> /// <param name="request">The request.</param> - protected async override void OnRequestReceived(RequestReceivedEventArgs e) + protected async override void OnRequestReceived(MessageContainer request) { - base.OnRequestReceived(e); - - var container = e.Container; + base.OnRequestReceived(request); - if (container.Type == MessageType.ExternalBridgeLogoutRequest) + if (request.Type == MessageType.ExternalBridgeLogoutRequest) { - try - { - await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), container.Token); - } - catch { } - - await Task.Delay(2000); - + await SendResponse<ExternalBridgeLogoutResponse>(new ExternalBridgeLogoutResponse(), request.Token); try { State = TransportComponentState.Disconnected; @@ -387,19 +289,10 @@ namespace Tango.Integration.ExternalBridge 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> @@ -408,7 +301,7 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Gets the database machine associated with this client. /// </summary> - public Machine Machine { get; protected set; } + public Machine Machine { get; private set; } /// <summary> /// Sets the database machine. diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs index d7246fe7b..0767d73d5 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeUsbClient.cs @@ -68,11 +68,6 @@ namespace Tango.Integration.ExternalBridge } /// <summary> - /// Gets or sets a value indicating whether transport compression is required by the remote machine. - /// </summary> - public bool CompressionEnabled { get; set; } - - /// <summary> /// Connects the transport component. /// </summary> /// <returns></returns> @@ -98,7 +93,6 @@ namespace Tango.Integration.ExternalBridge /// <param name="device">The device.</param> public ExternalBridgeUsbClient(String comPort, String device,UsbSerialBaudRates baudRate = UsbSerialBaudRates.BR_115200) { - ComponentName = $"External Bridge USB Client {_component_counter++}"; ComPort = comPort; Device = device; BaudRate = baudRate; diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs deleted file mode 100644 index 753afc899..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeRequestHandler.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Google.Protobuf; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - /// <summary> - /// Represents an <see cref="IExternalBridgeService"/> request handler. - /// </summary> - public interface IExternalBridgeRequestHandler - { - /// <summary> - /// Called when any of the external bridge clients (receivers) has disconnected. - /// </summary> - /// <param name="receiver">The receiver.</param> - void OnReceiverDisconnected(ExternalBridgeReceiver receiver); - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs index aaf7efc2d..7d35963d4 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeSecureClient.cs @@ -21,9 +21,8 @@ namespace Tango.Integration.ExternalBridge /// <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> + /// <param name="login">The login.</param> /// <returns></returns> - Task Connect(ExternalBridgeLoginRequest login, ConfigureProtocolRequest protocol = null); + Task Connect(ExternalBridgeLoginRequest login); } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs index c7d2c8d5c..c0b41fd00 100644 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs +++ b/Software/Visual_Studio/Tango.Integration/ExternalBridge/IExternalBridgeService.cs @@ -1,7 +1,5 @@ -using Google.Protobuf; -using System; +using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,27 +7,21 @@ using Tango.BL.Entities; using Tango.Integration.Operation; using Tango.PMR.Integration; using Tango.Transport; -using Tango.Transport.Adapters; using Tango.Transport.Transporters; namespace Tango.Integration.ExternalBridge { - public interface IExternalBridgeService + public interface IExternalBridgeService : ITransporter { /// <summary> - /// Gets the collection of logged-in receivers. - /// </summary> - List<ExternalBridgeReceiver> ActiveReceivers { get; } - - /// <summary> /// Occurs when a new client is waiting for authentication. /// </summary> event EventHandler<ExternalBridgeClientConnectedEventArgs> ConnectionRequest; /// <summary> - /// Occurs when the current full control session has disconnected. + /// Occurs when the last client has been disconnected. /// </summary> - event EventHandler FullControlSessionDisconnected; + event EventHandler ClientDisconnected; /// <summary> /// Occurs when the service has received a new color profile request. @@ -47,21 +39,6 @@ namespace Tango.Integration.ExternalBridge Machine Machine { get; set; } /// <summary> - /// Gets or sets the SignalR configuration. - /// </summary> - ExternalBridgeSignalRConfiguration SignalRConfiguration { get; set; } - - /// <summary> - /// Gets the current full control session receiver. - /// </summary> - ExternalBridgeReceiver FullControlSessionReceiver { get; } - - /// <summary> - /// Gets or sets the TCP transport adapter write mode when creating a TCP receiver. - /// </summary> - TcpTransportAdapterWriteMode TcpTransportAdapterWriteMode { get; set; } - - /// <summary> /// Gets a value indicating whether this instance is started. /// </summary> bool IsStarted { get; } @@ -72,9 +49,9 @@ namespace Tango.Integration.ExternalBridge bool Enabled { get; set; } /// <summary> - /// Gets a value indicating whether there are any connected sessions. + /// Gets a value indicating whether a remote client is authenticated and in session. /// </summary> - bool HasSessions { get; } + bool IsInSession { get; } /// <summary> /// Starts this instance. @@ -89,18 +66,11 @@ namespace Tango.Integration.ExternalBridge /// <summary> /// Disconnects the current remote client session. /// </summary> - void DisconnectFullControlSession(); - - /// <summary> - /// Registers the request handler. - /// </summary> - /// <param name="handler">The handler.</param> - void RegisterRequestHandler(IExternalBridgeRequestHandler handler); + void DisconnectSession(); /// <summary> - /// Unregisters the request handler. + /// Gets the current session login intent. /// </summary> - /// <param name="handler">The handler.</param> - void UnregisterRequestHandler(IExternalBridgeRequestHandler handler); + ExternalBridgeLoginIntent SessionIntent { get; } } } diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs deleted file mode 100644 index c4b07e173..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/RequestHandlerLoggingMode.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tango.Integration.ExternalBridge -{ - public enum RequestHandlerLoggingMode - { - None, - LogRequestName, - LogRequestNameAndContent, - } -} diff --git a/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs b/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs deleted file mode 100644 index cccc24c35..000000000 --- a/Software/Visual_Studio/Tango.Integration/ExternalBridge/Web/MachineInfo.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Tango.PMR.Integration; -using Tango.Transport; - -namespace Tango.Integration.ExternalBridge.Web -{ - public class MachineInfo - { - public String SerialNumber { get; set; } - public String Organization { get; set; } - public String IPAddress { get; set; } - - public MachineInfo() - { - IPAddress = "Unknown"; - } - } -} |
