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); }
internal void Init(RdKafkaType type, IntPtr config, Config.LogCallback logger) { logger = logger ?? ((string handle, int level, string fac, string buf) => { var now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); 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); }