rabbitmq 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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