qpid_proton 0.21.0 → 0.22.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.
@@ -1,703 +0,0 @@
1
- # Licensed to the Apache Software Foundation (ASF) under one
2
- # or more contributor license agreements. See the NOTICE file
3
- # distributed with this work for additional information
4
- # regarding copyright ownership. The ASF licenses this file
5
- # to you under the Apache License, Version 2.0 (the
6
- # "License"); you may not use this file except in compliance
7
- # with the License. You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing,
12
- # software distributed under the License is distributed on an
13
- # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
- # KIND, either express or implied. See the License for the
15
- # specific language governing permissions and limitations
16
- # under the License.
17
-
18
-
19
- module Qpid::Proton::Messenger
20
- # @deprecated use {Qpid::Proton::Container}
21
- #
22
- # The +Messenger+ class defines a high level interface for
23
- # sending and receiving Messages. Every Messenger contains
24
- # a single logical queue of incoming messages and a single
25
- # logical queue of outgoing messages. These messages in these
26
- # queues may be destined for, or originate from, a variety of
27
- # addresses.
28
- #
29
- # The messenger interface is single-threaded. All methods
30
- # except one ( #interrupt ) are intended to be used from within
31
- # the messenger thread.
32
- #
33
- # === Sending & Receiving Messages
34
- #
35
- # The Messenger class works in conjuction with the Message class. The
36
- # Message class is a mutable holder of message content.
37
- #
38
- # The put method copies its Message to the outgoing queue, and may
39
- # send queued messages if it can do so without blocking. The send
40
- # method blocks until it has sent the requested number of
41
- # or until a timeout interrupts the attempt.
42
- #
43
- # Similarly, the recv method receives messages into the incoming
44
- # queue, and may block as it attempts to receive the requested number
45
- # of messages, or until timeout is reached. It may receive fewer
46
- # than the requested number. The get method pops the
47
- # eldest Message off the incoming queue and copies it into the Message
48
- # object that you supply. It will not block.
49
- #
50
- # The blocking attribute allows you to turn off blocking behavior entirely,
51
- # in which case send and recv will do whatever they can without
52
- # blocking, and then return. You can then look at the number
53
- # of incoming and outgoing messages to see how much outstanding work
54
- # still remains.
55
- #
56
- class Messenger
57
-
58
- include Qpid::Proton::Util::ErrorHandler
59
- include Qpid::Proton::Util::Deprecation
60
-
61
- # Creates a new +Messenger+.
62
- #
63
- # The +name+ parameter is optional. If one is not provided then
64
- # a unique name is generated.
65
- #
66
- # ==== Options
67
- #
68
- # * name - the name (def. nil)
69
- #
70
- def initialize(name = nil)
71
- deprecated Qpid::Proton::Messenger, Qpid::Proton::Container
72
- @impl = Cproton.pn_messenger(name)
73
- @selectables = {}
74
- ObjectSpace.define_finalizer(self, self.class.finalize!(@impl))
75
- end
76
-
77
- def self.finalize!(impl) # :nodoc:
78
- proc {
79
- Cproton.pn_messenger_free(impl)
80
- }
81
- end
82
-
83
- # Returns the name.
84
- #
85
- def name
86
- Cproton.pn_messenger_name(@impl)
87
- end
88
-
89
- # This property contains the password for the Messenger.private_key
90
- # file, or +nil+ if the file is not encrypted.
91
- #
92
- # ==== Arguments
93
- #
94
- # * password - the password
95
- #
96
- def password=(password)
97
- Cproton.pn_messenger_set_password(@impl, password)
98
- end
99
-
100
- # Returns the password property for the Messenger.private_key file.
101
- #
102
- def password
103
- Cproton.pn_messenger_get_password(@impl)
104
- end
105
-
106
- # Sets the timeout period, in milliseconds.
107
- #
108
- # A negative timeout period implies an infinite timeout.
109
- #
110
- # ==== Options
111
- #
112
- # * timeout - the timeout period
113
- #
114
- def timeout=(timeout)
115
- raise TypeError.new("invalid timeout: #{timeout}") if timeout.nil?
116
- Cproton.pn_messenger_set_timeout(@impl, timeout)
117
- end
118
-
119
- # Returns the timeout period
120
- #
121
- def timeout
122
- Cproton.pn_messenger_get_timeout(@impl)
123
- end
124
-
125
- # Returns true if blocking mode is enabled.
126
- #
127
- # Enable or disable blocking behavior during message sending
128
- # and receiving. This affects every blocking call, with the
129
- # exception of work(). Currently, the affected calls are
130
- # send, recv, and stop.
131
- def blocking?
132
- Cproton.pn_messenger_is_blocking(@impl)
133
- end
134
-
135
- # Sets the blocking mode.
136
- def blocking=(blocking)
137
- Cproton.pn_messenger_set_blocking(@impl, blocking)
138
- end
139
-
140
- # Returns true if passive mode is enabled.
141
- #
142
- def passive?
143
- Cproton.pn_messenger_is_passive(@impl)
144
- end
145
-
146
- # Turns passive mode on or off.
147
- #
148
- # When set to passive mode, Messenger will not attempt to perform I/O
149
- # operations internally. In this mode it is necesssary to use the
150
- # Selectable type to drive any I/O needed to perform requestioned
151
- # actions.
152
- #
153
- # In this mode Messenger will never block.
154
- #
155
- def passive=(mode)
156
- Cproton.pn_messenger_set_passive(@impl, mode)
157
- end
158
-
159
- def deadline
160
- tstamp = Cproton.pn_messenger_deadline(@impl)
161
- return tstamp / 1000.0 unless tstamp.nil?
162
- end
163
-
164
- # Reports whether an error occurred.
165
- #
166
- def error?
167
- !Cproton.pn_messenger_errno(@impl).zero?
168
- end
169
-
170
- # Returns the most recent error number.
171
- #
172
- def errno
173
- Cproton.pn_messenger_errno(@impl)
174
- end
175
-
176
- # Returns the most recent error message.
177
- #
178
- def error
179
- Cproton.pn_error_text(Cproton.pn_messenger_error(@impl))
180
- end
181
-
182
- # Clears the current error state.
183
- #
184
- def clear_error
185
- error = Cproton.pn_messenger_error(@impl)
186
- unless error.nil?
187
- Cproton.pn_error_clear(error)
188
- end
189
- end
190
-
191
- # For future compatibility, do not send or recv messages
192
- # before starting the +Messenger+.
193
- #
194
- def start
195
- at_exit { stop }
196
- Cproton.pn_messenger_start(@impl)
197
- end
198
-
199
- # Stops the +Messenger+, preventing it from sending or receiving
200
- # any more messages.
201
- #
202
- def stop
203
- Cproton.pn_messenger_stop(@impl)
204
- end
205
-
206
- # Returns true if a Messenger is in the stopped state.
207
- # This function does not block.
208
- #
209
- def stopped?
210
- Cproton.pn_messenger_stopped(@impl)
211
- end
212
-
213
- # Subscribes the Messenger to messages originating from the
214
- # specified source. The source is an address as specified in the
215
- # Messenger introduction with the following addition. If the
216
- # domain portion of the address begins with the '~' character, the
217
- # Messenger will interpret the domain as host/port, bind to it,
218
- # and listen for incoming messages. For example "~0.0.0.0",
219
- # "amqp://~0.0.0.0" will all bind to any local interface and
220
- # listen for incoming messages. An address of "amqps://~0.0.0.0"
221
- # will only permit incoming SSL connections.
222
- #
223
- # ==== Options
224
- #
225
- # * address - the source address to be subscribe
226
- # * timeout - an optional time-to-live value, in seconds, for the
227
- # subscription
228
- #
229
- def subscribe(address, timeout=0)
230
- raise TypeError.new("invalid address: #{address}") if address.nil?
231
- subscription = Cproton.pn_messenger_subscribe_ttl(@impl, address, timeout)
232
- raise Qpid::Proton::ProtonError.new("Subscribe failed") if subscription.nil?
233
- Subscription.new(subscription)
234
- end
235
-
236
- # Path to a certificate file for the +Messenger+.
237
- #
238
- # This certificate is used when the +Messenger+ accepts or establishes
239
- # SSL/TLS connections. This property must be specified for the
240
- # Messenger to accept incoming SSL/TLS connections and to establish
241
- # client authenticated outgoing SSL/TLS connection. Non client authenticated
242
- # outgoing SSL/TLS connections do not require this property.
243
- #
244
- # ==== Options
245
- #
246
- # * certificate - the certificate
247
- #
248
- def certificate=(certificate)
249
- Cproton.pn_messenger_set_certificate(@impl, certificate)
250
- end
251
-
252
- # Returns the path to a certificate file.
253
- #
254
- def certificate
255
- Cproton.pn_messenger_get_certificate(@impl)
256
- end
257
-
258
- # Path to a private key file for the +Messenger+.
259
- #
260
- # The property must be specified for the +Messenger+ to accept incoming
261
- # SSL/TLS connections and to establish client authenticated outgoing
262
- # SSL/TLS connections. Non client authenticated SSL/TLS connections
263
- # do not require this property.
264
- #
265
- # ==== Options
266
- #
267
- # * key - the key file
268
- #
269
- def private_key=(key)
270
- Cproton.pn_messenger_set_private_key(@impl, key)
271
- end
272
-
273
- # Returns the path to a private key file.
274
- #
275
- def private_key
276
- Cproton.pn_messenger_get_private_key(@impl)
277
- end
278
-
279
- # A path to a database of trusted certificates for use in verifying the
280
- # peer on an SSL/TLS connection. If this property is +nil+, then the
281
- # peer will not be verified.
282
- #
283
- # ==== Options
284
- #
285
- # * certificates - the certificates path
286
- #
287
- def trusted_certificates=(certificates)
288
- Cproton.pn_messenger_set_trusted_certificates(@impl,certificates)
289
- end
290
-
291
- # The path to the databse of trusted certificates.
292
- #
293
- def trusted_certificates
294
- Cproton.pn_messenger_get_trusted_certificates(@impl)
295
- end
296
-
297
- # Places the content contained in the message onto the outgoing
298
- # queue of the Messenger.
299
- #
300
- # This method will never block, however it will send any unblocked
301
- # Messages in the outgoing queue immediately and leave any blocked
302
- # Messages remaining in the outgoing queue.
303
- # The send call may then be used to block until the outgoing queue
304
- # is empty. The outgoing attribute may be used to check the depth
305
- # of the outgoing queue.
306
- #
307
- # ==== Options
308
- #
309
- # * message - the message
310
- #
311
- def put(message)
312
- if message.nil?
313
- raise TypeError.new("invalid message: #{message}")
314
- end
315
- unless message.kind_of?(Qpid::Proton::Message)
316
- raise ::ArgumentError.new("invalid message type: #{message.class}")
317
- end
318
- # encode the message first
319
- message.pre_encode
320
- perform_put(message)
321
- return outgoing_tracker
322
- end
323
-
324
- private
325
-
326
- def perform_put(message) # :nodoc:
327
- Cproton.pn_messenger_put(@impl, message.impl)
328
- end
329
-
330
- public
331
-
332
-
333
- # This call will block until the indicated number of messages
334
- # have been sent, or until the operation times out.
335
- # If n is -1 this call will block until all outgoing messages
336
- # have been sent. If n is 0 then this call will send whatever
337
- # it can without blocking.
338
- #
339
- def send(n = -1)
340
- Cproton.pn_messenger_send(@impl, n)
341
- end
342
-
343
- # Moves the message from the head of the incoming message queue into
344
- # the supplied message object. Any content in the supplied message
345
- # will be overwritten.
346
- # A tracker for the incoming Message is returned. The tracker can
347
- # later be used to communicate your acceptance or rejection of the
348
- # Message.
349
- #
350
- # If no message is provided in the argument, then one is created. In
351
- # either case, the one returned will be the fetched message.
352
- #
353
- # ==== Options
354
- #
355
- # * msg - the (optional) +Message+ instance to be used
356
- #
357
- def get(msg = nil)
358
- msg_impl = nil
359
- if msg.nil? then
360
- msg_impl = nil
361
- else
362
- msg_impl = msg.impl
363
- end
364
- perform_get(msg_impl)
365
- msg.post_decode unless msg.nil?
366
- return incoming_tracker
367
- end
368
-
369
- private
370
-
371
- def perform_get(msg) # :nodoc:
372
- Cproton.pn_messenger_get(@impl, msg)
373
- end
374
-
375
- public
376
-
377
- # Receives up to limit messages into the incoming queue. If no value
378
- # for limit is supplied, this call will receive as many messages as it
379
- # can buffer internally. If the Messenger is in blocking mode, this
380
- # call will block until at least one Message is available in the
381
- # incoming queue.
382
- #
383
- # Options ====
384
- #
385
- # * limit - the maximum number of messages to receive
386
- #
387
- def receive(limit = -1)
388
- Cproton.pn_messenger_recv(@impl, limit)
389
- end
390
-
391
- # Returns true if the messenger is currently receiving data.
392
- def receiving?
393
- Cproton.pn_messenger_receiving(@impl)
394
- end
395
-
396
- # Attempts interrupting of the messenger thread.
397
- #
398
- # The Messenger interface is single-threaded, and this is the only
399
- # function intended to be called from outside of is thread.
400
- #
401
- # Call this from a non-Messenger thread to interrupt it while it
402
- # is blocking. This will cause a ::InterruptError to be raised.
403
- #
404
- # If there is no currently blocking call, then the next blocking
405
- # call will be affected, even if it is within the same thread that
406
- # originated the interrupt.
407
- #
408
- def interrupt
409
- Cproton.pn_messenger_interrupt(@impl)
410
- end
411
-
412
- # Sends or receives any outstanding messages queued for a Messenger.
413
- #
414
- # This will block for the indicated timeout. This method may also do I/O
415
- # other than sending and receiving messages. For example, closing
416
- # connections after stop() has been called.
417
- #
418
- def work(timeout=-1)
419
- err = Cproton.pn_messenger_work(@impl, timeout)
420
- if (err == Cproton::PN_TIMEOUT) then
421
- return false
422
- else
423
- check_for_error(err)
424
- return true
425
- end
426
- end
427
-
428
- # Returns the number messages in the outgoing queue that have not been
429
- # transmitted.
430
- #
431
- def outgoing
432
- Cproton.pn_messenger_outgoing(@impl)
433
- end
434
-
435
- # Returns the number of messages in the incoming queue that have not
436
- # been retrieved.
437
- #
438
- def incoming
439
- Cproton.pn_messenger_incoming(@impl)
440
- end
441
-
442
- # Adds a routing rule to the Messenger's internal routing table.
443
- #
444
- # The route procedure may be used to influence how a Messenger will
445
- # internally treat a given address or class of addresses. Every call
446
- # to the route procedure will result in Messenger appending a routing
447
- # rule to its internal routing table.
448
- #
449
- # Whenever a Message is presented to a Messenger for delivery, it
450
- # will match the address of this message against the set of routing
451
- # rules in order. The first rule to match will be triggered, and
452
- # instead of routing based on the address presented in the message,
453
- # the Messenger will route based on the address supplied in the rule.
454
- #
455
- # The pattern matching syntax supports two types of matches, a '%'
456
- # will match any character except a '/', and a '*' will match any
457
- # character including a '/'.
458
- #
459
- # A routing address is specified as a normal AMQP address, however it
460
- # may additionally use substitution variables from the pattern match
461
- # that triggered the rule.
462
- #
463
- # ==== Arguments
464
- #
465
- # * pattern - the address pattern
466
- # * address - the target address
467
- #
468
- # ==== Examples
469
- #
470
- # # route messages sent to foo to the destionaty amqp://foo.com
471
- # messenger.route("foo", "amqp://foo.com")
472
- #
473
- # # any message to foobar will be routed to amqp://foo.com/bar
474
- # messenger.route("foobar", "amqp://foo.com/bar")
475
- #
476
- # # any message to bar/<path> will be routed to the same path within
477
- # # the amqp://bar.com domain
478
- # messenger.route("bar/*", "amqp://bar.com/$1")
479
- #
480
- # # route all Message objects over TLS
481
- # messenger.route("amqp:*", "amqps:$1")
482
- #
483
- # # supply credentials for foo
484
- # messenger.route("amqp://foo.com/*", "amqp://user:password@foo.com/$1")
485
- #
486
- # # supply credentials for all domains
487
- # messenger.route("amqp://*", "amqp://user:password@$1")
488
- #
489
- # # route all addresses through a single proxy while preserving the
490
- # # original destination
491
- # messenger.route("amqp://%$/*", "amqp://user:password@proxy/$1/$2")
492
- #
493
- # # route any address through a single broker
494
- # messenger.route("*", "amqp://user:password@broker/$1")
495
- #
496
- def route(pattern, address)
497
- Cproton.pn_messenger_route(@impl, pattern, address)
498
- end
499
-
500
- # Similar to #route, except that the destination of
501
- # the Message is determined before the message address is rewritten.
502
- #
503
- # The outgoing address is only rewritten after routing has been
504
- # finalized. If a message has an outgoing address of
505
- # "amqp://0.0.0.0:5678", and a rewriting rule that changes its
506
- # outgoing address to "foo", it will still arrive at the peer that
507
- # is listening on "amqp://0.0.0.0:5678", but when it arrives there,
508
- # the receiver will see its outgoing address as "foo".
509
- #
510
- # The default rewrite rule removes username and password from addresses
511
- # before they are transmitted.
512
- #
513
- # ==== Arguments
514
- #
515
- # * pattern - the outgoing address
516
- # * address - the target address
517
- #
518
- def rewrite(pattern, address)
519
- Cproton.pn_messenger_rewrite(@impl, pattern, address)
520
- end
521
-
522
- def selectable
523
- impl = Cproton.pn_messenger_selectable(@impl)
524
-
525
- # if we don't have any selectables, then return
526
- return nil if impl.nil?
527
-
528
- fd = Cproton.pn_selectable_get_fd(impl)
529
-
530
- selectable = @selectables[fd]
531
- if selectable.nil?
532
- selectable = Selectable.new(self, impl)
533
- @selectables[fd] = selectable
534
- end
535
- return selectable
536
- end
537
-
538
- # Returns a +Tracker+ for the message most recently sent via the put
539
- # method.
540
- #
541
- def outgoing_tracker
542
- impl = Cproton.pn_messenger_outgoing_tracker(@impl)
543
- return nil if impl == -1
544
- Tracker.new(impl)
545
- end
546
-
547
- # Returns a +Tracker+ for the most recently received message.
548
- #
549
- def incoming_tracker
550
- impl = Cproton.pn_messenger_incoming_tracker(@impl)
551
- return nil if impl == -1
552
- Tracker.new(impl)
553
- end
554
-
555
- # Signal the sender that you have acted on the Message
556
- # pointed to by the tracker. If no tracker is supplied,
557
- # then all messages that have been returned by the get
558
- # method are accepted, except those that have already been
559
- # auto-settled by passing beyond your incoming window size.
560
- #
561
- # ==== Options
562
- #
563
- # * tracker - the tracker
564
- #
565
- def accept(tracker = nil)
566
- raise TypeError.new("invalid tracker: #{tracker}") unless tracker.nil? or valid_tracker?(tracker)
567
- if tracker.nil? then
568
- tracker = self.incoming_tracker
569
- flag = Cproton::PN_CUMULATIVE
570
- else
571
- flag = 0
572
- end
573
- Cproton.pn_messenger_accept(@impl, tracker.impl, flag)
574
- end
575
-
576
- # Rejects the incoming message identified by the tracker.
577
- # If no tracker is supplied, all messages that have been returned
578
- # by the get method are rejected, except those that have already
579
- # been auto-settled by passing beyond your outgoing window size.
580
- #
581
- # ==== Options
582
- #
583
- # * tracker - the tracker
584
- #
585
- def reject(tracker)
586
- raise TypeError.new("invalid tracker: #{tracker}") unless tracker.nil? or valid_tracker?(tracker)
587
- if tracker.nil? then
588
- tracker = self.incoming_tracker
589
- flag = Cproton::PN_CUMULATIVE
590
- else
591
- flag = 0
592
- end
593
- Cproton.pn_messenger_reject(@impl, tracker.impl, flag)
594
- end
595
-
596
- # Gets the last known remote state of the delivery associated with
597
- # the given tracker, as long as the Message is still within your
598
- # outgoing window. (Also works on incoming messages that are still
599
- # within your incoming queue. See TrackerStatus for details on the
600
- # values returned.
601
- #
602
- # ==== Options
603
- #
604
- # * tracker - the tracker
605
- #
606
- def status(tracker)
607
- raise TypeError.new("invalid tracker: #{tracker}") unless valid_tracker?(tracker)
608
- TrackerStatus.by_value(Cproton.pn_messenger_status(@impl, tracker.impl))
609
- end
610
-
611
- # Frees a Messenger from tracking the status associated
612
- # with a given tracker. If you don't supply a tracker, all
613
- # outgoing messages up to the most recent will be settled.
614
- #
615
- # ==== Options
616
- #
617
- # * tracker - the tracker
618
- #
619
- # ==== Examples
620
- #
621
- def settle(tracker)
622
- raise TypeError.new("invalid tracker: #{tracker}") unless valid_tracker?(tracker)
623
- if tracker.nil? then
624
- tracker = self.incoming_tracker
625
- flag = Cproton::PN_CUMULATIVE
626
- else
627
- flag = 0
628
- end
629
- Cproton.pn_messenger_settle(@impl, tracker.impl, flag)
630
- end
631
-
632
- # Sets the incoming window.
633
- #
634
- # The Messenger will track the remote status of this many incoming
635
- # deliveries after they have been accepted or rejected.
636
- #
637
- # Messages enter this window only when you take them into your application
638
- # using get(). If your incoming window size is n, and you get n+1 messages
639
- # without explicitly accepting or rejecting the oldest message, then the
640
- # message that passes beyond the edge of the incoming window will be
641
- # assigned the default disposition of its link.
642
- #
643
- # ==== Options
644
- #
645
- # * window - the window size
646
- #
647
- def incoming_window=(window)
648
- raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
649
- Cproton.pn_messenger_set_incoming_window(@impl, window)
650
- end
651
-
652
- # Returns the incoming window.
653
- #
654
- def incoming_window
655
- Cproton.pn_messenger_get_incoming_window(@impl)
656
- end
657
-
658
- # Sets the outgoing window.
659
- #
660
- # The Messenger will track the remote status of this many outgoing
661
- # deliveries after calling send.
662
- # A Message enters this window when you call the put() method with the
663
- # message. If your outgoing window size is n, and you call put n+1
664
- # times, status information will no longer be available for the
665
- # first message.
666
- #
667
- # ==== Options
668
- #
669
- # * window - the window size
670
- #
671
- def outgoing_window=(window)
672
- raise TypeError.new("invalid window: #{window}") unless valid_window?(window)
673
- Cproton.pn_messenger_set_outgoing_window(@impl, window)
674
- end
675
-
676
- # Returns the outgoing window.
677
- #
678
- def outgoing_window
679
- Cproton.pn_messenger_get_outgoing_window(@impl)
680
- end
681
-
682
- # Unregisters a selectable object.
683
- def unregister_selectable(fileno) # :nodoc:
684
- @selectables.delete(fileno)
685
- end
686
-
687
- private
688
-
689
- def valid_tracker?(tracker)
690
- !tracker.nil? && tracker.is_a?(Tracker)
691
- end
692
-
693
- def valid_window?(window)
694
- !window.nil? && window.is_a?(Numeric)
695
- end
696
-
697
- can_raise_error [:send, :receive, :password=, :start, :stop,
698
- :perform_put, :perform_get, :interrupt,
699
- :route, :rewrite, :accept, :reject,
700
- :incoming_window=, :outgoing_window=]
701
-
702
- end
703
- end