rabbitmq 0.1.1 → 0.2.0

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.
data/lib/rabbitmq/ffi.rb CHANGED
@@ -6,6 +6,7 @@ module RabbitMQ
6
6
  module FFI
7
7
  extend ::FFI::Library
8
8
 
9
+ ffi_lib ::FFI::Library::LIBC
9
10
  ffi_lib \
10
11
  File.expand_path("../../ext/rabbitmq/librabbitmq.so", File.dirname(__FILE__))
11
12
 
@@ -14,11 +15,45 @@ module RabbitMQ
14
15
  blocking: true # only necessary on MRI to deal with the GIL.
15
16
  }
16
17
 
17
- # The following definition is based on library version 0.5.2
18
+ attach_function :free, [:pointer], :void, **opts
19
+ attach_function :malloc, [:size_t], :pointer, **opts
18
20
 
19
21
  attach_function :amqp_version_number, [], :uint32, **opts
20
22
  attach_function :amqp_version, [], :string, **opts
21
23
 
24
+ Status = enum ::FFI::TypeDefs[:int], [
25
+ :ok, 0x0,
26
+ :no_memory, -0x0001,
27
+ :bad_amqp_data, -0x0002,
28
+ :unknown_class, -0x0003,
29
+ :unknown_method, -0x0004,
30
+ :hostname_resolution_failed, -0x0005,
31
+ :incompatible_amqp_version, -0x0006,
32
+ :connection_closed, -0x0007,
33
+ :bad_url, -0x0008,
34
+ :socket_error, -0x0009,
35
+ :invalid_parameter, -0x000A,
36
+ :table_too_big, -0x000B,
37
+ :wrong_method, -0x000C,
38
+ :timeout, -0x000D,
39
+ :timer_failure, -0x000E,
40
+ :heartbeat_timeout, -0x000F,
41
+ :unexpected_state, -0x0010,
42
+ :unexpected_socket_closed, -0x0011,
43
+ :unexpected_socket_inuse, -0x0012,
44
+ :tcp_error, -0x0100,
45
+ :tcp_socketlib_init_error, -0x0101,
46
+ :ssl_error, -0x0200,
47
+ :ssl_hostname_verify_failed, -0x0201,
48
+ :ssl_peer_verify_failed, -0x0202,
49
+ :ssl_connection_failed, -0x0203,
50
+ ]
51
+
52
+ DeliveryMode = enum ::FFI::TypeDefs[:uint8], [
53
+ :nonpersistent, 1,
54
+ :persistent, 2,
55
+ ]
56
+
22
57
  class Timeval < ::FFI::Struct
23
58
  layout :tv_sec, :time_t,
24
59
  :tv_usec, :suseconds_t
@@ -98,8 +133,10 @@ module RabbitMQ
98
133
  :confirm_select_ok, 0x0055000B, # 85, 11; 5570571
99
134
  ]
100
135
 
101
- Flags = :uint32
102
- Channel = :uint16
136
+ Flags = :uint32
137
+
138
+ Channel = ::FFI::TypeDefs[:uint16]
139
+ CHANNEL_MAX_ID = 2 ** (Channel.size * 8) - 1
103
140
 
104
141
  class Bytes < ::FFI::Struct
105
142
  layout :len, :size_t,
@@ -189,6 +226,13 @@ module RabbitMQ
189
226
  :decoded, :pointer
190
227
  end
191
228
 
229
+ FrameType = enum ::FFI::TypeDefs[:uint8], [
230
+ :method, 1,
231
+ :header, 2,
232
+ :body, 3,
233
+ :heartbeat, 8,
234
+ ]
235
+
192
236
  class FramePayloadProperties < ::FFI::Struct
193
237
  layout :class_id, :uint16,
194
238
  :body_size, :uint64,
@@ -210,8 +254,8 @@ module RabbitMQ
210
254
  :protocol_header, FramePayloadProtocolHeader
211
255
  end
212
256
 
213
- class Frame < ::FFI::Union
214
- layout :frame_type, :uint8,
257
+ class Frame < ::FFI::Struct
258
+ layout :frame_type, FrameType,
215
259
  :channel, Channel,
216
260
  :payload, FramePayload
217
261
  end
@@ -226,7 +270,7 @@ module RabbitMQ
226
270
  class RpcReply < ::FFI::Struct
227
271
  layout :reply_type, ResponseType,
228
272
  :reply, Method,
229
- :library_error, :int
273
+ :library_error, Status
230
274
  end
231
275
 
232
276
  SaslMethod = enum [
@@ -235,48 +279,15 @@ module RabbitMQ
235
279
 
236
280
  ConnectionState = :pointer
237
281
 
238
- Status = enum [
239
- :ok, 0x0,
240
- :no_memory, -0x0001,
241
- :bad_amqp_data, -0x0002,
242
- :unknown_class, -0x0003,
243
- :unknown_method, -0x0004,
244
- :hostname_resolution_failed, -0x0005,
245
- :incompatible_amqp_version, -0x0006,
246
- :connection_closed, -0x0007,
247
- :bad_url, -0x0008,
248
- :socket_error, -0x0009,
249
- :invalid_parameter, -0x000A,
250
- :table_too_big, -0x000B,
251
- :wrong_method, -0x000C,
252
- :timeout, -0x000D,
253
- :timer_failure, -0x000E,
254
- :heartbeat_timeout, -0x000F,
255
- :unexpected_state, -0x0010,
256
- :unexpected_socket_closed, -0x0011,
257
- :unexpected_socket_inuse, -0x0012,
258
- :tcp_error, -0x0100,
259
- :tcp_socketlib_init_error, -0x0101,
260
- :ssl_error, -0x0200,
261
- :ssl_hostname_verify_failed, -0x0201,
262
- :ssl_peer_verify_failed, -0x0202,
263
- :ssl_connection_failed, -0x0203,
264
- ]
265
-
266
- DeliveryMode = enum [
267
- :nonpersistent, 1,
268
- :persistent, 2,
269
- ]
270
-
271
282
  attach_function :amqp_constant_name, [:int], :string, **opts
272
283
  attach_function :amqp_constant_is_hard_error, [:int], Boolean, **opts
273
284
 
274
- attach_function :amqp_method_name, [MethodNumber], :string, **opts
275
- attach_function :amqp_method_has_content, [MethodNumber], Boolean, **opts
276
- attach_function :amqp_decode_method, [MethodNumber, Pool.ptr, Bytes, :pointer], Status, **opts
277
- attach_function :amqp_decode_properties, [:uint16, Pool.ptr, Bytes, :pointer], Status, **opts
278
- attach_function :amqp_encode_method, [MethodNumber, :pointer, Bytes], Status, **opts
279
- attach_function :amqp_encode_properties, [:uint16, :pointer, Bytes], Status, **opts
285
+ attach_function :amqp_method_name, [MethodNumber], :string, **opts
286
+ attach_function :amqp_method_has_content, [MethodNumber], Boolean, **opts
287
+ attach_function :amqp_decode_method, [MethodNumber, Pool.ptr, Bytes.val, :pointer], Status, **opts
288
+ attach_function :amqp_decode_properties, [:uint16, Pool.ptr, Bytes.val, :pointer], Status, **opts
289
+ attach_function :amqp_encode_method, [MethodNumber, :pointer, Bytes.val], Status, **opts
290
+ attach_function :amqp_encode_properties, [:uint16, :pointer, Bytes.val], Status, **opts
280
291
 
281
292
  class ConnectionStart < ::FFI::Struct
282
293
  layout :version_major, :uint8,
@@ -362,7 +373,7 @@ module RabbitMQ
362
373
  layout :reply_code, :uint16,
363
374
  :reply_text, Bytes,
364
375
  :class_id, :uint16,
365
- :method_i, :uint16
376
+ :method_id, :uint16
366
377
  end
367
378
 
368
379
  class ChannelCloseOk < ::FFI::Struct
@@ -391,7 +402,7 @@ module RabbitMQ
391
402
  :auto_delete, Boolean,
392
403
  :internal, Boolean,
393
404
  :nowait, Boolean,
394
- :arguments, Bytes
405
+ :arguments, Table
395
406
  end
396
407
 
397
408
  class ExchangeDeclareOk < ::FFI::Struct
@@ -415,7 +426,7 @@ module RabbitMQ
415
426
  :source, Bytes,
416
427
  :routing_key, Bytes,
417
428
  :nowait, Boolean,
418
- :arguments, Bytes
429
+ :arguments, Table
419
430
  end
420
431
 
421
432
  class ExchangeBindOk < ::FFI::Struct
@@ -428,7 +439,7 @@ module RabbitMQ
428
439
  :source, Bytes,
429
440
  :routing_key, Bytes,
430
441
  :nowait, Boolean,
431
- :arguments, Bytes
442
+ :arguments, Table
432
443
  end
433
444
 
434
445
  class ExchangeUnbindOk < ::FFI::Struct
@@ -443,7 +454,7 @@ module RabbitMQ
443
454
  :exclusive, Boolean,
444
455
  :auto_delete, Boolean,
445
456
  :nowait, Boolean,
446
- :arguments, Bytes
457
+ :arguments, Table
447
458
  end
448
459
 
449
460
  class QueueDeclareOk < ::FFI::Struct
@@ -458,7 +469,7 @@ module RabbitMQ
458
469
  :exchange, Bytes,
459
470
  :routing_key, Bytes,
460
471
  :nowait, Boolean,
461
- :arguments, Bytes
472
+ :arguments, Table
462
473
  end
463
474
 
464
475
  class QueueBindOk < ::FFI::Struct
@@ -492,7 +503,7 @@ module RabbitMQ
492
503
  :queue, Bytes,
493
504
  :exchange, Bytes,
494
505
  :routing_key, Bytes,
495
- :arguments, Bytes
506
+ :arguments, Table
496
507
  end
497
508
 
498
509
  class QueueUnbindOk < ::FFI::Struct
@@ -517,7 +528,7 @@ module RabbitMQ
517
528
  :no_ack, Boolean,
518
529
  :exclusive, Boolean,
519
530
  :nowait, Boolean,
520
- :arguments, Bytes
531
+ :arguments, Table
521
532
  end
522
533
 
523
534
  class BasicConsumeOk < ::FFI::Struct
@@ -674,7 +685,7 @@ module RabbitMQ
674
685
  :content_type, Bytes,
675
686
  :content_encoding, Bytes,
676
687
  :headers, Table,
677
- :delivery_mode, :uint8,
688
+ :delivery_mode, DeliveryMode,
678
689
  :priority, :uint8,
679
690
  :correlation_id, Bytes,
680
691
  :reply_to, Bytes,
@@ -687,25 +698,25 @@ module RabbitMQ
687
698
  :cluster_id, Bytes
688
699
  end
689
700
 
690
- attach_function :amqp_channel_open, [ConnectionState, Channel], ChannelOpenOk.ptr, **opts
691
- attach_function :amqp_channel_flow, [ConnectionState, Channel, Boolean], ChannelFlowOk.ptr, **opts
692
- attach_function :amqp_exchange_declare, [ConnectionState, Channel, Bytes, Bytes, Boolean, Boolean, Table], ExchangeDeclareOk.ptr, **opts
693
- attach_function :amqp_exchange_delete, [ConnectionState, Channel, Bytes, Boolean], ExchangeDeleteOk.ptr, **opts
694
- attach_function :amqp_exchange_bind, [ConnectionState, Channel, Bytes, Bytes, Bytes, Table], ExchangeBindOk.ptr, **opts
695
- attach_function :amqp_exchange_unbind, [ConnectionState, Channel, Bytes, Bytes, Bytes, Table], ExchangeUnbindOk.ptr, **opts
696
- attach_function :amqp_queue_declare, [ConnectionState, Channel, Bytes, Boolean, Boolean, Boolean, Boolean, Table], QueueDeclareOk.ptr, **opts
697
- attach_function :amqp_queue_bind, [ConnectionState, Channel, Bytes, Bytes, Bytes, Table], QueueBindOk.ptr, **opts
698
- attach_function :amqp_queue_purge, [ConnectionState, Channel, Bytes], QueuePurgeOk.ptr, **opts
699
- attach_function :amqp_queue_delete, [ConnectionState, Channel, Bytes, Boolean, Boolean], QueueDeleteOk.ptr, **opts
700
- attach_function :amqp_queue_unbind, [ConnectionState, Channel, Bytes, Bytes, Bytes, Table], QueueUnbindOk.ptr, **opts
701
- attach_function :amqp_basic_qos, [ConnectionState, Channel, :uint32, :uint16, Boolean], BasicQosOk.ptr, **opts
702
- attach_function :amqp_basic_consume, [ConnectionState, Channel, Bytes, Bytes, Boolean, Boolean, Boolean, Table], BasicConsumeOk.ptr, **opts
703
- attach_function :amqp_basic_cancel, [ConnectionState, Channel, Bytes], BasicCancelOk.ptr, **opts
704
- attach_function :amqp_basic_recover, [ConnectionState, Channel, Boolean], BasicRecoverOk.ptr, **opts
705
- attach_function :amqp_tx_select, [ConnectionState, Channel], TxSelect.ptr, **opts
706
- attach_function :amqp_tx_commit, [ConnectionState, Channel], TxCommit.ptr, **opts
707
- attach_function :amqp_tx_rollback, [ConnectionState, Channel], TxRollback.ptr, **opts
708
- attach_function :amqp_confirm_select, [ConnectionState, Channel], ConfirmSelect.ptr, **opts
701
+ attach_function :amqp_channel_open, [ConnectionState, Channel], ChannelOpenOk.ptr, **opts
702
+ attach_function :amqp_channel_flow, [ConnectionState, Channel, Boolean], ChannelFlowOk.ptr, **opts
703
+ attach_function :amqp_exchange_declare, [ConnectionState, Channel, Bytes.val, Bytes.val, Boolean, Boolean, Table.val], ExchangeDeclareOk.ptr, **opts
704
+ attach_function :amqp_exchange_delete, [ConnectionState, Channel, Bytes.val, Boolean], ExchangeDeleteOk.ptr, **opts
705
+ attach_function :amqp_exchange_bind, [ConnectionState, Channel, Bytes.val, Bytes.val, Bytes.val, Table.val], ExchangeBindOk.ptr, **opts
706
+ attach_function :amqp_exchange_unbind, [ConnectionState, Channel, Bytes.val, Bytes.val, Bytes.val, Table.val], ExchangeUnbindOk.ptr, **opts
707
+ attach_function :amqp_queue_declare, [ConnectionState, Channel, Bytes.val, Boolean, Boolean, Boolean, Boolean, Table.val], QueueDeclareOk.ptr, **opts
708
+ attach_function :amqp_queue_bind, [ConnectionState, Channel, Bytes.val, Bytes.val, Bytes.val, Table.val], QueueBindOk.ptr, **opts
709
+ attach_function :amqp_queue_purge, [ConnectionState, Channel, Bytes.val], QueuePurgeOk.ptr, **opts
710
+ attach_function :amqp_queue_delete, [ConnectionState, Channel, Bytes.val, Boolean, Boolean], QueueDeleteOk.ptr, **opts
711
+ attach_function :amqp_queue_unbind, [ConnectionState, Channel, Bytes.val, Bytes.val, Bytes.val, Table.val], QueueUnbindOk.ptr, **opts
712
+ attach_function :amqp_basic_qos, [ConnectionState, Channel, :uint32, :uint16, Boolean], BasicQosOk.ptr, **opts
713
+ attach_function :amqp_basic_consume, [ConnectionState, Channel, Bytes.val, Bytes.val, Boolean, Boolean, Boolean, Table.val], BasicConsumeOk.ptr, **opts
714
+ attach_function :amqp_basic_cancel, [ConnectionState, Channel, Bytes.val], BasicCancelOk.ptr, **opts
715
+ attach_function :amqp_basic_recover, [ConnectionState, Channel, Boolean], BasicRecoverOk.ptr, **opts
716
+ attach_function :amqp_tx_select, [ConnectionState, Channel], TxSelect.ptr, **opts
717
+ attach_function :amqp_tx_commit, [ConnectionState, Channel], TxCommit.ptr, **opts
718
+ attach_function :amqp_tx_rollback, [ConnectionState, Channel], TxRollback.ptr, **opts
719
+ attach_function :amqp_confirm_select, [ConnectionState, Channel], ConfirmSelect.ptr, **opts
709
720
 
710
721
  attach_function :init_amqp_pool, [Pool.ptr, :size_t], :void, **opts
711
722
  attach_function :recycle_amqp_pool, [Pool.ptr], :void, **opts
@@ -713,10 +724,10 @@ module RabbitMQ
713
724
  attach_function :amqp_pool_alloc, [Pool.ptr, :size_t], :pointer, **opts
714
725
  attach_function :amqp_pool_alloc_bytes, [Pool.ptr, :size_t, Bytes.ptr], :void, **opts
715
726
 
716
- attach_function :amqp_cstring_bytes, [:string], Bytes, **opts
717
- attach_function :amqp_bytes_malloc_dup, [Bytes], Bytes, **opts
718
- attach_function :amqp_bytes_malloc, [:size_t], Bytes, **opts
719
- attach_function :amqp_bytes_free, [Bytes], :void, **opts
727
+ attach_function :amqp_cstring_bytes, [:string], Bytes.val, **opts
728
+ attach_function :amqp_bytes_malloc_dup, [Bytes.val], Bytes.val, **opts
729
+ attach_function :amqp_bytes_malloc, [:size_t], Bytes.val, **opts
730
+ attach_function :amqp_bytes_free, [Bytes.val], :void, **opts
720
731
 
721
732
  attach_function :amqp_new_connection, [], ConnectionState, **opts
722
733
  attach_function :amqp_get_sockfd, [ConnectionState], :int, **opts
@@ -727,12 +738,12 @@ module RabbitMQ
727
738
  attach_function :amqp_get_heartbeat, [ConnectionState], :int, **opts
728
739
  attach_function :amqp_destroy_connection, [ConnectionState], Status, **opts
729
740
 
730
- attach_function :amqp_handle_input, [ConnectionState, Bytes, Frame.ptr], Status, **opts
731
- attach_function :amqp_release_buffers_ok, [ConnectionState], Boolean, **opts
732
- attach_function :amqp_release_buffers, [ConnectionState], :void, **opts
733
- attach_function :amqp_maybe_release_buffers, [ConnectionState], :void, **opts
734
- attach_function :amqp_maybe_release_buffers_on_channel, [ConnectionState, Channel], :void, **opts
735
- attach_function :amqp_send_frame, [ConnectionState, Frame.ptr], Status, **opts
741
+ attach_function :amqp_handle_input, [ConnectionState, Bytes.val, Frame.ptr], Status, **opts
742
+ attach_function :amqp_release_buffers_ok, [ConnectionState], Boolean, **opts
743
+ attach_function :amqp_release_buffers, [ConnectionState], :void, **opts
744
+ attach_function :amqp_maybe_release_buffers, [ConnectionState], :void, **opts
745
+ attach_function :amqp_maybe_release_buffers_on_channel, [ConnectionState, Channel], :void, **opts
746
+ attach_function :amqp_send_frame, [ConnectionState, Frame.ptr], Status, **opts
736
747
 
737
748
  attach_function :amqp_table_entry_cmp, [:pointer, :pointer], :int, **opts
738
749
 
@@ -743,19 +754,19 @@ module RabbitMQ
743
754
  attach_function :amqp_simple_wait_frame, [ConnectionState, Frame.ptr], Status, **opts
744
755
  attach_function :amqp_simple_wait_frame_noblock, [ConnectionState, Frame.ptr, Timeval.ptr], Status, **opts
745
756
  attach_function :amqp_simple_wait_method, [ConnectionState, Channel, MethodNumber, Method.ptr], Status, **opts
746
- attach_function :amqp_send_method, [ConnectionState, Channel, MethodNumber, Method.ptr], Status, **opts
757
+ attach_function :amqp_send_method, [ConnectionState, Channel, MethodNumber, :pointer], Status, **opts
747
758
 
748
- attach_function :amqp_simple_rpc, [ConnectionState, Channel, MethodNumber, :pointer, :pointer], RpcReply.by_value, **opts
749
- attach_function :amqp_simple_rpc_decoded, [ConnectionState, Channel, MethodNumber, MethodNumber, :pointer], :pointer, **opts
750
- attach_function :amqp_get_rpc_reply, [ConnectionState], RpcReply.by_value, **opts
751
- attach_function :amqp_login, [ConnectionState, :string, :int, :int, :int, SaslMethod, :varargs], RpcReply.by_value, **opts
752
- attach_function :amqp_login_with_properties, [ConnectionState, :string, :int, :int, :int, Table.ptr, SaslMethod, :varargs], RpcReply.by_value, **opts
753
- attach_function :amqp_channel_close, [ConnectionState, Channel, :int], RpcReply.by_value, **opts
754
- attach_function :amqp_connection_close, [ConnectionState, :int], RpcReply.by_value, **opts
759
+ attach_function :amqp_simple_rpc, [ConnectionState, Channel, MethodNumber, :pointer, :pointer], RpcReply.val, **opts
760
+ attach_function :amqp_simple_rpc_decoded, [ConnectionState, Channel, MethodNumber, MethodNumber, :pointer], :pointer, **opts
761
+ attach_function :amqp_get_rpc_reply, [ConnectionState], RpcReply.val, **opts
762
+ attach_function :amqp_login, [ConnectionState, :string, :int, :int, :int, SaslMethod, :varargs], RpcReply.val, **opts
763
+ attach_function :amqp_login_with_properties, [ConnectionState, :string, :int, :int, :int, Table.ptr, SaslMethod, :varargs], RpcReply.val, **opts
764
+ attach_function :amqp_channel_close, [ConnectionState, Channel, :int], RpcReply.val, **opts
765
+ attach_function :amqp_connection_close, [ConnectionState, :int], RpcReply.val, **opts
755
766
 
756
- attach_function :amqp_basic_publish, [ConnectionState, Channel, Bytes, Bytes, Boolean, Boolean, BasicProperties.ptr, Bytes], RpcReply.by_value, **opts
767
+ attach_function :amqp_basic_publish, [ConnectionState, Channel, Bytes.val, Bytes.val, Boolean, Boolean, BasicProperties.ptr, Bytes.val], Status, **opts
757
768
 
758
- attach_function :amqp_basic_get, [ConnectionState, Channel, Bytes, Boolean], Status, **opts
769
+ attach_function :amqp_basic_get, [ConnectionState, Channel, Bytes.val, Boolean], Status, **opts
759
770
  attach_function :amqp_basic_ack, [ConnectionState, Channel, :uint64, Boolean], Status, **opts
760
771
  attach_function :amqp_basic_reject, [ConnectionState, Channel, :uint64, Boolean], Status, **opts
761
772
  attach_function :amqp_basic_nack, [ConnectionState, Channel, :uint64, Boolean, Boolean], Status, **opts
@@ -765,8 +776,8 @@ module RabbitMQ
765
776
  attach_function :amqp_error_string, [:int], :string, **opts
766
777
  attach_function :amqp_error_string2, [:int], :string, **opts
767
778
 
768
- attach_function :amqp_decode_table, [Bytes, Pool.ptr, Table.ptr, :pointer], Status, **opts
769
- attach_function :amqp_encode_table, [Bytes, Table.ptr, :pointer], Status, **opts
779
+ attach_function :amqp_decode_table, [Bytes.val, Pool.ptr, Table.ptr, :pointer], Status, **opts
780
+ attach_function :amqp_encode_table, [Bytes.val, Table.ptr, :pointer], Status, **opts
770
781
  attach_function :amqp_table_clone, [Table.ptr, Table.ptr, Pool.ptr], Status, **opts
771
782
 
772
783
  class Message < ::FFI::Struct
@@ -775,8 +786,8 @@ module RabbitMQ
775
786
  :pool, Pool
776
787
  end
777
788
 
778
- attach_function :amqp_read_message, [ConnectionState, Channel, Message.ptr, :int], RpcReply.by_value, **opts
779
- attach_function :amqp_destroy_message, [Message.ptr], :void, **opts
789
+ attach_function :amqp_read_message, [ConnectionState, Channel, Message.ptr, :int], RpcReply.val, **opts
790
+ attach_function :amqp_destroy_message, [Message.ptr], :void, **opts
780
791
 
781
792
  class Envelope < ::FFI::Struct
782
793
  layout :channel, Channel,
@@ -788,8 +799,8 @@ module RabbitMQ
788
799
  :message, Message
789
800
  end
790
801
 
791
- attach_function :amqp_consume_message, [ConnectionState, Envelope.ptr, Timeval.ptr, :int], RpcReply.by_value, **opts
792
- attach_function :amqp_destroy_envelope, [Envelope.ptr], :void, **opts
802
+ attach_function :amqp_consume_message, [ConnectionState, Envelope.ptr, Timeval.ptr, :int], RpcReply.val, **opts
803
+ attach_function :amqp_destroy_envelope, [Envelope.ptr], :void, **opts
793
804
 
794
805
  class ConnectionInfo < ::FFI::Struct
795
806
  layout :user, :string,
@@ -29,12 +29,10 @@ module RabbitMQ
29
29
  end
30
30
 
31
31
  FFI::Status.symbols.each do |status|
32
- message = RabbitMQ::FFI.amqp_error_string2(status)
33
- const_name = status.to_s.gsub(/((?:\A\w)|(?:_\w))/) { |x| x[-1].upcase }
34
-
32
+ message = RabbitMQ::FFI.amqp_error_string2(status)
35
33
  kls = Class.new(Error) { define_method(:status_message) { message } }
36
34
  lookup_table[status] = kls
37
- const_set const_name, kls
35
+ const_set Util.const_name(status), kls
38
36
  end
39
37
  end
40
38
 
@@ -2,6 +2,18 @@
2
2
  module RabbitMQ
3
3
  module FFI
4
4
 
5
+ class Timeval
6
+ def self.from(seconds)
7
+ obj = new
8
+ obj[:tv_sec] = seconds.to_i
9
+ obj[:tv_usec] = (seconds * 1_000_000).to_i
10
+ obj
11
+ end
12
+
13
+ @zero = self.from(0)
14
+ class << self; attr_reader :zero; end
15
+ end
16
+
5
17
  class ConnectionInfo
6
18
  def to_h
7
19
  members.map { |k| [k, self[k]] }.to_h
@@ -9,19 +21,29 @@ module RabbitMQ
9
21
  end
10
22
 
11
23
  class Bytes
12
- def to_s
13
- ::FFI::Pointer.new(self[:bytes]).read_bytes(self[:len])
24
+ def to_s(free=false)
25
+ size = self[:len]
26
+ s = size == 0 ? "" : self[:bytes].read_bytes(size)
27
+ free! if free
28
+ s
14
29
  end
15
30
 
16
- def self.from_s(str)
17
- size = str.bytesize
18
- ptr = Util.mem_ptr(size, release: false)
19
- ptr.write_string(str)
20
-
21
- bytes = new
22
- bytes[:len] = str.bytesize
23
- bytes[:bytes] = Util.mem_ptr(str.bytesize, release: false)
24
- bytes
31
+ def free!
32
+ FFI.free(self[:bytes])
33
+ clear
34
+ end
35
+
36
+ def self.from_s(str, borrow=false)
37
+ if borrow
38
+ FFI.amqp_cstring_bytes(str)
39
+ else
40
+ size = str.bytesize
41
+ bytes = FFI.amqp_bytes_malloc(size)
42
+
43
+ bytes[:bytes].write_string(str)
44
+ bytes[:len] = size
45
+ bytes
46
+ end
25
47
  end
26
48
  end
27
49
 
@@ -34,28 +56,215 @@ module RabbitMQ
34
56
  end
35
57
  end
36
58
 
37
- def to_value
38
- kind = self[:kind]
39
- value = self[:value][value_member(kind)]
40
- case kind
41
- when :bytes; value.to_s
42
- when :utf8; value.to_s.force_encoding(Encoding::UTF_8)
59
+ def to_value(free=false)
60
+ kind = self[:kind]
61
+ value = self[:value][value_member(kind)]
62
+ result = case kind
63
+ when :bytes; value.to_s(free)
64
+ when :utf8; value.to_s(free).force_encoding(Encoding::UTF_8)
43
65
  when :timestamp; Time.at(value / 1000.0)
44
- when :table; value.to_h
66
+ when :table; value.to_h(free)
45
67
  when :array; value.to_array_not_yet_implemented!
46
68
  when :decimal; value.to_value_not_yet_implemented!
47
69
  else value
48
70
  end
71
+
72
+ clear if free
73
+ result
74
+ end
75
+
76
+ def free!
77
+ kind = self[:kind]
78
+ value = self[:value][value_member(kind)]
79
+ value.free! if value.respond_to? :free!
80
+ clear
81
+ end
82
+
83
+ def self.from(value, borrow=false)
84
+ obj = new
85
+ obj[:kind], obj[:value] = case value
86
+ when String; [:bytes, FieldValueValue.new(Bytes.from_s(value, borrow).pointer)]
87
+ else raise NotImplementedError
88
+ end
89
+ obj
49
90
  end
50
91
  end
51
92
 
52
93
  class Table
53
- def to_h
94
+ include Enumerable
95
+
96
+ def each(*a, &b)
54
97
  entry_ptr = self[:entries]
55
- entries = self[:num_entries].times.map { |i|
56
- entry = FFI::TableEntry.new(entry_ptr + i * FFI::TableEntry.size)
57
- [entry[:key].to_s, entry[:value].to_value]
58
- }.to_h
98
+ entries = self[:num_entries].times.map do |i|
99
+ FFI::TableEntry.new(entry_ptr + i * FFI::TableEntry.size)
100
+ end
101
+ entries.each(*a, &b)
102
+ end
103
+
104
+ def to_h(free=false)
105
+ result = self.map do |entry|
106
+ [entry[:key].to_s(free), entry[:value].to_value(free)]
107
+ end.to_h
108
+
109
+ clear if free
110
+ result
111
+ end
112
+
113
+ def free!
114
+ self.each do
115
+ entry[:key].free!
116
+ entry[:value].free!
117
+ end
118
+ FFI.free(self[:entries])
119
+ clear
120
+ end
121
+
122
+ def self.from(params, borrow=false)
123
+ size = params.size
124
+ entry_ptr = Util.mem_ptr(size * FFI::TableEntry.size, release: false)
125
+ params.each_with_index do |param, idx|
126
+ entry = FFI::TableEntry.new(entry_ptr + idx * FFI::TableEntry.size)
127
+ entry[:key] = FFI::Bytes.from_s(param.first.to_s, borrow)
128
+ entry[:value] = FFI::FieldValue.from(param.last, borrow)
129
+ end
130
+
131
+ obj = new
132
+ obj[:num_entries] = size
133
+ obj[:entries] = entry_ptr
134
+ obj
135
+ end
136
+ end
137
+
138
+ class Method
139
+ MethodClasses = FFI::MethodNumber.symbols.map do |name|
140
+ const_name = name.to_s.gsub(/((?:\A\w)|(?:_\w))/) { |x| x[-1].upcase }
141
+ [name, FFI.const_get(const_name)]
142
+ end.to_h.freeze
143
+
144
+ MethodNames = MethodClasses.to_a.map(&:reverse).to_h.freeze
145
+
146
+ def to_h(free=false)
147
+ { method: self[:id],
148
+ properties: self.decoded.to_h(free) }
149
+ end
150
+
151
+ def decoded
152
+ MethodClasses.fetch(self[:id]).new(self[:decoded])
153
+ end
154
+
155
+ def self.lookup(kls)
156
+ MethodNames.fetch(kls)
157
+ end
158
+
159
+ def self.lookup_class(name)
160
+ MethodClasses.fetch(name)
161
+ end
162
+
163
+ def self.from(decoded)
164
+ obj = new
165
+ obj[:id] = lookup(decoded.class)
166
+ obj[:decoded] = decoded.pointer
167
+ obj
168
+ end
169
+
170
+ def self.has_content?(type)
171
+ case type
172
+ when :basic_publish; true
173
+ when :basic_return; true
174
+ when :basic_deliver; true
175
+ when :basic_get_ok; true
176
+ else false
177
+ end
178
+ end
179
+ end
180
+
181
+ module MethodClassMixin
182
+ def apply(borrow=false, **params)
183
+ params.each do |key, value|
184
+ next if key == :dummy
185
+ case value
186
+ when String; value = FFI::Bytes.from_s(value, borrow)
187
+ when Hash; value = FFI::Table.from(value, borrow)
188
+ end
189
+ self[key] = value
190
+ end
191
+ self
192
+ end
193
+
194
+ def to_h(free=false)
195
+ result = {}
196
+ self.members.each do |key| [key, self[key]]
197
+ next if key == :dummy
198
+ value = self[key]
199
+ case value
200
+ when FFI::Bytes; value = value.to_s(free)
201
+ when FFI::Table; value = value.to_h(free)
202
+ end
203
+ result[key] = value
204
+ end
205
+
206
+ # TODO: handle the inverse case of this transformation in apply method
207
+ if (method_id = result.delete(:method_id))
208
+ method_num = (result.delete(:class_id) << 16) + method_id
209
+ result[:method] = FFI::MethodNumber[method_num]
210
+ end
211
+
212
+ clear if free
213
+ result
214
+ end
215
+
216
+ def free!
217
+ self.values.each do |item|
218
+ item.free! if item.respond_to? :free!
219
+ end
220
+ clear
221
+ end
222
+ end
223
+
224
+ Method::MethodClasses.each { |_, kls| kls.send(:include, MethodClassMixin) }
225
+
226
+ BasicProperties.send(:include, MethodClassMixin)
227
+
228
+ class FramePayloadProperties
229
+ def decoded
230
+ BasicProperties.new(self[:decoded])
231
+ end
232
+ end
233
+
234
+ class Frame
235
+ def payload
236
+ member = case self[:frame_type]
237
+ when :method; :method
238
+ when :header; :properties
239
+ when :body; :body_fragment
240
+ else; raise NotImplementedError, "frame type: #{self[:frame_type]}"
241
+ end
242
+ self[:payload][member]
243
+ end
244
+
245
+ def as_method_to_h(free=false)
246
+ # TODO: raise correct error class with enough info for appropriate action
247
+ raise "Wrong frame type for method frame of event: #{self[:frame_type]}" \
248
+ unless self[:frame_type] == :method
249
+
250
+ payload.to_h(free).merge(channel: self[:channel])
251
+ end
252
+
253
+ def as_header_to_h(free=false)
254
+ # TODO: raise correct error class with enough info for appropriate action
255
+ raise "Wrong frame type for header frame of multiframe event: #{self[:frame_type]}" \
256
+ unless self[:frame_type] == :header
257
+
258
+ properties = self[:payload][:properties]
259
+ { header: properties.decoded.to_h(free), body_size: properties[:body_size] }
260
+ end
261
+
262
+ def as_body_to_s(free=false)
263
+ # TODO: raise correct error class with enough info for appropriate action
264
+ raise "Wrong frame type for body frame of multiframe event: #{self[:frame_type]}" \
265
+ unless self[:frame_type] == :body
266
+
267
+ self[:payload][:body_fragment].to_s(free)
59
268
  end
60
269
  end
61
270