aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs
diff options
context:
space:
mode:
authorMirta <mirta@twine-s.com>2020-12-30 16:39:52 +0200
committerMirta <mirta@twine-s.com>2020-12-30 16:39:52 +0200
commit00a491d93733d4625ad329b2ba8237f445364b3f (patch)
tree4b24c6fa78d7648f4bb7cefafa464bb0b063fec4 /Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs
parent124ad4150f80c6846fdee41dbbda9848c105f6e5 (diff)
downloadTango-00a491d9.tar.gz
Tango-00a491d9.zip
merge
Diffstat (limited to 'Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs')
-rw-r--r--Software/Visual_Studio/Tango.Integration/ExternalBridge/ExternalBridgeService.cs908
1 files changed, 452 insertions, 456 deletions
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
}
}