qpid_proton 0.21.0 → 0.22.0

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