/// <summary>
        /// Common entry-point for all the "request" public synchronous methods
        /// </summary>
        /// <param name="message"></param>
        /// <param name="timeout"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private MsgOut RequestCore(
            MsgIn message,
            TimeSpan timeout,
            CancellationToken token
            )
        {
            InFlightRequest request = null;

            try
            {
                request = this._rrmgr.SetupRequest(message);
                this.PublishCore(message, timeout, token);
            }
            catch (Exception ex)
            {
                if (request != null)
                {
                    this._rrmgr.DropRequest(request);
                    request.Dispose();
                }
                throw ex;
            }

            return(request.GetReply(timeout, token));
        }
Example #2
0
        /// <summary>
        /// Publishes a <see cref="MsgIn"/> instance, which includes the subject, an optional reply, and an
        /// optional data field.
        /// </summary>
        /// <remarks>
        /// <para>NATS implements a publish-subscribe message distribution model. NATS publish subscribe is a
        /// one-to-many communication. A publisher sends a message on a subject. Any active subscriber listening
        /// on that subject receives the message. Subscribers can register interest in wildcard subjects.</para>
        /// <para>In the basic NATS platfrom, if a subscriber is not listening on the subject (no subject match),
        /// or is not acive when the message is sent, the message is not received. NATS is a fire-and-forget
        /// messaging system. If you need higher levels of service, you can either use NATS Streaming, or build the
        /// additional reliability into your client(s) yourself.</para>
        /// </remarks>
        /// <param name="message">A <see cref="MsgIn"/> instance containing the subject, optional reply, and data to publish
        /// to the NATS server.</param>
        /// <param name="timeout">Represents the time to wait for the connection going stable.</param>
        /// <param name="token">Propagates notification that operations should be canceled.</param>
        public void Publish(MsgIn message, TimeSpan timeout, CancellationToken token)
        {
            if (timeout <= TimeSpan.Zero)
            {
                throw new ArgumentException("Timeout must be greater than zero.", nameof(timeout));
            }

            this.PublishCore(message, timeout, token);
        }
        /// <summary>
        /// Sends a request payload and returns the response <see cref="MsgOut"/>, or throws
        /// <see cref="NATSTimeoutException"/> if the <paramref name="timeout"/> expires.
        /// </summary>
        /// <remarks>
        /// <para>NATS supports two flavors of request-reply messaging: point-to-point or one-to-many. Point-to-point
        /// involves the fastest or first to respond. In a one-to-many exchange, you set a limit on the number of
        /// responses the requestor may receive and instead must use a subscription (<see cref="ISubscription.AutoUnsubscribe(int)"/>).
        /// In a request-response exchange, publish request operation publishes a message with a reply subject expecting
        /// a response on that reply subject.</para>
        /// <para><see cref="Request(MsgIn, TimeSpan, CancellationToken)"/> will create an unique inbox for this request, sharing a single
        /// subscription for all replies to this <see cref="Connection"/> instance. However, if
        /// <see cref="ClientOptions.UseOldRequestStyle"/> is set, each request will have its own underlying subscription.
        /// The old behavior is not recommended as it may cause unnecessary overhead on connected NATS servers.</para>
        /// </remarks>
        /// <param name="message">A <see cref="MsgIn"/> instance containing the subject, optional reply, and data to publish
        /// to the NATS server.</param>
        /// <param name="timeout">Represents the overall time to wait for the connection going stable, if not, and for the message loopback.</param>
        /// <param name="token">Propagates notification that operations should be canceled.</param>
        /// <returns>A <see cref="MsgOut"/> with the response from the NATS server.</returns>
        public MsgOut Request(MsgIn message, TimeSpan timeout, CancellationToken token)
        {
            if (timeout <= TimeSpan.Zero)
            {
                throw new ArgumentException("Timeout must be greater than zero.", nameof(timeout));
            }

            return(this.RequestCore(message, timeout, token));
        }
        /// <summary>
        /// Sets an <see cref="InFlightRequest"/> instance up,
        /// as proxy for a request-reply process.
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        internal InFlightRequest SetupRequest(MsgIn message)
        {
            InFlightRequest request;

            lock (this._reqlocker)
            {
                request = new InFlightRequest(this, ++this._reqId);
                this._requestRegister.Add(request.ReqId, request);
            }

            message.InboxRequest = request;
            return(request);
        }
Example #5
0
        /// <summary>
        /// Common entry-point for all the "publish" public methods
        /// </summary>
        /// <param name="message"></param>
        /// <param name="timeout"></param>
        /// <param name="token"></param>
        private void PublishCore(
            MsgIn message,
            TimeSpan timeout,
            CancellationToken token
            )
        {
            if (this._connmgr.IsLogicalStarted == false)
            {
                this._connmgr.WaitLogicalStart(timeout, token);
            }

            // Proactively reject payloads over the threshold set by server.
            int payloadLength = message.PayloadInternal.Length;

            if (payloadLength > this._connmgr.MaxPayload)
            {
                throw new NATSMaxPayloadException();
            }

            //ensures the following section mutex-accessed
            lock (this._pubLocker)
            {
                //build the header as described here:
                //https://nats.io/documentation/internals/nats-protocol/
                this._pubBuilder.Length = 0;
                this._pubBuilder.Append(InternalConstants._PUB_P_);
                this._pubBuilder.Append(message.Subject);
                this._pubBuilder.Append(' ');

                if (message.InboxRequest != null)
                {
                    this._pubBuilder.Append(message.InboxRequest.ReplyToSubject);
                    this._pubBuilder.Append(' ');
                }
                else if (message.ReplyTo.Length != 0)
                {
                    this._pubBuilder.Append(message.ReplyTo);
                    this._pubBuilder.Append(' ');
                }

                this._pubBuilder.Append(payloadLength.ToString(CultureInfo.InvariantCulture));
                this._pubBuilder.Append(InternalConstants._CRLF_);
                int buflen = Encoding.UTF8.GetBytes(this._pubBuilder.ToString(), 0, this._pubBuilder.Length, this._pubProtoBuf, 0);

                //outstreams the pub data (header and payload)
                this._connmgr.WritePubData(
                    new ArraySegment <byte>(this._pubProtoBuf, 0, buflen),
                    message.PayloadInternal
                    );
            }
        }
Example #6
0
 /// <summary>
 /// Publishes a <see cref="MsgIn"/> instance, which includes the subject, an optional reply, and an
 /// optional data field.
 /// </summary>
 /// <remarks>
 /// <para>NATS implements a publish-subscribe message distribution model. NATS publish subscribe is a
 /// one-to-many communication. A publisher sends a message on a subject. Any active subscriber listening
 /// on that subject receives the message. Subscribers can register interest in wildcard subjects.</para>
 /// <para>In the basic NATS platfrom, if a subscriber is not listening on the subject (no subject match),
 /// or is not acive when the message is sent, the message is not received. NATS is a fire-and-forget
 /// messaging system. If you need higher levels of service, you can either use NATS Streaming, or build the
 /// additional reliability into your client(s) yourself.</para>
 /// </remarks>
 /// <param name="message">A <see cref="MsgIn"/> instance containing the subject, optional reply, and data to publish
 /// to the NATS server.</param>
 /// <param name="token">Propagates notification that operations should be canceled.</param>
 public void Publish(MsgIn message, CancellationToken token)
 {
     this.PublishCore(message, Timeout.InfiniteTimeSpan, token);
 }
 /// <summary>
 /// Sends a request payload and returns the response <see cref="MsgOut"/>, or throws
 /// <see cref="NATSTimeoutException"/> if the <paramref name="timeout"/> expires.
 /// </summary>
 /// <remarks>
 /// <para>NATS supports two flavors of request-reply messaging: point-to-point or one-to-many. Point-to-point
 /// involves the fastest or first to respond. In a one-to-many exchange, you set a limit on the number of
 /// responses the requestor may receive and instead must use a subscription (<see cref="ISubscription.AutoUnsubscribe(int)"/>).
 /// In a request-response exchange, publish request operation publishes a message with a reply subject expecting
 /// a response on that reply subject.</para>
 /// <para><see cref="Request(MsgIn, CancellationToken)"/> will create an unique inbox for this request, sharing a single
 /// subscription for all replies to this <see cref="Connection"/> instance. However, if
 /// <see cref="ClientOptions.UseOldRequestStyle"/> is set, each request will have its own underlying subscription.
 /// The old behavior is not recommended as it may cause unnecessary overhead on connected NATS servers.</para>
 /// </remarks>
 /// <param name="message">A <see cref="MsgIn"/> instance containing the subject, optional reply, and data to publish
 /// to the NATS server.</param>
 /// <param name="token">Propagates notification that operations should be canceled.</param>
 /// <returns>A <see cref="MsgOut"/> with the response from the NATS server.</returns>
 public MsgOut Request(MsgIn message, CancellationToken token)
 {
     return(this.RequestCore(message, Timeout.InfiniteTimeSpan, token));
 }
 /// <summary>
 /// Sends a request payload and returns the response <see cref="MsgOut"/>, or throws
 /// <see cref="NATSTimeoutException"/> if the <paramref name="timeout"/> expires.
 /// </summary>
 /// <remarks>
 /// <para>NATS supports two flavors of request-reply messaging: point-to-point or one-to-many. Point-to-point
 /// involves the fastest or first to respond. In a one-to-many exchange, you set a limit on the number of
 /// responses the requestor may receive and instead must use a subscription (<see cref="ISubscription.AutoUnsubscribe(int)"/>).
 /// In a request-response exchange, publish request operation publishes a message with a reply subject expecting
 /// a response on that reply subject.</para>
 /// <para><see cref="RequestAsync(MsgIn, CancellationToken)"/> will create an unique inbox for this request, sharing a single
 /// subscription for all replies to this <see cref="Connection"/> instance. However, if
 /// <see cref="ClientOptions.UseOldRequestStyle"/> is set, each request will have its own underlying subscription.
 /// The old behavior is not recommended as it may cause unnecessary overhead on connected NATS servers.</para>
 /// </remarks>
 /// <param name="message">A <see cref="MsgIn"/> instance containing the subject, optional reply, and data to publish
 /// to the NATS server.</param>
 /// <param name="token">Propagates notification that operations should be canceled.</param>
 /// <returns>A task that represents the asynchronous read operation. The value of the <see cref="Task{TResult}.Result"/>
 /// parameter contains a <see cref="MsgOut"/> with the response from the NATS server.</returns>
 public Task <MsgOut> RequestAsync(MsgIn message, CancellationToken token)
 {
     return(this.RequestAsync(message, Timeout.InfiniteTimeSpan, token));
 }