Пример #1
0
        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));
            }
        }
Пример #2
0
        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();
            }
        }
Пример #3
0
        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"));
        }
Пример #4
0
        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"));
        }
Пример #5
0
        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"));
        }
Пример #6
0
        ///<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));
            }
        }
Пример #7
0
        ///<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"));
        }
Пример #8
0
        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"));
        }
Пример #9
0
        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);
            }));
        }