/// <summary> /// Creates a new <see cref="SubscriberConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="serverCommandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> /// <param name="clientCommandChannel"><see cref="TcpClient"/> command channel used to lookup connection information.</param> public SubscriberConnection(DataPublisher parent, Guid clientID, IServer serverCommandChannel, IClient clientCommandChannel) { m_parent = parent; ClientID = clientID; ServerCommandChannel = serverCommandChannel; ClientCommandChannel = clientCommandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; CacheUpdateLock = new(); PendingCacheUpdateLock = new(); // Setup ping timer m_pingTimer = Common.TimerScheduler.CreateTimer(5000); m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += PingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = Common.TimerScheduler.CreateTimer(1000); m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += ReconnectTimer_Elapsed; LookupEndPointInfo(clientID, GetCommandChannelSocket().RemoteEndPoint as IPEndPoint, ref m_ipAddress, ref m_hostName, ref m_connectionID); }
/// <summary> /// Creates a new <see cref="DataGapRecoverer"/>. /// </summary> public DataGapRecoverer() { Log = Logger.CreatePublisher(GetType(), MessageClass.Framework); Log.InitialStackMessages = Log.InitialStackMessages.Union("ComponentName", GetType().Name); m_dataGapRecoveryCompleted = new ManualResetEventSlim(true); m_recoveryStartDelay = DefaultRecoveryStartDelay; m_minimumRecoverySpan = DefaultMinimumRecoverySpan; m_maximumRecoverySpan = DefaultMaximumRecoverySpan; StartRecoveryBuffer = DefaultStartRecoveryBuffer; EndRecoveryBuffer = DefaultEndRecoveryBuffer; string loggingPath = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(DataSubscriber.DefaultLoggingPath)); if (Directory.Exists(loggingPath)) { m_loggingPath = loggingPath; } m_subscriptionInfo = new UnsynchronizedSubscriptionInfo(false); m_subscriptionInfo.FilterExpression = DefaultFilterExpression; m_subscriptionInfo.ProcessingInterval = DefaultRecoveryProcessingInterval; m_subscriptionInfo.UseMillisecondResolution = DefaultUseMillisecondResolution; m_dataStreamMonitor = Common.TimerScheduler.CreateTimer((int)(DefaultDataMonitoringInterval * 1000.0D)); m_dataStreamMonitor.Elapsed += DataStreamMonitor_Elapsed; m_dataStreamMonitor.AutoReset = true; m_dataStreamMonitor.Enabled = false; }
/// <summary> /// Constructs a new instance of the <see cref="OutputAdapterBase"/>. /// </summary> protected OutputAdapterBase() { m_metadataRefreshOperation = new LongSynchronizedOperation(ExecuteMetadataRefresh) { IsBackground = true }; m_measurementQueue = ProcessQueue <IMeasurement> .CreateRealTimeQueue(ProcessMeasurements); m_measurementQueue.ProcessException += m_measurementQueue_ProcessException; m_connectionOperation = new LongSynchronizedOperation(AttemptConnectionOperation) { IsBackground = true }; m_connectionTimer = Common.TimerScheduler.CreateTimer(2000); m_connectionTimer.Elapsed += m_connectionTimer_Elapsed; m_connectionTimer.AutoReset = false; m_connectionTimer.Enabled = false; // We monitor total number of unarchived measurements every 5 seconds - this is a useful statistic to monitor, if // total number of unarchived measurements gets very large, measurement archival could be falling behind m_monitorTimer = Common.TimerScheduler.CreateTimer(5000); m_monitorTimer.Elapsed += m_monitorTimer_Elapsed; m_monitorTimer.AutoReset = true; m_monitorTimer.Enabled = false; }
public RandomDataViewModel( // This will be a unique IUpbeatService created and injected by the IUpbeatStack specifically for this ViewModel. IUpbeatService upbeatService, // This will be an injected transient instance of a Random service. Random random, // This is a shared singleton service. SharedTimer sharedTimer) { _upbeatService = upbeatService ?? throw new ArgumentNullException(nameof(upbeatService)); _random = random ?? throw new ArgumentNullException(nameof(random)); _sharedTimer = sharedTimer ?? throw new ArgumentNullException(nameof(sharedTimer)); _sharedTimer.Ticked += SharedTimerTicked; // DelegateCommand is a common convenience ICommand implementation to call methods or lambda expressions when the command is executed. It supports both async and non-async methods/lambdas. OpenPositionedPopupCommand = new DelegateCommand <Func <Point> >( // Create a Parameters object for a ViewModel and pass it to the IUpbeatStack using OpenViewModel. The IUpbeatStack will use the configured mappings to create the appropriate ViewModel from the Parameters type. pointGetter => _upbeatService.OpenViewModel( new PopupViewModel.Parameters { Message = "This popup appears on top of\nthe button that opened it.", // The pointGetter parameter is a Func<Point> created by the View that will return the position within the window of the control that executed this command. See the bindings in View\RandomDataControl.xaml for details on how to bind a pointGetter() as a CommandParameter. Position = pointGetter(), })); RefreshDataCommand = new DelegateCommand(RefreshData); Data = new ReadOnlyObservableCollection <KeyValuePair <string, string> >(_data); for (var i = 0; i < 100; i++) { _data.Add(CreateRandomKeyValuePair()); } }
/// <summary> /// Releases the unmanaged resources used by the <see cref="UnsynchronizedClientSubscription"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { m_parent = null; // Dispose base time rotation timer if ((object)m_baseTimeRotationTimer != null) { m_baseTimeRotationTimer.Dispose(); m_baseTimeRotationTimer = null; } // Dispose Iaon session this.DisposeTemporalSession(ref m_iaonSession); } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
public MenuViewModel( // This will be a unique IUpbeatService created and injected by the IUpbeatStack specifically for this ViewModel. IUpbeatService upbeatService, // This ViewModel requires an async delegate to be provided, so it can start closing the application. Func <Task> closeApplicationCallbackAsync, // This is a shared singleton service. SharedTimer sharedTimer) { _upbeatService = upbeatService ?? throw new NullReferenceException(nameof(upbeatService)); _ = closeApplicationCallbackAsync ?? throw new NullReferenceException(nameof(closeApplicationCallbackAsync)); _sharedTimer = sharedTimer ?? throw new NullReferenceException(nameof(sharedTimer)); _sharedTimer.Ticked += SharedTimerTicked; // DelegateCommand is a common convenience ICommand implementation to call methods or lambda expressions when the command is executed. It supports both async and non-async methods/lambdas. ExitCommand = new DelegateCommand(closeApplicationCallbackAsync); OpenRandomDataCommand = new DelegateCommand( () => { // Create a Parameters object for a ViewModel and pass it to the IUpbeatStack using OpenViewModel. The IUpbeatStack will use the configured mappings to create the appropriate ViewModel from the Parameters type. _upbeatService.OpenViewModel(new RandomDataViewModel.Parameters()); // Since this is Side Menu, it can close after the requested ViewModel is opened. _upbeatService.Close(); }); OpenSharedListCommand = new DelegateCommand( () => { _upbeatService.OpenViewModel(new SharedListViewModel.Parameters()); _upbeatService.Close(); }); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="DataGapRecoverer"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_dataGapRecoveryCompleted != null) { // Signal any waiting threads m_abnormalTermination = true; m_dataGapRecoveryCompleted.Set(); m_dataGapRecoveryCompleted.Dispose(); } if ((object)m_dataStreamMonitor != null) { m_dataStreamMonitor.Elapsed -= DataStreamMonitor_Elapsed; m_dataStreamMonitor.Dispose(); m_dataStreamMonitor = null; } if ((object)m_dataGapLogProcessor != null) { m_dataGapLogProcessor.Dispose(); m_dataGapLogProcessor = null; } if ((object)m_dataGapLog != null) { m_dataGapLog.ProcessException -= Common_ProcessException; m_dataGapLog.Dispose(); m_dataGapLog = null; } if ((object)m_temporalSubscription != null) { m_temporalSubscription.StatusMessage -= Common_StatusMessage; m_temporalSubscription.ProcessException -= Common_ProcessException; m_temporalSubscription.ConnectionEstablished -= TemporalSubscription_ConnectionEstablished; m_temporalSubscription.ConnectionTerminated -= TemporalSubscription_ConnectionTerminated; m_temporalSubscription.NewMeasurements -= TemporalSubscription_NewMeasurements; m_temporalSubscription.ProcessingComplete -= TemporalSubscription_ProcessingComplete; m_temporalSubscription.Dispose(); m_temporalSubscription = null; } } } finally { m_disposed = true; // Prevent duplicate dispose. if ((object)Disposed != null) { Disposed(this, EventArgs.Empty); } } } }
public BottomViewModel( // This will be a unique IUpbeatService created and injected by the IUpbeatStack specifically for this ViewModel. IUpbeatService upbeatService, // This is a shared singleton service. SharedTimer sharedTimer) { _upbeatService = upbeatService ?? throw new NullReferenceException(nameof(upbeatService)); _sharedTimer = sharedTimer ?? throw new NullReferenceException(nameof(sharedTimer)); // Registering a CloseCallback allows the ViewModel to prevent itself from closing. For example: if there is unsaved work. This can also completely prevent the application from shutting down. CloseCallbacks can be either async or non-async methods/lambdas. _upbeatService.RegisterCloseCallback(AskBeforeClosingAsync); _sharedTimer.Ticked += SharedTimerTicked; // DelegateCommand is a common convenience ICommand implementation to call methods or lambda expressions when the command is executed. It supports both async and non-async methods/lambdas. OpenMenuCommand = new DelegateCommand( // Create a Parameters object for a ViewModel and pass it to the IUpbeatStack using OpenViewModel. The IUpbeatStack will use the configured mappings to create the appropriate ViewModel from the Parameters type. () => _upbeatService.OpenViewModel( new MenuViewModel.Parameters())); OpenSharedListCommand = new DelegateCommand( () => _upbeatService.OpenViewModel( new SharedListViewModel.Parameters())); OpenRandomDataCommand = new DelegateCommand( () => _upbeatService.OpenViewModel( new RandomDataViewModel.Parameters())); }
/// <summary> /// Releases the unmanaged resources used by the <see cref="ClientConnection"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if ((object)m_pingTimer != null) { m_pingTimer.Elapsed -= m_pingTimer_Elapsed; m_pingTimer.Dispose(); m_pingTimer = null; } if ((object)m_reconnectTimer != null) { m_reconnectTimer.Elapsed -= m_reconnectTimer_Elapsed; m_reconnectTimer.Dispose(); m_reconnectTimer = null; } DataChannel = null; m_commandChannel = null; m_ipAddress = null; m_subscription = null; m_parent = null; } } finally { m_disposed = true; // Prevent duplicate dispose. } } }
/// <summary> /// Initializes <see cref="SynchronizedClientSubscription"/>. /// </summary> public override void Initialize() { MeasurementKey[] inputMeasurementKeys; string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) { // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null // in order to prevent SQL injection via the subscription filter expression inputMeasurementKeys = AdapterBase.ParseInputMeasurementKeys(DataSource, false, setting); m_requestedInputFilter = setting; // IMPORTANT: We need to remove the setting before calling base.Initialize() // or else we will still be subject to SQL injection Settings.Remove("inputMeasurementKeys"); } else { inputMeasurementKeys = new MeasurementKey[0]; m_requestedInputFilter = null; } base.Initialize(); // Set the InputMeasurementKeys and UsePrecisionTimer properties after calling // base.Initialize() so that the base class does not overwrite our settings InputMeasurementKeys = inputMeasurementKeys; UsePrecisionTimer = false; if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting)) { m_bufferBlockRetransmissionTimeout = double.Parse(setting); } else { m_bufferBlockRetransmissionTimeout = 5.0D; } if (Settings.TryGetValue("requestNaNValueFilter", out setting)) { m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean(); } else { m_isNaNFiltered = false; } m_bufferBlockRetransmissionTimer = Common.TimerScheduler.CreateTimer((int)(m_bufferBlockRetransmissionTimeout * 1000.0D)); m_bufferBlockRetransmissionTimer.AutoReset = false; m_bufferBlockRetransmissionTimer.Elapsed += BufferBlockRetransmissionTimer_Elapsed; // Handle temporal session initialization if (this.TemporalConstraintIsDefined()) { m_iaonSession = this.CreateTemporalSession(); } }
public void SharedTimer_Disposed_NoCallback() { var timerSet = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { timer.Register(_ => timerSet.Set(), null); } Assert.False(timerSet.WaitOne(100)); }
public void SharedTimer_DisposeRegistrationQuickly_NoCallback() { var timerSet = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { IDisposable cleanup = timer.Register(_ => timerSet.Set(), null); cleanup.Dispose(); Assert.False(timerSet.WaitOne(100)); } }
public void SharedTimer_Register_CallbackInvoked() { var timerSet = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { using (IDisposable cleanup = timer.Register(_ => timerSet.Set(), null)) { Assert.NotNull(cleanup); Assert.True(timerSet.WaitOne(100)); } } }
/// <summary> /// Initializes a new instance of the <see cref="FileClient"/> class. /// </summary> /// <param name="connectString">Connect string of the <see cref="FileClient"/>. See <see cref="DefaultConnectionString"/> for format.</param> public FileClient(string connectString) : base(TransportProtocol.File, connectString) { m_autoRepeat = DefaultAutoRepeat; m_receiveOnDemand = DefaultReceiveOnDemand; m_receiveInterval = DefaultReceiveInterval; m_startingOffset = DefaultStartingOffset; FileOpenMode = DefaultFileOpenMode; FileShareMode = DefaultFileShareMode; m_fileAccessMode = DefaultFileAccessMode; m_fileClient = new TransportProvider <FileStream>(); m_receiveDataTimer = s_timerScheduler.CreateTimer(); m_receiveDataTimer.Elapsed += m_receiveDataTimer_Elapsed; }
/// <summary> /// Constructs a new instance of the <see cref="InputAdapterBase"/>. /// </summary> protected InputAdapterBase() { m_connectionOperation = new LongSynchronizedOperation(AttemptConnectionOperation) { IsBackground = true }; m_connectionTimer = Common.TimerScheduler.CreateTimer(2000); m_connectionTimer.Elapsed += m_connectionTimer_Elapsed; m_connectionTimer.AutoReset = false; m_connectionTimer.Enabled = false; }
public void SharedTimer_OneCallbackThrows_OtherCallbacksInvoked() { var timerSet0 = new ManualResetEvent(false); var timerSet1 = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { timer.Register(_ => timerSet0.Set(), null); timer.Register(_ => { throw new InvalidOperationException(); }, null); timer.Register(_ => timerSet1.Set(), null); Assert.True(timerSet0.WaitOne(500)); Assert.True(timerSet1.WaitOne(500)); } }
public PopupViewModel( // These are the parameters the parent used when opening this ViewModel. The IUpbeatService can inject the Parameters object into this constructor to pass initialization data or callbacks. Parameters parameters, // This is a shared singleton service. SharedTimer sharedTimer) { _ = parameters ?? throw new NullReferenceException(nameof(parameters)); _sharedTimer = sharedTimer ?? throw new ArgumentNullException(nameof(sharedTimer)); Message = parameters.Message; XPosition = parameters.Position.X; YPosition = parameters.Position.Y; _sharedTimer.Ticked += SharedTimerTicked; }
public void SharedTimer_RegisterState_CallbackInvokedWithState() { var myState = new object(); bool? correctState = null; var timerSet = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { timer.Register(state => { correctState = (myState == state); timerSet.Set(); }, myState); Assert.True(timerSet.WaitOne(100)); Assert.True(correctState.Value); } }
public void SharedTimer_DisposeOne_OtherCallbacksInvoked() { var timerSet0 = new ManualResetEvent(false); var timerSet1 = new ManualResetEvent(false); var timerSet2 = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { IDisposable dispose0 = timer.Register(_ => timerSet0.Set(), null); IDisposable dispose1 = timer.Register(_ => timerSet1.Set(), null); IDisposable dispose2 = timer.Register(_ => timerSet2.Set(), null); dispose1.Dispose(); Assert.True(timerSet0.WaitOne(100)); Assert.True(timerSet2.WaitOne(100)); Assert.False(timerSet1.WaitOne(100)); } }
public void SharedTimer_RegisterState_CallbackInvokedWithState() { var myState = new object(); bool?correctState = null; var timerSet = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { timer.Register(state => { correctState = (myState == state); timerSet.Set(); }, myState); Assert.True(timerSet.WaitOne(100)); Assert.True(correctState.Value); } }
public ConfirmPopupViewModel // This will be a unique IUpbeatService created and injected by the IUpbeatStack specifically for this ViewModel. (IUpbeatService upbeatService, // These are the parameters the parent used when opening this ViewModel. The IUpbeatService can inject the Parameters object into this constructor to pass initialization data or callbacks. Parameters parameters, // This is a shared singleton service. SharedTimer sharedTimer) : base(parameters, sharedTimer) { // DelegateCommand is a common convenience ICommand implementation to call methods or lambda expressions when the command is executed. It supports both async and non-async methods/lambdas. ConfirmCommand = new DelegateCommand( () => { parameters?.ConfirmCallback?.Invoke(); // Will close this ViewModel. upbeatService.Close(); }); }
public SharedListViewModel( // This will be a unique IUpbeatService created and injected by the IUpbeatStack for this ViewModel and child ViewModels. IUpbeatService upbeatService, // This is a scoped service shared between this ViewModel and other ViewModel or scoped/transient service dependencies. SharedList sharedList, // This is a shared singleton service. SharedTimer sharedTimer, // This is a child ViewModel, which can help with separating concerns and keep ViewModels from being too complicated. Child ViewModels share an IUpbeatService and any scoped services with their parents. SharedListDataViewModel sharedListDataViewModel) { _upbeatService = upbeatService ?? throw new NullReferenceException(nameof(upbeatService)); _sharedTimer = sharedTimer ?? throw new NullReferenceException(nameof(sharedTimer)); _sharedList = sharedList ?? throw new ArgumentNullException(nameof(sharedList)); SharedListDataViewModel = sharedListDataViewModel ?? throw new ArgumentNullException(nameof(sharedListDataViewModel)); _sharedTimer.Ticked += SharedTimerTicked; _sharedList.StringAdded += SharedListStringAdded; CloseCommand = new DelegateCommand(_upbeatService.Close); }
public void SharedTimer_Register5_CallbacksInvoked() { var timerSet0 = new ManualResetEvent(false); var timerSet1 = new ManualResetEvent(false); var timerSet2 = new ManualResetEvent(false); var timerSet3 = new ManualResetEvent(false); var timerSet4 = new ManualResetEvent(false); using (var timer = new SharedTimer(TimeSpan.FromMilliseconds(20))) { timer.Register(_ => timerSet0.Set(), null); timer.Register(_ => timerSet1.Set(), null); timer.Register(_ => timerSet2.Set(), null); timer.Register(_ => timerSet3.Set(), null); timer.Register(_ => timerSet4.Set(), null); Assert.True(timerSet0.WaitOne(100)); Assert.True(timerSet1.WaitOne(100)); Assert.True(timerSet2.WaitOne(100)); Assert.True(timerSet3.WaitOne(100)); Assert.True(timerSet4.WaitOne(100)); } }
/// <summary> /// Releases the unmanaged resources used by the <see cref="InputAdapterBase"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if (m_connectionTimer != null) { m_connectionTimer.Elapsed -= m_connectionTimer_Elapsed; m_connectionTimer.Dispose(); } m_connectionTimer = null; } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
/// <summary> /// Creates a new <see cref="DataGapRecoverer"/>. /// </summary> public DataGapRecoverer() { Log = Logger.CreatePublisher(GetType(), MessageClass.Framework); Log.InitialStackMessages = Log.InitialStackMessages.Union("ComponentName", GetType().Name); m_dataGapRecoveryCompleted = new(true); m_recoveryStartDelay = DefaultRecoveryStartDelay; m_minimumRecoverySpan = DefaultMinimumRecoverySpan; m_maximumRecoverySpan = DefaultMaximumRecoverySpan; StartRecoveryBuffer = DefaultStartRecoveryBuffer; EndRecoveryBuffer = DefaultEndRecoveryBuffer; string loggingPath = FilePath.GetDirectoryName(FilePath.GetAbsolutePath(DataSubscriber.DefaultLoggingPath)); if (Directory.Exists(loggingPath)) { m_loggingPath = loggingPath; } m_subscriptionInfo = new() { FilterExpression = DefaultFilterExpression, ProcessingInterval = DefaultRecoveryProcessingInterval, UseMillisecondResolution = DefaultUseMillisecondResolution }; m_dataStreamMonitor = Common.TimerScheduler.CreateTimer((int)(DefaultDataMonitoringInterval * 1000.0D)); m_dataStreamMonitor.Elapsed += DataStreamMonitor_Elapsed; m_dataStreamMonitor.AutoReset = true; m_dataStreamMonitor.Enabled = false; } /// <summary> /// Releases the unmanaged resources before the <see cref="DataGapRecoverer"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~DataGapRecoverer() => Dispose(false);
/// <summary> /// Releases the unmanaged resources used by the <see cref="OutputAdapterBase"/> object and optionally releases the managed resources. /// </summary> /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (!m_disposed) { try { if (disposing) { if (m_connectionTimer != null) { m_connectionTimer.Elapsed -= m_connectionTimer_Elapsed; m_connectionTimer.Dispose(); } m_connectionTimer = null; if (m_monitorTimer != null) { m_monitorTimer.Elapsed -= m_monitorTimer_Elapsed; m_monitorTimer.Dispose(); } m_monitorTimer = null; if (m_measurementQueue != null) { m_measurementQueue.ProcessException -= m_measurementQueue_ProcessException; m_measurementQueue.Dispose(); } m_measurementQueue = null; } } finally { m_disposed = true; // Prevent duplicate dispose. base.Dispose(disposing); // Call base class Dispose(). } } }
/// <summary> /// Creates a new <see cref="ClientConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="commandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> public ClientConnection(DataPublisher parent, Guid clientID, IServer commandChannel) { m_parent = parent; m_clientID = clientID; m_commandChannel = commandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; // Setup ping timer m_pingTimer = Common.TimerScheduler.CreateTimer(5000); m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += m_pingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = Common.TimerScheduler.CreateTimer(1000); m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += m_reconnectTimer_Elapsed; // Attempt to lookup remote connection identification for logging purposes try { Socket commandChannelSocket = GetCommandChannelSocket(); IPEndPoint remoteEndPoint = null; if ((object)commandChannel != null) { remoteEndPoint = commandChannelSocket.RemoteEndPoint as IPEndPoint; } if ((object)remoteEndPoint != null) { m_ipAddress = remoteEndPoint.Address; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { m_connectionID = "[" + m_ipAddress + "]:" + remoteEndPoint.Port; } else { m_connectionID = m_ipAddress + ":" + remoteEndPoint.Port; } try { IPHostEntry ipHost = Dns.GetHostEntry(remoteEndPoint.Address); if (!string.IsNullOrWhiteSpace(ipHost.HostName)) { m_hostName = ipHost.HostName; m_connectionID = m_hostName + " (" + m_connectionID + ")"; } } // Just ignoring possible DNS lookup failures... catch (ArgumentNullException) { // The hostNameOrAddress parameter is null. } catch (ArgumentOutOfRangeException) { // The length of hostNameOrAddress parameter is greater than 255 characters. } catch (ArgumentException) { // The hostNameOrAddress parameter is an invalid IP address. } catch (SocketException) { // An error was encountered when resolving the hostNameOrAddress parameter. } } } catch { // At worst we'll just use the client GUID for identification m_connectionID = m_subscriberID == Guid.Empty ? clientID.ToString() : m_subscriberID.ToString(); } if (string.IsNullOrWhiteSpace(m_connectionID)) { m_connectionID = "unavailable"; } if (string.IsNullOrWhiteSpace(m_hostName)) { if ((object)m_ipAddress != null) { m_hostName = m_ipAddress.ToString(); } else { m_hostName = m_connectionID; } } if ((object)m_ipAddress == null) { m_ipAddress = IPAddress.None; } }
/// <summary> /// Initializes <see cref="UnsynchronizedClientSubscription"/>. /// </summary> public override void Initialize() { MeasurementKey[] inputMeasurementKeys; string setting; if (Settings.TryGetValue("inputMeasurementKeys", out setting)) { // IMPORTANT: The allowSelect argument of ParseInputMeasurementKeys must be null // in order to prevent SQL injection via the subscription filter expression inputMeasurementKeys = ParseInputMeasurementKeys(DataSource, false, setting); m_requestedInputFilter = setting; // IMPORTANT: We need to remove the setting before calling base.Initialize() // or else we will still be subject to SQL injection Settings.Remove("inputMeasurementKeys"); } else { inputMeasurementKeys = new MeasurementKey[0]; m_requestedInputFilter = null; } base.Initialize(); // Set the InputMeasurementKeys property after calling base.Initialize() // so that the base class does not overwrite our setting InputMeasurementKeys = inputMeasurementKeys; if (!Settings.TryGetValue("publishInterval", out setting) || !double.TryParse(setting, out m_publishInterval)) { m_publishInterval = -1; } if (Settings.TryGetValue("includeTime", out setting)) { m_includeTime = setting.ParseBoolean(); } else { m_includeTime = true; } if (Settings.TryGetValue("useMillisecondResolution", out setting)) { m_useMillisecondResolution = setting.ParseBoolean(); } else { m_useMillisecondResolution = false; } if (Settings.TryGetValue("requestNaNValueFilter", out setting)) { m_isNaNFiltered = m_parent.AllowNaNValueFilter && setting.ParseBoolean(); } else { m_isNaNFiltered = false; } if (Settings.TryGetValue("bufferBlockRetransmissionTimeout", out setting)) { m_bufferBlockRetransmissionTimeout = double.Parse(setting); } else { m_bufferBlockRetransmissionTimeout = 5.0D; } if (m_parent.UseBaseTimeOffsets && m_includeTime) { m_baseTimeRotationTimer = Common.TimerScheduler.CreateTimer(m_useMillisecondResolution ? 60000 : 420000); m_baseTimeRotationTimer.AutoReset = true; m_baseTimeRotationTimer.Elapsed += BaseTimeRotationTimer_Elapsed; } m_bufferBlockRetransmissionTimer = Common.TimerScheduler.CreateTimer((int)(m_bufferBlockRetransmissionTimeout * 1000.0D)); m_bufferBlockRetransmissionTimer.AutoReset = false; m_bufferBlockRetransmissionTimer.Elapsed += BufferBlockRetransmissionTimer_Elapsed; // Handle temporal session initialization if (this.TemporalConstraintIsDefined()) { m_iaonSession = this.CreateTemporalSession(); } }