コード例 #1
0
ファイル: Topic.cs プロジェクト: liuhd1992/rdkafka-dotnet
        public Task <DeliveryReport> Produce(byte[] payload, byte[] key = null, Int32 partition = RD_KAFKA_PARTITION_UA)
        {
            // Passes the TaskCompletionSource to the delivery report callback
            // via the msg_opaque pointer
            var deliveryCompletionSource = new TaskCompletionSource <DeliveryReport>();
            var gch = GCHandle.Alloc(deliveryCompletionSource);

            while (true)
            {
                if (handle.Produce(payload, key, partition, GCHandle.ToIntPtr(gch)) == 0)
                {
                    // Successfully enqueued produce request
                    break;
                }

                ErrorCode err = LibRdKafka.last_error();
                if (err == ErrorCode._QUEUE_FULL)
                {
                    // Wait and retry
                    Task.Delay(TimeSpan.FromMilliseconds(50)).Wait();
                }
                else
                {
                    gch.Free();
                    throw RdKafkaException.FromErr(err, "Could not produce message");
                }
            }

            return(deliveryCompletionSource.Task);
        }
コード例 #2
0
ファイル: Topic.cs プロジェクト: zhijia1122/rdkafka-dotnet
        internal Topic(SafeKafkaHandle kafkaHandle, Producer producer, string topic, TopicConfig config,
                       out LibRdKafka.PartitionerCallback partitionerDelegate)
        {
            // PartitionerDelegate is an out parameter as its reference must be kept outside of Topic
            // it may be called after topic is GC, and it may be different for different topics
            // so we can't simply make it static here
            this.producer = producer;

            config = config ?? new TopicConfig();
            config["produce.offset.report"] = "true";
            IntPtr configPtr = config.handle.Dup();

            if (config.CustomPartitioner != null)
            {
                partitionerDelegate = (IntPtr rkt, IntPtr keydata, UIntPtr keylen, int partition_cnt,
                                       IntPtr rkt_opaque, IntPtr msg_opaque) =>
                {
                    byte[] key = null;
                    if (keydata != IntPtr.Zero)
                    {
                        key = new byte[(int)keylen];
                        Marshal.Copy(keydata, key, 0, (int)keylen);
                    }
                    return(config.CustomPartitioner(this, key, partition_cnt));
                };
                LibRdKafka.topic_conf_set_partitioner_cb(configPtr, partitionerDelegate);
            }
            else
            {
                partitionerDelegate = null;
            }

            handle = kafkaHandle.Topic(topic, configPtr);
        }
コード例 #3
0
        private void Produce(
            string topic,
            byte[] val, int valOffset, int valLength,
            byte[] key, int keyOffset, int keyLength,
            long?timestamp,
            Int32 partition, bool blockIfQueueFull,
            IDeliveryHandler deliveryHandler)
        {
            SafeTopicHandle topicHandle = getKafkaTopicHandle(topic);

            if (!this.disableDeliveryReports && deliveryHandler != null)
            {
                // Passes the TaskCompletionSource to the delivery report callback via the msg_opaque pointer
                var deliveryCompletionSource = deliveryHandler;
                var gch = GCHandle.Alloc(deliveryCompletionSource);
                var ptr = GCHandle.ToIntPtr(gch);

                if (topicHandle.Produce(val, valOffset, valLength, key, keyOffset, keyLength, partition, timestamp, ptr, blockIfQueueFull) != 0)
                {
                    var err = LibRdKafka.last_error();
                    gch.Free();
                    throw new KafkaException(err, "Could not produce message");
                }

                return;
            }

            if (topicHandle.Produce(val, valOffset, valLength, key, keyOffset, keyLength, partition, timestamp, IntPtr.Zero, blockIfQueueFull) != 0)
            {
                var err = LibRdKafka.last_error();
                throw new KafkaException(err, "Could not produce message");
            }

            return;
        }
コード例 #4
0
ファイル: Topic.cs プロジェクト: qed-/rdkafka-dotnet
        private void Produce(byte[] payload, byte[] key, Int32 partition, object deliveryHandler)
        {
            var gch = GCHandle.Alloc(deliveryHandler);
            var ptr = GCHandle.ToIntPtr(gch);

            while (true)
            {
                if (handle.Produce(payload, key, partition, ptr) == 0)
                {
                    // Successfully enqueued produce request
                    break;
                }

                var err = LibRdKafka.last_error();
                if (err == ErrorCode._QUEUE_FULL)
                {
                    // Wait and retry
                    Task.Delay(TimeSpan.FromMilliseconds(50)).Wait();
                }
                else
                {
                    gch.Free();
                    throw RdKafkaException.FromErr(err, "Could not produce message");
                }
            }
        }
コード例 #5
0
ファイル: Topic.cs プロジェクト: liuhd1992/rdkafka-dotnet
        internal Topic(SafeKafkaHandle kafkaHandle, Producer producer, string topic, TopicConfig config)
        {
            this.producer = producer;

            config = config ?? new TopicConfig();
            config["produce.offset.report"] = "true";
            IntPtr configPtr = config.handle.Dup();

            if (config.CustomPartitioner != null)
            {
                PartitionerDelegate = (IntPtr rkt, IntPtr keydata, UIntPtr keylen, int partition_cnt,
                                       IntPtr rkt_opaque, IntPtr msg_opaque) =>
                {
                    byte[] key = null;
                    if (keydata != IntPtr.Zero)
                    {
                        key = new byte[(int)keylen];
                        Marshal.Copy(keydata, key, 0, (int)keylen);
                    }
                    return(config.CustomPartitioner(this, key, partition_cnt));
                };
                LibRdKafka.topic_conf_set_partitioner_cb(configPtr, PartitionerDelegate);
            }

            handle = kafkaHandle.Topic(topic, configPtr);
        }
コード例 #6
0
        /// <summary>
        ///     Initializes a new Producer instance.
        /// </summary>
        /// <param name="config">
        ///     librdkafka configuration parameters (refer to https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md)
        ///     TODO: Link to confluent-kafka-dotnet page with dotnet specific parameters also (i.e. default.topic.config).
        /// </param>
        /// <param name="manualPoll">
        ///     If true, does not start a dedicated polling thread to trigger events or receive delivery reports -
        ///     you must call the Poll method periodically instead.
        /// </param>
        /// <param name="disableDeliveryReports">
        ///     If true, disables notification of delivery reports. Note: if set to true and you use a ProduceAsync variant that return
        ///     a Task, the Tasks will never complete. Generally you should leave this parameter as false. Set it to true for "fire and
        ///     forget" semantics and a small boost in performance.
        /// </param>
        public Producer(IEnumerable <KeyValuePair <string, object> > config, bool manualPoll = false, bool disableDeliveryReports = false)
        {
            this.topicConfig            = (IEnumerable <KeyValuePair <string, object> >)config.FirstOrDefault(prop => prop.Key == "default.topic.config").Value;
            this.manualPoll             = manualPoll;
            this.disableDeliveryReports = disableDeliveryReports;

            var configHandle = SafeConfigHandle.Create();

            config
            .Where(prop => prop.Key != "default.topic.config")
            .ToList()
            .ForEach((kvp) => { configHandle.Set(kvp.Key, kvp.Value.ToString()); });

            IntPtr configPtr = configHandle.DangerousGetHandle();

            if (!disableDeliveryReports)
            {
                LibRdKafka.conf_set_dr_msg_cb(configPtr, DeliveryReportCallback);
            }

            // TODO: provide some mechanism whereby calls to the error and log callbacks are cached until
            //       such time as event handlers have had a chance to be registered.
            LibRdKafka.conf_set_error_cb(configPtr, ErrorCallback);
            LibRdKafka.conf_set_log_cb(configPtr, LogCallback);
            LibRdKafka.conf_set_stats_cb(configPtr, StatsCallback);

            this.kafkaHandle = SafeKafkaHandle.Create(RdKafkaType.Producer, configPtr);

            if (!manualPoll)
            {
                callbackCts  = new CancellationTokenSource();
                callbackTask = StartPollTask(callbackCts.Token);
            }
        }
コード例 #7
0
 /// <summary>
 /// Wait for all rdkafka objects to be destroyed.
 ///
 /// Returns if all kafka objects are now destroyed,
 /// or throws TimeoutException if the timeout was reached.
 ///
 /// Since RdKafka handle deletion is an async operation the
 /// WaitDestroyed() function can be used for applications where
 /// a clean shutdown is required.
 /// </summary>
 /// <exception cref="System.TimeoutException">Timeout was reached before all objects were destroyed.</exception>
 public static void WaitDestroyed(TimeSpan timeout)
 {
     if ((long)LibRdKafka.wait_destroyed((IntPtr)timeout.TotalMilliseconds) != 0)
     {
         throw new TimeoutException();
     }
 }
コード例 #8
0
        /// <param name="opaque">
        ///     note: this property is set to that defined in rd_kafka_conf
        ///     (which is never used by confluent-kafka-dotnet).
        /// </param>
        private static void DeliveryReportCallbackImpl(IntPtr rk, IntPtr rkmessage, IntPtr opaque)
        {
            var msg = Marshal.PtrToStructure <rd_kafka_message>(rkmessage);

            // the msg._private property has dual purpose. Here, it is an opaque pointer set
            // by Topic.Produce to be an IDeliveryHandler. When Consuming, it's for internal
            // use (hence the name).
            if (msg._private == IntPtr.Zero)
            {
                // Note: this can occur if the ProduceAsync overload that accepts a DeliveryHandler
                // was used and the delivery handler was set to null.
                return;
            }

            var gch             = GCHandle.FromIntPtr(msg._private);
            var deliveryHandler = (IDeliveryHandler)gch.Target;

            gch.Free();

            byte[] key = null;
            byte[] val = null;
            if (deliveryHandler.MarshalData)
            {
                if (msg.key != IntPtr.Zero)
                {
                    key = new byte[(int)msg.key_len];
                    System.Runtime.InteropServices.Marshal.Copy(msg.key, key, 0, (int)msg.key_len);
                }
                if (msg.val != IntPtr.Zero)
                {
                    val = new byte[(int)msg.len];
                    System.Runtime.InteropServices.Marshal.Copy(msg.val, val, 0, (int)msg.len);
                }
            }

            IntPtr timestampType;
            long   timestamp = LibRdKafka.message_timestamp(rkmessage, out timestampType) / 1000;
            var    dateTime  = new DateTime(0);

            if ((TimestampType)timestampType != TimestampType.NotAvailable)
            {
                dateTime = Timestamp.UnixTimestampMsToDateTime(timestamp);
            }

            deliveryHandler.HandleDeliveryReport(
                new Message(
                    // TODO: tracking handle -> topicName in addition to topicName -> handle could
                    //       avoid this marshalling / memory allocation cost.
                    Util.Marshal.PtrToStringUTF8(LibRdKafka.topic_name(msg.rkt)),
                    msg.partition,
                    msg.offset,
                    key,
                    val,
                    new Timestamp(dateTime, (TimestampType)timestampType),
                    msg.err
                    )
                );
        }
コード例 #9
0
ファイル: Topic.cs プロジェクト: zhijia1122/rdkafka-dotnet
        private void Produce(byte[] payload, int payloadCount, byte[] key, int keyCount, Int32 partition, object deliveryHandler, bool blockIfQueueFull)
        {
            var gch = GCHandle.Alloc(deliveryHandler);
            var ptr = GCHandle.ToIntPtr(gch);

            if (handle.Produce(payload, payloadCount, key, keyCount, partition, ptr, blockIfQueueFull) != 0)
            {
                var err = LibRdKafka.last_error();
                gch.Free();
                throw RdKafkaException.FromErr(err, "Could not produce message");
            }
        }
        private static void ProcessInMemoryCertificatesIfConfigured(
            SafeConfigHandle configHandle,
            IntPtr configPtr,
            ManualConfigSettings ManualConfigSettings)
        {
            if (ManualConfigSettings.X509Certificate == null)
            {
                return;
            }

            X509Certificate2 caCertificate = ManualConfigSettings.CAX509Certificate;

            if (caCertificate == null)
            {
                caCertificate = AttemptToResolveCACertificateFromUserCertificate(ManualConfigSettings.X509Certificate);
            }

            if (caCertificate == null)
            {
                throw new InvalidOperationException("An accompanying in-memory CA certificate must be provided");
            }

            PrivateKeyAlgorithmAndBytes privateKeyAlgorithmAndBytes = ManualConfigSettings.PrivateKeyAlgorithmAndBytes;

            if (privateKeyAlgorithmAndBytes == null)
            {
                privateKeyAlgorithmAndBytes = AttemptToResolvePrivateKeyFromUserCertificate(ManualConfigSettings.X509Certificate);
            }

            if (privateKeyAlgorithmAndBytes == null)
            {
                throw new InvalidOperationException("A private key must accompany the in-memory certificate");
            }

            LibRdKafka.conf_set_bytes(
                configPtr,
                ManualConfigSettings.SettingNameSslCertificateLocationInMemory,
                ManualConfigSettings.X509Certificate.RawData);

            LibRdKafka.conf_set_bytes(
                configPtr,
                ManualConfigSettings.SettingNameSslCALocationInMemory,
                caCertificate.RawData);

            LibRdKafka.conf_set_bytes(
                configPtr,
                ManualConfigSettings.SettingNameSslKeyInMemory,
                privateKeyAlgorithmAndBytes.RawData);

            configHandle.Set(
                ManualConfigSettings.SettingNameSslKeyInMemoryType,
                privateKeyAlgorithmAndBytes.PrivateKeyAlgorithmInUse);
        }
コード例 #11
0
        private void LogCallback(IntPtr rk, int level, string fac, string buf)
        {
            var name = Util.Marshal.PtrToStringUTF8(LibRdKafka.name(rk));

            if (OnLog == null)
            {
                // Log to stderr by default if no logger is specified.
                Loggers.ConsoleLogger(this, new LogMessage(name, level, fac, buf));
                return;
            }

            OnLog.Invoke(this, new LogMessage(name, level, fac, buf));
        }
コード例 #12
0
        public Producer(Config config, string brokerList = null)
        {
            config = config ?? new Config();

            IntPtr cfgPtr = config.handle.Dup();

            LibRdKafka.conf_set_dr_msg_cb(cfgPtr, DeliveryReportDelegate);
            Init(RdKafkaType.Producer, cfgPtr, config.Logger);

            if (brokerList != null)
            {
                handle.AddBrokers(brokerList);
            }
        }
コード例 #13
0
        internal void Init(RdKafkaType type, IntPtr config, Config.LogCallback logger)
        {
            ErrorDelegate = (IntPtr rk, ErrorCode err, string reason, IntPtr opaque) =>
            {
                OnError?.Invoke(this, new ErrorArgs()
                {
                    ErrorCode = err,
                    Reason    = reason
                });
            };
            LibRdKafka.conf_set_error_cb(config, ErrorDelegate);

            if (logger == null)
            {
                logger = ((string handle, int level, string fac, string buf) =>
                {
                    var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                    Console.WriteLine($"{level}|{now}|{handle}|{fac}| {buf}");
                });
            }

            LogDelegate = (IntPtr rk, int level, string fac, string buf) =>
            {
                // The log_cb is called very early during construction, before
                // SafeKafkaHandle or any of the C# wrappers are ready.
                // So we can't really pass rk on, just pass the rk name instead.
                var name = Marshal.PtrToStringAnsi(LibRdKafka.name(rk));
                logger(name, level, fac, buf);
            };
            LibRdKafka.conf_set_log_cb(config, LogDelegate);

            StatsDelegate = (IntPtr rk, IntPtr json, UIntPtr json_len, IntPtr opaque) =>
            {
                OnStatistics?.Invoke(this, Marshal.PtrToStringAnsi(json));
                return(0);
            };
            LibRdKafka.conf_set_stats_cb(config, StatsDelegate);

            handle = SafeKafkaHandle.Create(type, config);

            callbackCts  = new CancellationTokenSource();
            callbackTask = StartCallbackTask(callbackCts.Token);
        }
コード例 #14
0
        public Consumer(Config config, string brokerList = null)
        {
            RebalanceDelegate = RebalanceCallback;
            CommitDelegate    = CommitCallback;

            IntPtr cfgPtr = config.handle.Dup();

            LibRdKafka.conf_set_rebalance_cb(cfgPtr, RebalanceDelegate);
            LibRdKafka.conf_set_offset_commit_cb(cfgPtr, CommitDelegate);
            if (config.DefaultTopicConfig != null)
            {
                LibRdKafka.conf_set_default_topic_conf(cfgPtr,
                                                       config.DefaultTopicConfig.handle.Dup());
            }
            Init(RdKafkaType.Consumer, cfgPtr, config.Logger);

            if (brokerList != null)
            {
                handle.AddBrokers(brokerList);
            }
        }
コード例 #15
0
 internal static string ErrorToString(ErrorCode errorCode) => Marshal.PtrToStringAnsi(LibRdKafka.err2str(errorCode));
コード例 #16
0
ファイル: Library.cs プロジェクト: yigubigu/docfx
 /// <summary>
 ///     Loads the native librdkafka library from the specified path (note: the
 ///     specified path needs to include the filename). Does nothing if the
 ///     library is already loaded.
 /// </summary>
 /// <returns>
 ///     true if librdkafka was loaded as a result of this call, false if the
 ///     library has already been loaded.
 /// </returns>
 /// <remarks>
 ///     You will not typically need to call this method - librdkafka is loaded
 ///     automatically on first use of a Producer or Consumer instance.
 /// </remarks>
 public static bool Load(string path)
 => LibRdKafka.Initialize(path);
コード例 #17
0
 public static void SetLogLevel(int logLevel)
 {
     LibRdKafka.set_log_level(IntPtr.Zero, (IntPtr)logLevel);
 }