rdkafka 0.13.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/workflows/ci.yml +57 -0
  5. data/.gitignore +4 -0
  6. data/.rspec +1 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +155 -111
  10. data/{LICENSE → MIT-LICENSE} +2 -1
  11. data/README.md +60 -39
  12. data/certs/cert_chain.pem +26 -0
  13. data/docker-compose.yml +18 -15
  14. data/ext/README.md +1 -1
  15. data/ext/Rakefile +43 -26
  16. data/lib/rdkafka/abstract_handle.rb +40 -26
  17. data/lib/rdkafka/admin/acl_binding_result.rb +51 -0
  18. data/lib/rdkafka/admin/create_acl_handle.rb +28 -0
  19. data/lib/rdkafka/admin/create_acl_report.rb +24 -0
  20. data/lib/rdkafka/admin/create_partitions_handle.rb +27 -0
  21. data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
  22. data/lib/rdkafka/admin/delete_acl_handle.rb +30 -0
  23. data/lib/rdkafka/admin/delete_acl_report.rb +23 -0
  24. data/lib/rdkafka/admin/delete_groups_handle.rb +28 -0
  25. data/lib/rdkafka/admin/delete_groups_report.rb +24 -0
  26. data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
  27. data/lib/rdkafka/admin/describe_acl_report.rb +23 -0
  28. data/lib/rdkafka/admin.rb +449 -7
  29. data/lib/rdkafka/bindings.rb +133 -7
  30. data/lib/rdkafka/callbacks.rb +196 -1
  31. data/lib/rdkafka/config.rb +53 -19
  32. data/lib/rdkafka/consumer/headers.rb +2 -4
  33. data/lib/rdkafka/consumer/topic_partition_list.rb +11 -8
  34. data/lib/rdkafka/consumer.rb +164 -74
  35. data/lib/rdkafka/helpers/time.rb +14 -0
  36. data/lib/rdkafka/metadata.rb +22 -1
  37. data/lib/rdkafka/native_kafka.rb +6 -1
  38. data/lib/rdkafka/producer/delivery_handle.rb +12 -1
  39. data/lib/rdkafka/producer/delivery_report.rb +16 -3
  40. data/lib/rdkafka/producer.rb +121 -13
  41. data/lib/rdkafka/version.rb +3 -3
  42. data/lib/rdkafka.rb +21 -1
  43. data/rdkafka.gemspec +19 -5
  44. data/renovate.json +6 -0
  45. data/spec/rdkafka/abstract_handle_spec.rb +0 -2
  46. data/spec/rdkafka/admin/create_acl_handle_spec.rb +56 -0
  47. data/spec/rdkafka/admin/create_acl_report_spec.rb +18 -0
  48. data/spec/rdkafka/admin/create_topic_handle_spec.rb +0 -2
  49. data/spec/rdkafka/admin/create_topic_report_spec.rb +0 -2
  50. data/spec/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
  51. data/spec/rdkafka/admin/delete_acl_report_spec.rb +72 -0
  52. data/spec/rdkafka/admin/delete_topic_handle_spec.rb +0 -2
  53. data/spec/rdkafka/admin/delete_topic_report_spec.rb +0 -2
  54. data/spec/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
  55. data/spec/rdkafka/admin/describe_acl_report_spec.rb +73 -0
  56. data/spec/rdkafka/admin_spec.rb +205 -2
  57. data/spec/rdkafka/bindings_spec.rb +0 -1
  58. data/spec/rdkafka/callbacks_spec.rb +0 -2
  59. data/spec/rdkafka/config_spec.rb +8 -2
  60. data/spec/rdkafka/consumer/headers_spec.rb +0 -2
  61. data/spec/rdkafka/consumer/message_spec.rb +0 -2
  62. data/spec/rdkafka/consumer/partition_spec.rb +0 -2
  63. data/spec/rdkafka/consumer/topic_partition_list_spec.rb +19 -2
  64. data/spec/rdkafka/consumer_spec.rb +232 -39
  65. data/spec/rdkafka/error_spec.rb +0 -2
  66. data/spec/rdkafka/metadata_spec.rb +2 -3
  67. data/spec/rdkafka/native_kafka_spec.rb +2 -3
  68. data/spec/rdkafka/producer/delivery_handle_spec.rb +0 -2
  69. data/spec/rdkafka/producer/delivery_report_spec.rb +4 -2
  70. data/spec/rdkafka/producer_spec.rb +183 -3
  71. data/spec/spec_helper.rb +3 -1
  72. data.tar.gz.sig +0 -0
  73. metadata +78 -14
  74. metadata.gz.sig +0 -0
  75. data/.semaphore/semaphore.yml +0 -27
data/lib/rdkafka/admin.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "objspace"
4
-
5
3
  module Rdkafka
6
4
  class Admin
7
5
  # @private
@@ -16,6 +14,19 @@ module Rdkafka
16
14
  ->(_) { close }
17
15
  end
18
16
 
17
+ # Performs the metadata request using admin
18
+ #
19
+ # @param topic_name [String, nil] metadat about particular topic or all if nil
20
+ # @param timeout_ms [Integer] metadata request timeout
21
+ # @return [Metadata] requested metadata
22
+ def metadata(topic_name = nil, timeout_ms = 2_000)
23
+ closed_admin_check(__method__)
24
+
25
+ @native_kafka.with_inner do |inner|
26
+ Metadata.new(inner, topic_name, timeout_ms)
27
+ end
28
+ end
29
+
19
30
  # Close this admin instance
20
31
  def close
21
32
  return if closed?
@@ -30,11 +41,12 @@ module Rdkafka
30
41
 
31
42
  # Create a topic with the given partition count and replication factor
32
43
  #
44
+ # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of
45
+ # creating the topic
46
+ #
33
47
  # @raise [ConfigError] When the partition count or replication factor are out of valid range
34
48
  # @raise [RdkafkaError] When the topic name is invalid or the topic already exists
35
49
  # @raise [RdkafkaError] When the topic configuration is invalid
36
- #
37
- # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
38
50
  def create_topic(topic_name, partition_count, replication_factor, topic_config={})
39
51
  closed_admin_check(__method__)
40
52
 
@@ -107,11 +119,64 @@ module Rdkafka
107
119
  create_topic_handle
108
120
  end
109
121
 
110
- # Delete the named topic
122
+ def delete_group(group_id)
123
+ closed_admin_check(__method__)
124
+
125
+ # Create a rd_kafka_DeleteGroup_t representing the new topic
126
+ delete_groups_ptr = Rdkafka::Bindings.rd_kafka_DeleteGroup_new(
127
+ FFI::MemoryPointer.from_string(group_id)
128
+ )
129
+
130
+ pointer_array = [delete_groups_ptr]
131
+ groups_array_ptr = FFI::MemoryPointer.new(:pointer)
132
+ groups_array_ptr.write_array_of_pointer(pointer_array)
133
+
134
+ # Get a pointer to the queue that our request will be enqueued on
135
+ queue_ptr = @native_kafka.with_inner do |inner|
136
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
137
+ end
138
+ if queue_ptr.null?
139
+ Rdkafka::Bindings.rd_kafka_DeleteTopic_destroy(delete_topic_ptr)
140
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
141
+ end
142
+
143
+ # Create and register the handle we will return to the caller
144
+ delete_groups_handle = DeleteGroupsHandle.new
145
+ delete_groups_handle[:pending] = true
146
+ delete_groups_handle[:response] = -1
147
+ DeleteGroupsHandle.register(delete_groups_handle)
148
+ admin_options_ptr = @native_kafka.with_inner do |inner|
149
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETETOPICS)
150
+ end
151
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_groups_handle.to_ptr)
152
+
153
+ begin
154
+ @native_kafka.with_inner do |inner|
155
+ Rdkafka::Bindings.rd_kafka_DeleteGroups(
156
+ inner,
157
+ groups_array_ptr,
158
+ 1,
159
+ admin_options_ptr,
160
+ queue_ptr
161
+ )
162
+ end
163
+ rescue Exception
164
+ DeleteGroupsHandle.remove(delete_groups_handle.to_ptr.address)
165
+ raise
166
+ ensure
167
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
168
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
169
+ Rdkafka::Bindings.rd_kafka_DeleteGroup_destroy(delete_groups_ptr)
170
+ end
171
+
172
+ delete_groups_handle
173
+ end
174
+
175
+ # Deletes the named topic
111
176
  #
177
+ # @return [DeleteTopicHandle] Delete topic handle that can be used to wait for the result of
178
+ # deleting the topic
112
179
  # @raise [RdkafkaError] When the topic name is invalid or the topic does not exist
113
- #
114
- # @return [DeleteTopicHandle] Delete topic handle that can be used to wait for the result of deleting the topic
115
180
  def delete_topic(topic_name)
116
181
  closed_admin_check(__method__)
117
182
 
@@ -164,7 +229,384 @@ module Rdkafka
164
229
  delete_topic_handle
165
230
  end
166
231
 
232
+ # Creates extra partitions for a given topic
233
+ #
234
+ # @param topic_name [String]
235
+ # @param partition_count [Integer] how many partitions we want to end up with for given topic
236
+ #
237
+ # @raise [ConfigError] When the partition count or replication factor are out of valid range
238
+ # @raise [RdkafkaError] When the topic name is invalid or the topic already exists
239
+ # @raise [RdkafkaError] When the topic configuration is invalid
240
+ #
241
+ # @return [CreateTopicHandle] Create topic handle that can be used to wait for the result of creating the topic
242
+ def create_partitions(topic_name, partition_count)
243
+ closed_admin_check(__method__)
244
+
245
+ @native_kafka.with_inner do |inner|
246
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
247
+ new_partitions_ptr = Rdkafka::Bindings.rd_kafka_NewPartitions_new(
248
+ FFI::MemoryPointer.from_string(topic_name),
249
+ partition_count,
250
+ error_buffer,
251
+ 256
252
+ )
253
+ if new_partitions_ptr.null?
254
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
255
+ end
256
+
257
+ pointer_array = [new_partitions_ptr]
258
+ topics_array_ptr = FFI::MemoryPointer.new(:pointer)
259
+ topics_array_ptr.write_array_of_pointer(pointer_array)
260
+
261
+ # Get a pointer to the queue that our request will be enqueued on
262
+ queue_ptr = Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
263
+ if queue_ptr.null?
264
+ Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
265
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
266
+ end
267
+
268
+ # Create and register the handle we will return to the caller
269
+ create_partitions_handle = CreatePartitionsHandle.new
270
+ create_partitions_handle[:pending] = true
271
+ create_partitions_handle[:response] = -1
272
+ CreatePartitionsHandle.register(create_partitions_handle)
273
+ admin_options_ptr = Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEPARTITIONS)
274
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_partitions_handle.to_ptr)
275
+
276
+ begin
277
+ Rdkafka::Bindings.rd_kafka_CreatePartitions(
278
+ inner,
279
+ topics_array_ptr,
280
+ 1,
281
+ admin_options_ptr,
282
+ queue_ptr
283
+ )
284
+ rescue Exception
285
+ CreatePartitionsHandle.remove(create_partitions_handle.to_ptr.address)
286
+ raise
287
+ ensure
288
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
289
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
290
+ Rdkafka::Bindings.rd_kafka_NewPartitions_destroy(new_partitions_ptr)
291
+ end
292
+
293
+ create_partitions_handle
294
+ end
295
+ end
296
+
297
+ # Create acl
298
+ # @param resource_type - values of type rd_kafka_ResourceType_t
299
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
300
+ # valid values are:
301
+ # RD_KAFKA_RESOURCE_TOPIC = 2
302
+ # RD_KAFKA_RESOURCE_GROUP = 3
303
+ # RD_KAFKA_RESOURCE_BROKER = 4
304
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
305
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
306
+ # valid values are:
307
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
308
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
309
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
310
+ # @param operation - values of type rd_kafka_AclOperation_t
311
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
312
+ # valid values are:
313
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
314
+ # RD_KAFKA_ACL_OPERATION_READ = 3
315
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
316
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
317
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
318
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
319
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
320
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
321
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
322
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
323
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
324
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
325
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
326
+ # valid values are:
327
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
328
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
329
+ #
330
+ # @return [CreateAclHandle] Create acl handle that can be used to wait for the result of creating the acl
331
+ #
332
+ # @raise [RdkafkaError]
333
+ def create_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
334
+ closed_admin_check(__method__)
335
+
336
+ # Create a rd_kafka_AclBinding_t representing the new acl
337
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
338
+ new_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBinding_new(
339
+ resource_type,
340
+ FFI::MemoryPointer.from_string(resource_name),
341
+ resource_pattern_type,
342
+ FFI::MemoryPointer.from_string(principal),
343
+ FFI::MemoryPointer.from_string(host),
344
+ operation,
345
+ permission_type,
346
+ error_buffer,
347
+ 256
348
+ )
349
+ if new_acl_ptr.null?
350
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
351
+ end
352
+
353
+ # Note that rd_kafka_CreateAcls can create more than one acl at a time
354
+ pointer_array = [new_acl_ptr]
355
+ acls_array_ptr = FFI::MemoryPointer.new(:pointer)
356
+ acls_array_ptr.write_array_of_pointer(pointer_array)
357
+
358
+ # Get a pointer to the queue that our request will be enqueued on
359
+ queue_ptr = @native_kafka.with_inner do |inner|
360
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
361
+ end
362
+
363
+ if queue_ptr.null?
364
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
365
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
366
+ end
367
+
368
+ # Create and register the handle that we will return to the caller
369
+ create_acl_handle = CreateAclHandle.new
370
+ create_acl_handle[:pending] = true
371
+ create_acl_handle[:response] = -1
372
+ CreateAclHandle.register(create_acl_handle)
373
+
374
+ admin_options_ptr = @native_kafka.with_inner do |inner|
375
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_CREATEACLS)
376
+ end
377
+
378
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, create_acl_handle.to_ptr)
379
+
380
+ begin
381
+ @native_kafka.with_inner do |inner|
382
+ Rdkafka::Bindings.rd_kafka_CreateAcls(
383
+ inner,
384
+ acls_array_ptr,
385
+ 1,
386
+ admin_options_ptr,
387
+ queue_ptr
388
+ )
389
+ end
390
+ rescue Exception
391
+ CreateAclHandle.remove(create_acl_handle.to_ptr.address)
392
+ raise
393
+ ensure
394
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
395
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
396
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
397
+ end
398
+
399
+ create_acl_handle
400
+ end
401
+
402
+ # Delete acl
403
+ #
404
+ # @param resource_type - values of type rd_kafka_ResourceType_t
405
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
406
+ # valid values are:
407
+ # RD_KAFKA_RESOURCE_TOPIC = 2
408
+ # RD_KAFKA_RESOURCE_GROUP = 3
409
+ # RD_KAFKA_RESOURCE_BROKER = 4
410
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
411
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
412
+ # valid values are:
413
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
414
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
415
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
416
+ # @param operation - values of type rd_kafka_AclOperation_t
417
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
418
+ # valid values are:
419
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
420
+ # RD_KAFKA_ACL_OPERATION_READ = 3
421
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
422
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
423
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
424
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
425
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
426
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
427
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
428
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
429
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
430
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
431
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
432
+ # valid values are:
433
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
434
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
435
+ # @return [DeleteAclHandle] Delete acl handle that can be used to wait for the result of deleting the acl
436
+ #
437
+ # @raise [RdkafkaError]
438
+ def delete_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
439
+ closed_admin_check(__method__)
440
+
441
+ # Create a rd_kafka_AclBinding_t representing the acl to be deleted
442
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
443
+
444
+ delete_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBindingFilter_new(
445
+ resource_type,
446
+ resource_name ? FFI::MemoryPointer.from_string(resource_name) : nil,
447
+ resource_pattern_type,
448
+ principal ? FFI::MemoryPointer.from_string(principal) : nil,
449
+ host ? FFI::MemoryPointer.from_string(host) : nil,
450
+ operation,
451
+ permission_type,
452
+ error_buffer,
453
+ 256
454
+ )
455
+
456
+ if delete_acl_ptr.null?
457
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
458
+ end
459
+
460
+ # Note that rd_kafka_DeleteAcls can delete more than one acl at a time
461
+ pointer_array = [delete_acl_ptr]
462
+ acls_array_ptr = FFI::MemoryPointer.new(:pointer)
463
+ acls_array_ptr.write_array_of_pointer(pointer_array)
464
+
465
+ # Get a pointer to the queue that our request will be enqueued on
466
+ queue_ptr = @native_kafka.with_inner do |inner|
467
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
468
+ end
469
+
470
+ if queue_ptr.null?
471
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
472
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
473
+ end
474
+
475
+ # Create and register the handle that we will return to the caller
476
+ delete_acl_handle = DeleteAclHandle.new
477
+ delete_acl_handle[:pending] = true
478
+ delete_acl_handle[:response] = -1
479
+ DeleteAclHandle.register(delete_acl_handle)
480
+
481
+ admin_options_ptr = @native_kafka.with_inner do |inner|
482
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DELETEACLS)
483
+ end
484
+
485
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, delete_acl_handle.to_ptr)
486
+
487
+ begin
488
+ @native_kafka.with_inner do |inner|
489
+ Rdkafka::Bindings.rd_kafka_DeleteAcls(
490
+ inner,
491
+ acls_array_ptr,
492
+ 1,
493
+ admin_options_ptr,
494
+ queue_ptr
495
+ )
496
+ end
497
+ rescue Exception
498
+ DeleteAclHandle.remove(delete_acl_handle.to_ptr.address)
499
+ raise
500
+ ensure
501
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
502
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
503
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(delete_acl_ptr)
504
+ end
505
+
506
+ delete_acl_handle
507
+ end
508
+
509
+ # Describe acls
510
+ #
511
+ # @param resource_type - values of type rd_kafka_ResourceType_t
512
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
513
+ # valid values are:
514
+ # RD_KAFKA_RESOURCE_TOPIC = 2
515
+ # RD_KAFKA_RESOURCE_GROUP = 3
516
+ # RD_KAFKA_RESOURCE_BROKER = 4
517
+ # @param resource_pattern_type - values of type rd_kafka_ResourcePatternType_t
518
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
519
+ # valid values are:
520
+ # RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
521
+ # RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
522
+ # RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
523
+ # @param operation - values of type rd_kafka_AclOperation_t
524
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
525
+ # valid values are:
526
+ # RD_KAFKA_ACL_OPERATION_ALL = 2
527
+ # RD_KAFKA_ACL_OPERATION_READ = 3
528
+ # RD_KAFKA_ACL_OPERATION_WRITE = 4
529
+ # RD_KAFKA_ACL_OPERATION_CREATE = 5
530
+ # RD_KAFKA_ACL_OPERATION_DELETE = 6
531
+ # RD_KAFKA_ACL_OPERATION_ALTER = 7
532
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
533
+ # RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
534
+ # RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
535
+ # RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
536
+ # RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
537
+ # @param permission_type - values of type rd_kafka_AclPermissionType_t
538
+ # https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
539
+ # valid values are:
540
+ # RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
541
+ # RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
542
+ # @return [DescribeAclHandle] Describe acl handle that can be used to wait for the result of fetching acls
543
+ #
544
+ # @raise [RdkafkaError]
545
+ def describe_acl(resource_type:, resource_name:, resource_pattern_type:, principal:, host:, operation:, permission_type:)
546
+ closed_admin_check(__method__)
547
+
548
+ # Create a rd_kafka_AclBinding_t with the filters to fetch existing acls
549
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
550
+ describe_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBindingFilter_new(
551
+ resource_type,
552
+ resource_name ? FFI::MemoryPointer.from_string(resource_name) : nil,
553
+ resource_pattern_type,
554
+ principal ? FFI::MemoryPointer.from_string(principal) : nil,
555
+ host ? FFI::MemoryPointer.from_string(host) : nil,
556
+ operation,
557
+ permission_type,
558
+ error_buffer,
559
+ 256
560
+ )
561
+ if describe_acl_ptr.null?
562
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
563
+ end
564
+
565
+ # Get a pointer to the queue that our request will be enqueued on
566
+ queue_ptr = @native_kafka.with_inner do |inner|
567
+ Rdkafka::Bindings.rd_kafka_queue_get_background(inner)
568
+ end
569
+
570
+ if queue_ptr.null?
571
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(new_acl_ptr)
572
+ raise Rdkafka::Config::ConfigError.new("rd_kafka_queue_get_background was NULL")
573
+ end
574
+
575
+ # Create and register the handle that we will return to the caller
576
+ describe_acl_handle = DescribeAclHandle.new
577
+ describe_acl_handle[:pending] = true
578
+ describe_acl_handle[:response] = -1
579
+ DescribeAclHandle.register(describe_acl_handle)
580
+
581
+ admin_options_ptr = @native_kafka.with_inner do |inner|
582
+ Rdkafka::Bindings.rd_kafka_AdminOptions_new(inner, Rdkafka::Bindings::RD_KAFKA_ADMIN_OP_DESCRIBEACLS)
583
+ end
584
+
585
+ Rdkafka::Bindings.rd_kafka_AdminOptions_set_opaque(admin_options_ptr, describe_acl_handle.to_ptr)
586
+
587
+ begin
588
+ @native_kafka.with_inner do |inner|
589
+ Rdkafka::Bindings.rd_kafka_DescribeAcls(
590
+ inner,
591
+ describe_acl_ptr,
592
+ admin_options_ptr,
593
+ queue_ptr
594
+ )
595
+ end
596
+ rescue Exception
597
+ DescribeAclHandle.remove(describe_acl_handle.to_ptr.address)
598
+ raise
599
+ ensure
600
+ Rdkafka::Bindings.rd_kafka_AdminOptions_destroy(admin_options_ptr)
601
+ Rdkafka::Bindings.rd_kafka_queue_destroy(queue_ptr)
602
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(describe_acl_ptr)
603
+ end
604
+
605
+ describe_acl_handle
606
+ end
607
+
167
608
  private
609
+
168
610
  def closed_admin_check(method)
169
611
  raise Rdkafka::ClosedAdminError.new(method) if closed?
170
612
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ffi"
4
- require "json"
5
- require "logger"
6
-
7
3
  module Rdkafka
8
4
  # @private
9
5
  module Bindings
@@ -35,12 +31,13 @@ module Rdkafka
35
31
 
36
32
  # Polling
37
33
 
38
- attach_function :rd_kafka_flush, [:pointer, :int], :void, blocking: true
39
- attach_function :rd_kafka_poll, [:pointer, :int], :void, blocking: true
34
+ attach_function :rd_kafka_flush, [:pointer, :int], :int, blocking: true
35
+ attach_function :rd_kafka_poll, [:pointer, :int], :int, blocking: true
40
36
  attach_function :rd_kafka_outq_len, [:pointer], :int, blocking: true
41
37
 
42
38
  # Metadata
43
39
 
40
+ attach_function :rd_kafka_name, [:pointer], :string, blocking: true
44
41
  attach_function :rd_kafka_memberid, [:pointer], :string, blocking: true
45
42
  attach_function :rd_kafka_clusterid, [:pointer], :string, blocking: true
46
43
  attach_function :rd_kafka_metadata, [:pointer, :int, :pointer, :pointer, :int], :int, blocking: true
@@ -157,6 +154,7 @@ module Rdkafka
157
154
  ) do |_client_prr, err_code, reason, _opaque|
158
155
  if Rdkafka::Config.error_callback
159
156
  error = Rdkafka::RdkafkaError.new(err_code, broker_message: reason)
157
+ error.set_backtrace(caller)
160
158
  Rdkafka::Config.error_callback.call(error)
161
159
  end
162
160
  end
@@ -181,15 +179,21 @@ module Rdkafka
181
179
  attach_function :rd_kafka_incremental_assign, [:pointer, :pointer], :int, blocking: true
182
180
  attach_function :rd_kafka_incremental_unassign, [:pointer, :pointer], :int, blocking: true
183
181
  attach_function :rd_kafka_assignment, [:pointer, :pointer], :int, blocking: true
182
+ attach_function :rd_kafka_assignment_lost, [:pointer], :int, blocking: true
184
183
  attach_function :rd_kafka_committed, [:pointer, :pointer, :int], :int, blocking: true
185
184
  attach_function :rd_kafka_commit, [:pointer, :pointer, :bool], :int, blocking: true
186
185
  attach_function :rd_kafka_poll_set_consumer, [:pointer], :void, blocking: true
187
186
  attach_function :rd_kafka_consumer_poll, [:pointer, :int], :pointer, blocking: true
188
187
  attach_function :rd_kafka_consumer_close, [:pointer], :void, blocking: true
189
- attach_function :rd_kafka_offset_store, [:pointer, :int32, :int64], :int, blocking: true
188
+ attach_function :rd_kafka_offsets_store, [:pointer, :pointer], :int, blocking: true
190
189
  attach_function :rd_kafka_pause_partitions, [:pointer, :pointer], :int, blocking: true
191
190
  attach_function :rd_kafka_resume_partitions, [:pointer, :pointer], :int, blocking: true
192
191
  attach_function :rd_kafka_seek, [:pointer, :int32, :int64, :int], :int, blocking: true
192
+ attach_function :rd_kafka_offsets_for_times, [:pointer, :pointer, :int], :int, blocking: true
193
+ attach_function :rd_kafka_position, [:pointer, :pointer], :int, blocking: true
194
+ # those two are used for eos support
195
+ attach_function :rd_kafka_consumer_group_metadata, [:pointer], :pointer, blocking: true
196
+ attach_function :rd_kafka_consumer_group_metadata_destroy, [:pointer], :void, blocking: true
193
197
 
194
198
  # Headers
195
199
  attach_function :rd_kafka_header_get_all, [:pointer, :size_t, :pointer, :pointer, SizePtr], :int
@@ -251,10 +255,13 @@ module Rdkafka
251
255
  RD_KAFKA_VTYPE_TIMESTAMP = 8
252
256
  RD_KAFKA_VTYPE_HEADER = 9
253
257
  RD_KAFKA_VTYPE_HEADERS = 10
258
+ RD_KAFKA_PURGE_F_QUEUE = 1
259
+ RD_KAFKA_PURGE_F_INFLIGHT = 2
254
260
 
255
261
  RD_KAFKA_MSG_F_COPY = 0x2
256
262
 
257
263
  attach_function :rd_kafka_producev, [:pointer, :varargs], :int, blocking: true
264
+ attach_function :rd_kafka_purge, [:pointer, :int], :int, blocking: true
258
265
  callback :delivery_cb, [:pointer, :pointer, :pointer], :void
259
266
  attach_function :rd_kafka_conf_set_dr_msg_cb, [:pointer, :delivery_cb], :void
260
267
 
@@ -299,6 +306,27 @@ module Rdkafka
299
306
  attach_function :rd_kafka_event_DeleteTopics_result, [:pointer], :pointer, blocking: true
300
307
  attach_function :rd_kafka_DeleteTopics_result_topics, [:pointer, :pointer], :pointer, blocking: true
301
308
 
309
+ # Create partitions
310
+ RD_KAFKA_ADMIN_OP_CREATEPARTITIONS = 3
311
+ RD_KAFKA_ADMIN_OP_CREATEPARTITIONS_RESULT = 102
312
+
313
+ attach_function :rd_kafka_CreatePartitions, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
314
+ attach_function :rd_kafka_NewPartitions_new, %i[pointer size_t pointer size_t], :pointer
315
+ attach_function :rd_kafka_NewPartitions_destroy, [:pointer], :void
316
+ attach_function :rd_kafka_event_CreatePartitions_result, [:pointer], :pointer
317
+ attach_function :rd_kafka_CreatePartitions_result_topics, [:pointer, :pointer], :pointer
318
+
319
+ # Delete Group
320
+
321
+ RD_KAFKA_ADMIN_OP_DELETEGROUPS = 7 # rd_kafka_admin_op_t
322
+ RD_KAFKA_EVENT_DELETEGROUPS_RESULT = 106 # rd_kafka_event_type_t
323
+
324
+ attach_function :rd_kafka_DeleteGroups, [:pointer, :pointer, :size_t, :pointer, :pointer], :void, blocking: true
325
+ attach_function :rd_kafka_DeleteGroup_new, [:pointer], :pointer, blocking: true
326
+ attach_function :rd_kafka_DeleteGroup_destroy, [:pointer], :void, blocking: true
327
+ attach_function :rd_kafka_event_DeleteGroups_result, [:pointer], :pointer, blocking: true # rd_kafka_event_t* => rd_kafka_DeleteGroups_result_t*
328
+ attach_function :rd_kafka_DeleteGroups_result_groups, [:pointer, :pointer], :pointer, blocking: true # rd_kafka_DeleteGroups_result_t*, size_t* => rd_kafka_group_result_t**
329
+
302
330
  # Background Queue and Callback
303
331
 
304
332
  attach_function :rd_kafka_queue_get_background, [:pointer], :pointer
@@ -321,5 +349,103 @@ module Rdkafka
321
349
  attach_function :rd_kafka_topic_result_error, [:pointer], :int32
322
350
  attach_function :rd_kafka_topic_result_error_string, [:pointer], :pointer
323
351
  attach_function :rd_kafka_topic_result_name, [:pointer], :pointer
352
+
353
+ # Create Acls
354
+
355
+ RD_KAFKA_ADMIN_OP_CREATEACLS = 9
356
+ RD_KAFKA_EVENT_CREATEACLS_RESULT = 1024
357
+
358
+ attach_function :rd_kafka_CreateAcls, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
359
+ attach_function :rd_kafka_event_CreateAcls_result, [:pointer], :pointer
360
+ attach_function :rd_kafka_CreateAcls_result_acls, [:pointer, :pointer], :pointer
361
+
362
+ # Delete Acls
363
+
364
+ RD_KAFKA_ADMIN_OP_DELETEACLS = 11
365
+ RD_KAFKA_EVENT_DELETEACLS_RESULT = 4096
366
+
367
+ attach_function :rd_kafka_DeleteAcls, [:pointer, :pointer, :size_t, :pointer, :pointer], :void
368
+ attach_function :rd_kafka_event_DeleteAcls_result, [:pointer], :pointer
369
+ attach_function :rd_kafka_DeleteAcls_result_responses, [:pointer, :pointer], :pointer
370
+ attach_function :rd_kafka_DeleteAcls_result_response_error, [:pointer], :pointer
371
+ attach_function :rd_kafka_DeleteAcls_result_response_matching_acls, [:pointer, :pointer], :pointer
372
+
373
+ # Describe Acls
374
+
375
+ RD_KAFKA_ADMIN_OP_DESCRIBEACLS = 10
376
+ RD_KAFKA_EVENT_DESCRIBEACLS_RESULT = 2048
377
+
378
+ attach_function :rd_kafka_DescribeAcls, [:pointer, :pointer, :pointer, :pointer], :void
379
+ attach_function :rd_kafka_event_DescribeAcls_result, [:pointer], :pointer
380
+ attach_function :rd_kafka_DescribeAcls_result_acls, [:pointer, :pointer], :pointer
381
+
382
+ # Acl Bindings
383
+
384
+ attach_function :rd_kafka_AclBinding_restype, [:pointer], :int32
385
+ attach_function :rd_kafka_AclBinding_name, [:pointer], :pointer
386
+ attach_function :rd_kafka_AclBinding_resource_pattern_type, [:pointer], :int32
387
+ attach_function :rd_kafka_AclBinding_principal, [:pointer], :pointer
388
+ attach_function :rd_kafka_AclBinding_host, [:pointer], :pointer
389
+ attach_function :rd_kafka_AclBinding_operation, [:pointer], :int32
390
+ attach_function :rd_kafka_AclBinding_permission_type, [:pointer], :int32
391
+ attach_function :rd_kafka_AclBinding_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t ], :pointer
392
+ attach_function :rd_kafka_AclBindingFilter_new, [:int32, :pointer, :int32, :pointer, :pointer, :int32, :int32, :pointer, :size_t ], :pointer
393
+ attach_function :rd_kafka_AclBinding_destroy, [:pointer], :void
394
+
395
+ # rd_kafka_ResourceType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7307
396
+
397
+ RD_KAFKA_RESOURCE_ANY = 1
398
+ RD_KAFKA_RESOURCE_TOPIC = 2
399
+ RD_KAFKA_RESOURCE_GROUP = 3
400
+ RD_KAFKA_RESOURCE_BROKER = 4
401
+
402
+ # rd_kafka_ResourcePatternType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L7320
403
+
404
+ RD_KAFKA_RESOURCE_PATTERN_ANY = 1
405
+ RD_KAFKA_RESOURCE_PATTERN_MATCH = 2
406
+ RD_KAFKA_RESOURCE_PATTERN_LITERAL = 3
407
+ RD_KAFKA_RESOURCE_PATTERN_PREFIXED = 4
408
+
409
+ # rd_kafka_AclOperation_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8403
410
+
411
+ RD_KAFKA_ACL_OPERATION_ANY = 1
412
+ RD_KAFKA_ACL_OPERATION_ALL = 2
413
+ RD_KAFKA_ACL_OPERATION_READ = 3
414
+ RD_KAFKA_ACL_OPERATION_WRITE = 4
415
+ RD_KAFKA_ACL_OPERATION_CREATE = 5
416
+ RD_KAFKA_ACL_OPERATION_DELETE = 6
417
+ RD_KAFKA_ACL_OPERATION_ALTER = 7
418
+ RD_KAFKA_ACL_OPERATION_DESCRIBE = 8
419
+ RD_KAFKA_ACL_OPERATION_CLUSTER_ACTION = 9
420
+ RD_KAFKA_ACL_OPERATION_DESCRIBE_CONFIGS = 10
421
+ RD_KAFKA_ACL_OPERATION_ALTER_CONFIGS = 11
422
+ RD_KAFKA_ACL_OPERATION_IDEMPOTENT_WRITE = 12
423
+
424
+ # rd_kafka_AclPermissionType_t - https://github.com/confluentinc/librdkafka/blob/292d2a66b9921b783f08147807992e603c7af059/src/rdkafka.h#L8435
425
+
426
+ RD_KAFKA_ACL_PERMISSION_TYPE_ANY = 1
427
+ RD_KAFKA_ACL_PERMISSION_TYPE_DENY = 2
428
+ RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW = 3
429
+
430
+ # Extracting error details from Acl results
431
+ attach_function :rd_kafka_acl_result_error, [:pointer], :pointer
432
+ attach_function :rd_kafka_error_code, [:pointer], :int32
433
+ attach_function :rd_kafka_error_string, [:pointer], :pointer
434
+ attach_function :rd_kafka_event_error, [:pointer], :int32
435
+ attach_function :rd_kafka_event_error_string, [:pointer], :pointer
436
+ attach_function :rd_kafka_AclBinding_error, [:pointer], :pointer
437
+
438
+
439
+ # Extracting data from group results
440
+ class NativeError < FFI::Struct # rd_kafka_error_t
441
+ layout :code, :int32,
442
+ :errstr, :pointer,
443
+ :fatal, :u_int8_t,
444
+ :retriable, :u_int8_t,
445
+ :txn_requires_abort, :u_int8_t
446
+ end
447
+
448
+ attach_function :rd_kafka_group_result_error, [:pointer], NativeError.by_ref # rd_kafka_group_result_t* => rd_kafka_error_t*
449
+ attach_function :rd_kafka_group_result_name, [:pointer], :pointer
324
450
  end
325
451
  end