internal static XtResult <TMessage> ParsePubSubMessage <TMessage>(this NetMQMessage msg, SocketConfiguration configuration) where TMessage : class { const string operation = "parse-pub-sub-msg"; if (msg.FrameCount != 2) { var exc = ZeroMqXtSocketException.MissedExpectedFrameCount(msg.FrameCount); configuration.Logger.Log(new DebugLogMsg(exc.Message)); return(XtResult <TMessage> .Failed(ZeroMqXtSocketException.MissedExpectedFrameCount(msg.FrameCount, 2))); } var receivedType = configuration.Serializer.Deserialize <string>(msg.First.ToByteArray()); if (receivedType != typeof(TMessage).FullName) { return(XtResult <TMessage> .Failed(ZeroMqXtSocketException.Frame1TypeDoesNotMatch <TMessage>(receivedType))); } try { var instance = configuration.Serializer.Deserialize <TMessage>(msg.Last.ToByteArray()); return(XtResult <TMessage> .Success(instance, operation : operation)); } catch (System.Exception ex) { return(XtResult <TMessage> .Failed(ex, operation : operation)); } }
public async Task <XtResult <TMessage> > PublishAsync <TMessage>(TMessage message) where TMessage : class, new() { PublisherSocket publisherSocket = null; try { publisherSocket = new PublisherSocket(); publisherSocket.Connect(_configuration.Address()); return(await Task.Run(() => { try { var msg = new PubSubMessage <TMessage>(_configuration, message); publisherSocket.SendMultipartMessage(msg); } catch (System.Exception ex) { return XtResult <TMessage> .Failed(ex, "publish"); } return XtResult <TMessage> .Success(message, "publish"); })); } catch (System.Exception ex) { return(XtResult <TMessage> .Failed(ex, "publish")); } finally { publisherSocket?.Dispose(); } }
public XtResult SetupReceiverAsync <TMessage>(Func <TMessage, Task> asyncCallback, CancellationToken token = default) where TMessage : class, new() { var setupResult = _rqRs.RespondAsync <TMessage, EmptyResponse>(async(msg) => { await asyncCallback(msg); return(new EmptyResponse()); }, token); return(setupResult.IsSuccess ? XtResult.Success("receiveAsync") : XtResult.Failed(setupResult.Exception, "receiveAsync")); }
public XtResult SetupReceiver <TMessage>(Action <TMessage> callback, CancellationToken token = default) where TMessage : class, new() { var setupResult = _rqRs.Respond <TMessage, EmptyResponse>((msg) => { callback(msg); return(new EmptyResponse()); }, token); return(setupResult.IsSuccess ? XtResult.Success("receive") : XtResult.Failed(setupResult.Exception, "receive")); }
public async Task <XtResult> SendAsync <TMessage>(TMessage message) where TMessage : class, new() { var xtResult = await _rqRs.RequestAsync <TMessage, EmptyResponse>(message); return(xtResult.IsSuccess ? XtResult.Success("send") : XtResult.Failed(xtResult.Exception, "send")); }
///<summary> /// Construct a Message from ReceivedFrames - according to /// <para>Frame 1 - RequestTypeName</para> /// <para>Frame 2 - Successful parsing and use of Incoming Instance of RequestType / on Response it is the successful deserialization</para> /// <para>Frame 3 - Actual Payload and instance of the RequestType</para> ///</summary> internal static XtResult <TMessage> ParseRqRepMessage <TMessage>(this NetMQMessage msg, SocketConfiguration configuration) where TMessage : class { configuration.Logger.Log(new DebugLogMsg($"parsing [{typeof(TMessage)}]")); const string operation = "parse-rq-rep-msg"; #region precondition checks if (msg.FrameCount != 3) { var exc = ZeroMqXtSocketException.MissedExpectedFrameCount(msg.FrameCount); configuration.Logger.Log(new DebugLogMsg(exc.Message)); return(XtResult <TMessage> .Failed(exc, operation)); } byte[] typeFrame = msg.Pop().ToByteArray(); byte[] successFrame = msg.Pop().ToByteArray(); byte[] payloadFrame = msg.Pop().ToByteArray(); string msgType = typeof(TMessage).TypeFrameName(); string typeFromFrame = configuration.Serializer.Deserialize <string>(typeFrame); if (typeFromFrame != msgType) { var exception = ZeroMqXtSocketException.Frame1TypeDoesNotMatch <TMessage>(typeFromFrame); configuration.Logger.Log(new DebugLogMsg(exception.Message)); return(XtResult <TMessage> .Failed(exception, operation)); } bool isSuccess = Convert.ToBoolean(configuration.Serializer.Deserialize <string>(successFrame)); if (!isSuccess) { var exceptnText = configuration.Serializer.Deserialize <string>(payloadFrame); var excption = new ZeroMqXtSocketException("Server failed with" + exceptnText); configuration.Logger.Log(new DebugLogMsg(excption.Message)); return(XtResult <TMessage> .Failed(excption, operation)); } #endregion try { // actual message body deserialization TMessage result = configuration.Serializer.Deserialize <TMessage>(payloadFrame); if (result == default(TMessage)) { return(XtResult <TMessage> .Failed(new ArgumentNullException($"{typeof(TMessage)} yielded the default value on deserializing! Proceeding is not safe."), operation)); } configuration.Logger.Log(new DebugLogMsg($"parsing was successful for [{typeof(TMessage)}]")); return(XtResult <TMessage> .Success(result, operation)); } catch (System.Exception ex) { return(XtResult <TMessage> .Failed(ZeroMqXtSocketException.SerializationFailed(ex.Message), operation)); } }
///<summary> /// necessary indirection for the responsehandler to be used in sync or async fashion ///</summary> private XtResult SetupResponder <T, TResult>(ResponseHandler <T, TResult> handler, CancellationToken token) where T : class, new() where TResult : class { lock (concurrencyToken) { if (responderIsSetup) { throw new ZeroMqXtSocketException("Responder for this instance of Socket exists already. Use a new instance for each server!"); } responderIsSetup = true; respondingIsActive = true; } poller = new NetMQ.NetMQPoller(); responseSocket = new ResponseSocket(); // handle notifies when the server is set up eventHandle = new ManualResetEvent(false); // create a new background thread with the response callback Exception faultingException = null; _ = Task.Run(() => { try { responseSocket.Bind(_configuration.Address()); // add to poller and register handler poller.Add(responseSocket); receiveHandler = async(s, e) => await ResponseHandlerCallback(responseSocket, handler, token); responseSocket.ReceiveReady += receiveHandler; poller.RunAsync(); } catch (Exception exception) { faultingException = exception; _configuration.Logger.Log(new ErrorLogMsg(exception.GetType().Name + "-" + exception.Message)); Dispose(); } finally { // open resetevent after binding to the socket and when the poller is started eventHandle.Set(); } }, token); // wait for the Set inside the background thread so we can know at the calling client that the server is set up properly eventHandle.WaitOne(); return(faultingException == null ? XtResult.Success("setup-response") : XtResult.Failed(ZeroMqXtSocketException.FromException(faultingException), "setup-response")); }
private XtResult RegisterHandler <TMessage>(Action <TMessage> syncCallback = null, Func <TMessage, Task> asyncCallback = null, CancellationToken token = default) where TMessage : class, new() { Exception exception = null; // handle notifies when the server is set up eventHandle = new ManualResetEvent(false); _ = Task.Run(() => { var next = new SubscriberHandler <TMessage> ( new SubscriberSocket(), _configuration, new NetMQ.NetMQPoller(), token, syncCallback: syncCallback, asyncCallback: asyncCallback ); var(success, exception) = next.Setup(); // dispose handler when an exception was registered during setup if (exception is not null) { next.Dispose(); return; } // add subscriber to dispsables to get rid of them later lock (_concurrencyToken) { _handlers.Add(next); } // open resetevent after using setup on the handler and after the poller has started asynchronously eventHandle.Set(); }); eventHandle.WaitOne(); if (exception is not null) { return(XtResult.Failed(exception, "register-subscriber")); } return(XtResult.Success("register-subscriber")); }
private async Task <XtResult <TResult> > DoRequestAsync <T, TResult>(T request) where T : class, new() where TResult : class { const string operation = "request"; _configuration.Logger.Log(new DebugLogMsg($"Send Request<{typeof(T)}, {typeof(TResult)}> to Address - {_configuration.Address()}")); using var rqSocket = new RequestSocket(); rqSocket.Connect(_configuration.Address()); var message = new RequestReplyMessage <T>(_configuration, request); return(await Task.Run(() => { // the request to be send with timeout bool rqDidNotTimeOut = rqSocket.TrySendMultipartMessage(_configuration.TimeOut, message); if (!rqDidNotTimeOut) { return XtResult <TResult> .Failed(new TimeoutException($"Request<{typeof(T)}, {typeof(TResult)}> timed out"), operation); } _configuration.Logger.Log(new DebugLogMsg($"successfully sent [Request:{typeof(T)}] and waiting for response [Response:{typeof(TResult)}]")); // wait for the response with timeout var response = new NetMQMessage(); bool noTimeOut = rqSocket.TryReceiveMultipartMessage(_configuration.TimeOut, ref response, expectedFrameCount: 3); if (!noTimeOut) { return XtResult <TResult> .Failed(new TimeoutException($"Request<{typeof(T)}, {typeof(TResult)}> timed out"), operation); } _configuration.Logger.Log(new DebugLogMsg($"received Response [Response:{typeof(TResult)}]")); // parse the response and return the result var xtResult = response.ParseRqRepMessage <TResult>(_configuration); return xtResult.IsSuccess ? XtResult <TResult> .Success(xtResult.GetResult(), operation) : XtResult <TResult> .Failed(xtResult.Exception, operation); })); }