/// <summary> /// Intent: Singleton. /// </summary> public static NetMqTransportShared Instance(Action <string> loggerDelegate = null) { if (_instance == null) { lock (_syncRoot) { if (_instance == null) { _instance = new NetMqTransportShared(loggerDelegate); } } } return(_instance); }
/// <summary> /// Intent: Singleton. /// </summary> public static NetMqTransportShared Instance(Action<string> loggerDelegate = null) { if (_instance == null) { lock (_syncRoot) { if (_instance == null) { _instance = new NetMqTransportShared(loggerDelegate); } } } return _instance; }
private void InitializePublisherOnFirstUse(string addressZeroMq) { if (_initializePublisherDone == false) // Double checked locking. { lock (_initializePublisherLock) { if (_initializePublisherDone == false) { _loggerDelegate?.Invoke(string.Format("Publisher socket binding to: {0}\n", AddressZeroMq)); _publisherSocket = NetMqTransportShared.Instance(_loggerDelegate).GetSharedPublisherSocket(addressZeroMq); _initializePublisherDone = true; } } } }
private void InitializeSubscriberOnFirstUse(string addressZeroMq) { if (_initializeSubscriberDone == false) // Double checked locking. { lock (_subscribersLock) { if (_initializeSubscriberDone == false) { if (_cancellationTokenSource == null) { _cancellationTokenSource = new CancellationTokenSource(); } _subscriberSocket = NetMqTransportShared.Instance(_loggerDelegate).GetSharedSubscriberSocket(addressZeroMq); ManualResetEvent threadReadySignal = new ManualResetEvent(false); _thread = new Thread(() => { try { _loggerDelegate?.Invoke(string.Format("Thread initialized.\n")); threadReadySignal.Set(); while (_cancellationTokenSource.IsCancellationRequested == false) { //_loggerDelegate?.Invoke(string.Format("Received message for {0}.\n", typeof(T))); string messageTopicReceived = _subscriberSocket.ReceiveFrameString(); if (messageTopicReceived != SubscriberFilterName) { // This message is for another subscriber. This should never occur. #if DEBUG throw new Exception( "Error E38444. Internal exception, this should never occur, as the ZeroMQ lib automaticlaly filters by subject name."); #else return; #endif } var type = _subscriberSocket.ReceiveFrameString(); switch (type) { // Originated from "OnNext". case "N": T messageReceived = _serializer.Deserialize(_subscriberSocket.ReceiveFrameBytes()); lock (_subscribersLock) { try { _subscribers.ForEach(o => o.OnNext(messageReceived)); } catch (Exception ex) { // If an unhandled exception is thrown inside the clients OnNext() event, we don't want this thread to die! _loggerDelegate?.Invoke(string.Format("Exception thrown on Subscription OnNext handler. Suggest adding an exception handler. Ignoring. Exception: {0}\n", ex)); } } break; // Originated from "OnCompleted". case "C": lock (_subscribersLock) { try { _subscribers.ForEach(o => o.OnCompleted()); } catch (Exception ex) { // If an unhandled exception is thrown inside the clients OnCompleted() event, we don't want this thread to die! _loggerDelegate?.Invoke(string.Format("Exception thrown on Subscription OnCompleted handler. Suggest adding an exception handler. Ignoring. Exception: {0}\n", ex)); } // We are done! We don't want to send any more messages to subscribers, and we // want to close the listening socket. _cancellationTokenSource.Cancel(); } break; // Originated from "OnException". case "E": Exception exception = null; try { // Not used, but useful for cross-platform debugging: we can read the error straight off the wire. string exceptionAsXml = _subscriberSocket.ReceiveFrameString(); exception = new Exception(exceptionAsXml); _subscriberSocket.ReceiveFrameBytes(); // For future expansion for a machine readable exception. } catch (Exception ex) { // If we had trouble deserializing the exception (probably due to a // different version of .NET), then do the next best thing: (1) The // inner exception is the error we got when deserializing, and (2) the // main exception is the human-readable "exception.ToString()" that we // originally captured. exception = new Exception("Error deserializing exception. To fix, recompile the remote sender with the same version as this subscriber.", ex); } lock (_subscribersLock) { try { _subscribers.ForEach(o => o.OnError(exception)); } catch (Exception ex) { // If an unhandled exception is thrown inside the clients OnCompleted() event, we don't want this thread to die! _loggerDelegate?.Invoke(string.Format("Exception thrown in Subscription OnError handler. Suggest adding an exception handler. Ignoring. Exception: {0}\n", ex)); } } break; // Originated from a "Ping" request. case "P": // Do nothing, this is a ping command used to wait until sockets are initialized properly. _loggerDelegate?.Invoke(string.Format("Received ping.\n")); break; default: throw new Exception(string.Format("Error E28734. Something is wrong - received '{0}' when we expected \"N\", \"C\" or \"E\" - are we out of sync?", type)); } } } catch (Exception ex) { _loggerDelegate?.Invoke(string.Format("Error E23844. Exception in threadName \"{0}\". Thread exiting. Exception: \"{1}\".\n", SubscriberFilterName, ex.Message)); lock (_subscribersLock) { this._subscribers.ForEach((ob) => ob.OnError(ex)); } } finally { lock (_subscribersLock) { _subscribers.Clear(); } _cancellationTokenSource.Dispose(); // Disconnect from the socket. _subscriberSocket.Dispose(); _threadWaitExitHandle.Set(); } }) { Name = this.SubscriberFilterName, IsBackground = true // Have to set it to background, or else it will not exit when the program exits. }; _thread.Start(); // Wait for subscriber thread to properly spin up. threadReadySignal.WaitOne(TimeSpan.FromMilliseconds(3000)); // Intent: Now connect to the socket. { _loggerDelegate?.Invoke(string.Format("Subscriber socket connecting to: {0}\n", addressZeroMq)); // this.SubscriberFilterName is set to the type T of the incoming class by default, so we can // have many types on the same transport. _subscriberSocket.Subscribe(this.SubscriberFilterName); } _loggerDelegate?.Invoke(string.Format("Subscriber: finished setup.\n")); _initializeSubscriberDone = true; } } // lock Thread.Sleep(500); // Otherwise, the first item we subscribe to may get missed by the subscriber. } }