Module proton
[frames] | no frames]

Source Code for Module proton

   1  # 
   2  # Licensed to the Apache Software Foundation (ASF) under one 
   3  # or more contributor license agreements.  See the NOTICE file 
   4  # distributed with this work for additional information 
   5  # regarding copyright ownership.  The ASF licenses this file 
   6  # to you under the Apache License, Version 2.0 (the 
   7  # "License"); you may not use this file except in compliance 
   8  # with the License.  You may obtain a copy of the License at 
   9  #  
  10  #   http://www.apache.org/licenses/LICENSE-2.0 
  11  #  
  12  # Unless required by applicable law or agreed to in writing, 
  13  # software distributed under the License is distributed on an 
  14  # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
  15  # KIND, either express or implied.  See the License for the 
  16  # specific language governing permissions and limitations 
  17  # under the License. 
  18  # 
  19   
  20  """ 
  21  The proton module defines a suite of APIs that implement the AMQP 1.0 
  22  protocol. 
  23   
  24  The proton APIs consist of the following classes: 
  25   
  26   - L{Messenger} -- A messaging endpoint. 
  27   - L{Message}   -- A class for creating and/or accessing AMQP message content. 
  28   - L{Data}      -- A class for creating and/or accessing arbitrary AMQP encoded 
  29                    data. 
  30   
  31  """ 
  32   
  33  from cproton import * 
  34  import uuid 
  35   
  36  LANGUAGE = "C" 
37 38 -class Constant(object):
39
40 - def __init__(self, name):
41 self.name = name
42
43 - def __repr__(self):
44 return self.name
45
46 -class ProtonException(Exception):
47 """ 48 The root of the proton exception hierarchy. All proton exception 49 classes derive from this exception. 50 """ 51 pass
52
53 -class Timeout(ProtonException):
54 """ 55 A timeout exception indicates that a blocking operation has timed 56 out. 57 """ 58 pass
59
60 -class MessengerException(ProtonException):
61 """ 62 The root of the messenger exception hierarchy. All exceptions 63 generated by the messenger class derive from this exception. 64 """ 65 pass
66
67 -class MessageException(ProtonException):
68 """ 69 The MessageException class is the root of the message exception 70 hierarhcy. All exceptions generated by the Message class derive from 71 this exception. 72 """ 73 pass
74 75 EXCEPTIONS = { 76 PN_TIMEOUT: Timeout 77 } 78 79 PENDING = Constant("PENDING") 80 ACCEPTED = Constant("ACCEPTED") 81 REJECTED = Constant("REJECTED") 82 83 STATUSES = { 84 PN_STATUS_ACCEPTED: ACCEPTED, 85 PN_STATUS_REJECTED: REJECTED, 86 PN_STATUS_PENDING: PENDING, 87 PN_STATUS_UNKNOWN: None 88 } 89 90 AUTOMATIC = Constant("AUTOMATIC") 91 MANUAL = Constant("MANUAL")
92 93 -class Messenger(object):
94 """ 95 The L{Messenger} class defines a high level interface for sending 96 and receiving L{Messages<Message>}. Every L{Messenger} contains a 97 single logical queue of incoming messages and a single logical queue 98 of outgoing messages. These messages in these queues may be destined 99 for, or originate from, a variety of addresses. 100 101 Address Syntax 102 ============== 103 104 An address has the following form:: 105 106 [ amqp[s]:// ] [user[:password]@] domain [/[name]] 107 108 Where domain can be one of:: 109 110 host | host:port | ip | ip:port | name 111 112 The following are valid examples of addresses: 113 114 - example.org 115 - example.org:1234 116 - amqp://example.org 117 - amqps://example.org 118 - example.org/incoming 119 - amqps://example.org/outgoing 120 - amqps://fred:trustno1@example.org 121 - 127.0.0.1:1234 122 - amqps://127.0.0.1:1234 123 124 Sending & Receiving Messages 125 ============================ 126 127 The L{Messenger} class works in conjuction with the L{Message} 128 class. The L{Message} class is a mutable holder of message content. 129 The L{put} method will encode the content in a given L{Message} 130 object into the outgoing message queue leaving that L{Message} 131 object free to be modified or discarded without having any impact on 132 the content in the outgoing queue. 133 134 >>> message = Message() 135 >>> for i in range(3): 136 ... message.address = "amqp://host/queue" 137 ... message.subject = "Hello World %i" % i 138 ... messenger.put(message) 139 >>> messenger.send() 140 141 Similarly, the L{get} method will decode the content in the incoming 142 message queue into the supplied L{Message} object. 143 144 >>> message = Message() 145 >>> messenger.recv(10): 146 >>> while messenger.incoming > 0: 147 ... messenger.get(message) 148 ... print message.subject 149 Hello World 0 150 Hello World 1 151 Hello World 2 152 """ 153
154 - def __init__(self, name=None):
155 """ 156 Construct a new L{Messenger} with the given name. The name has 157 global scope. If a NULL name is supplied, a L{uuid.UUID} based 158 name will be chosen. 159 160 @type name: string 161 @param name: the name of the messenger or None 162 """ 163 self._mng = pn_messenger(name)
164
165 - def __del__(self):
166 if hasattr(self, "_mng"): 167 pn_messenger_free(self._mng) 168 del self._mng
169
170 - def _check(self, err):
171 if err < 0: 172 exc = EXCEPTIONS.get(err, MessengerException) 173 raise exc("[%s]: %s" % (err, pn_messenger_error(self._mng))) 174 else: 175 return err
176 177 @property
178 - def name(self):
179 """ 180 The name of the L{Messenger}. 181 """ 182 return pn_messenger_name(self._mng)
183
184 - def _get_certificate(self):
185 return pn_messenger_get_certificate(self._mng)
186
187 - def _set_certificate(self, value):
188 self._check(pn_messenger_set_certificate(self._mng, value))
189 190 certificate = property(_get_certificate, _set_certificate, 191 doc=""" 192 Path to a certificate file for the L{Messenger}. This certificate is 193 used when the L{Messenger} accepts or establishes SSL/TLS connections. 194 This property must be specified for the L{Messenger} to accept 195 incoming SSL/TLS connections and to establish client authenticated 196 outgoing SSL/TLS connection. Non client authenticated outgoing SSL/TLS 197 connections do not require this property. 198 """) 199
200 - def _get_private_key(self):
201 return pn_messenger_get_private_key(self._mng)
202
203 - def _set_private_key(self, value):
204 self._check(pn_messenger_set_private_key(self._mng, value))
205 206 private_key = property(_get_private_key, _set_private_key, 207 doc=""" 208 Path to a private key file for the L{Messenger's<Messenger>} 209 certificate. This property must be specified for the L{Messenger} to 210 accept incoming SSL/TLS connections and to establish client 211 authenticated outgoing SSL/TLS connection. Non client authenticated 212 SSL/TLS connections do not require this property. 213 """) 214
215 - def _get_password(self):
216 return pn_messenger_get_password(self._mng)
217
218 - def _set_password(self, value):
219 self._check(pn_messenger_set_password(self._mng, value))
220 221 password = property(_get_password, _set_password, 222 doc=""" 223 This property contains the password for the L{Messenger.private_key} 224 file, or None if the file is not encrypted. 225 """) 226
227 - def _get_trusted_certificates(self):
228 return pn_messenger_get_trusted_certificates(self._mng)
229
230 - def _set_trusted_certificates(self, value):
231 self._check(pn_messenger_set_trusted_certificates(self._mng, value))
232 233 trusted_certificates = property(_get_trusted_certificates, 234 _set_trusted_certificates, 235 doc=""" 236 A path do a database of trusted certificates for use in verifying the 237 peer on an SSL/TLS connection. If this property is None, then the peer 238 will not be verified. 239 """) 240
241 - def _get_timeout(self):
242 return pn_messenger_get_timeout(self._mng)
243
244 - def _set_timeout(self, value):
245 self._check(pn_messenger_set_timeout(self._mng, value))
246 247 timeout = property(_get_timeout, _set_timeout, 248 doc=""" 249 The timeout property contains the default timeout for blocking 250 operations performed by the L{Messenger}. 251 """) 252
253 - def _get_incoming_window(self):
254 return pn_messenger_get_incoming_window(self._mng)
255
256 - def _set_incoming_window(self, window):
257 self._check(pn_messenger_set_incoming_window(self._mng, window))
258 259 incoming_window = property(_get_incoming_window, _set_incoming_window, 260 doc=""" 261 The incoming tracking window for the messenger. The messenger will 262 track the remote status of this many incoming deliveries after they 263 have been accepted or rejected. Defaults to zero. 264 """) 265
266 - def _get_outgoing_window(self):
267 return pn_messenger_get_outgoing_window(self._mng)
268
269 - def _set_outgoing_window(self, window):
270 self._check(pn_messenger_set_outgoing_window(self._mng, window))
271 272 outgoing_window = property(_get_outgoing_window, _set_outgoing_window, 273 doc=""" 274 The outgoing tracking window for the messenger. The messenger will 275 track the remote status of this many outgoing deliveries after calling 276 send. Defaults to zero. 277 """) 278
279 - def start(self):
280 """ 281 Transitions the L{Messenger} to an active state. A L{Messenger} is 282 initially created in an inactive state. When inactive a 283 L{Messenger} will not send or receive messages from its internal 284 queues. A L{Messenger} must be started before calling L{send} or 285 L{recv}. 286 """ 287 self._check(pn_messenger_start(self._mng))
288
289 - def stop(self):
290 """ 291 Transitions the L{Messenger} to an inactive state. An inactive 292 L{Messenger} will not send or receive messages from its internal 293 queues. A L{Messenger} should be stopped before being discarded to 294 ensure a clean shutdown handshake occurs on any internally managed 295 connections. 296 """ 297 self._check(pn_messenger_stop(self._mng))
298
299 - def subscribe(self, source):
300 """ 301 Subscribes the L{Messenger} to messages originating from the 302 specified source. The source is an address as specified in the 303 L{Messenger} introduction with the following addition. If the 304 domain portion of the address begins with the '~' character, the 305 L{Messenger} will interpret the domain as host/port, bind to it, 306 and listen for incoming messages. For example "~0.0.0.0", 307 "amqp://~0.0.0.0", and "amqps://~0.0.0.0" will all bind to any 308 local interface and listen for incoming messages with the last 309 variant only permitting incoming SSL connections. 310 311 @type source: string 312 @param source: the source of messages to subscribe to 313 """ 314 sub_impl = pn_messenger_subscribe(self._mng, source) 315 if not sub_impl: 316 self._check(PN_ERR)
317
318 - def put(self, message):
319 """ 320 Places the content contained in the message onto the outgoing 321 queue of the L{Messenger}. This method will never block, however 322 it will send any unblocked L{Messages<Message>} in the outgoing 323 queue immediately and leave any blocked L{Messages<Message>} 324 remaining in the outgoing queue. The L{send} call may be used to 325 block until the outgoing queue is empty. The L{outgoing} property 326 may be used to check the depth of the outgoing queue. 327 328 @type message: Message 329 @param message: the message to place in the outgoing queue 330 @return: a tracker 331 """ 332 message._pre_encode() 333 self._check(pn_messenger_put(self._mng, message._msg)) 334 return pn_messenger_outgoing_tracker(self._mng)
335
336 - def status(self, tracker):
337 """ 338 Gets the last known remote state of the delivery associated with 339 the given tracker. 340 341 @type tracker: tracker 342 @param tracker: the tracker whose status is to be retrieved 343 344 @return: one of None, PENDING, REJECTED, or ACCEPTED 345 """ 346 disp = pn_messenger_status(self._mng, tracker); 347 return STATUSES.get(disp, disp)
348
349 - def settle(self, tracker=None):
350 if tracker is None: 351 tracker = pn_messenger_outgoing_tracker(self._mng) 352 flags = PN_CUMULATIVE 353 else: 354 flags = 0 355 self._check(pn_messenger_settle(self._mng, tracker, flags))
356
357 - def send(self):
358 """ 359 Blocks until the outgoing queue is empty or the operation times 360 out. The L{timeout} property controls how long a L{Messenger} will 361 block before timing out. 362 """ 363 self._check(pn_messenger_send(self._mng))
364
365 - def recv(self, n):
366 """ 367 Receives up to I{n} messages into the incoming queue of the 368 L{Messenger}. This method will block until at least one message is 369 available or the operation times out. 370 """ 371 self._check(pn_messenger_recv(self._mng, n))
372
373 - def get(self, message=None):
374 """ 375 Moves the message from the head of the incoming message queue into 376 the supplied message object. Any content in the message will be 377 overwritten. 378 379 @type message: Message 380 @param message: the destination message object 381 @return: a tracker 382 """ 383 if message is None: 384 impl = None 385 else: 386 impl = message._msg 387 self._check(pn_messenger_get(self._mng, impl)) 388 if message is not None: 389 message._post_decode() 390 return pn_messenger_incoming_tracker(self._mng)
391
392 - def accept(self, tracker=None):
393 """ 394 Accepts messages retreived from the incoming message queue. 395 396 @type tracker: tracker 397 @param tracker: a tracker as returned by get 398 """ 399 if tracker is None: 400 tracker = pn_messenger_incoming_tracker(self._mng) 401 flags = PN_CUMULATIVE 402 else: 403 flags = 0 404 self._check(pn_messenger_accept(self._mng, tracker, flags))
405
406 - def reject(self, tracker=None):
407 """ 408 Rejects messages retreived from the incoming message queue. 409 410 @type tracker: tracker 411 @param tracker: a tracker as returned by get 412 """ 413 if tracker is None: 414 tracker = pn_messenger_incoming_tracker(self._mng) 415 flags = PN_CUMULATIVE 416 else: 417 flags = 0 418 self._check(pn_messenger_reject(self._mng, tracker, flags))
419 420 @property
421 - def outgoing(self):
422 """ 423 The outgoing queue depth. 424 """ 425 return pn_messenger_outgoing(self._mng)
426 427 @property
428 - def incoming(self):
429 """ 430 The incoming queue depth. 431 """ 432 return pn_messenger_incoming(self._mng)
433
434 -class Message(object):
435 """ 436 The L{Message} class is a mutable holder of message content. 437 438 @ivar instructions: delivery instructions for the message 439 @type instructions: dict 440 @ivar annotations: infrastructure defined message annotations 441 @type annotations: dict 442 @ivar properties: application defined message properties 443 @type properties: dict 444 @ivar body: message body 445 @type body: bytes | unicode | dict | list | int | long | float | UUID 446 """ 447 448 DATA = PN_DATA 449 TEXT = PN_TEXT 450 AMQP = PN_AMQP 451 JSON = PN_JSON 452 453 DEFAULT_PRIORITY = PN_DEFAULT_PRIORITY 454
455 - def __init__(self):
456 self._msg = pn_message() 457 self._id = Data(pn_message_id(self._msg)) 458 self._correlation_id = Data(pn_message_correlation_id(self._msg)) 459 self.instructions = None 460 self.annotations = None 461 self.properties = None 462 self.body = None
463
464 - def __del__(self):
465 if hasattr(self, "_msg"): 466 pn_message_free(self._msg) 467 del self._msg
468
469 - def _check(self, err):
470 if err < 0: 471 exc = EXCEPTIONS.get(err, MessageException) 472 raise exc("[%s]: %s" % (err, pn_message_error(self._msg))) 473 else: 474 return err
475
476 - def _pre_encode(self):
477 inst = Data(pn_message_instructions(self._msg)) 478 ann = Data(pn_message_annotations(self._msg)) 479 props = Data(pn_message_properties(self._msg)) 480 body = Data(pn_message_body(self._msg)) 481 482 inst.clear() 483 if self.instructions is not None: 484 inst.put_object(self.instructions) 485 ann.clear() 486 if self.annotations is not None: 487 ann.put_object(self.annotations) 488 props.clear() 489 if self.properties is not None: 490 props.put_object(self.properties) 491 if self.body is not None: 492 # XXX: move this out when load/save are gone 493 body.clear() 494 body.put_object(self.body)
495
496 - def _post_decode(self):
497 inst = Data(pn_message_instructions(self._msg)) 498 ann = Data(pn_message_annotations(self._msg)) 499 props = Data(pn_message_properties(self._msg)) 500 body = Data(pn_message_body(self._msg)) 501 502 if inst.next(): 503 self.instructions = inst.get_object() 504 else: 505 self.instructions = None 506 if ann.next(): 507 self.annotations = ann.get_object() 508 else: 509 self.annotations = None 510 if props.next(): 511 self.properties = props.get_object() 512 else: 513 self.properties = None 514 if body.next(): 515 self.body = body.get_object() 516 else: 517 self.body = None
518
519 - def clear(self):
520 """ 521 Clears the contents of the L{Message}. All fields will be reset to 522 their default values. 523 """ 524 pn_message_clear(self._msg) 525 self.instructions = None 526 self.annotations = None 527 self.properties = None 528 self.body = None
529
530 - def _is_inferred(self):
531 return pn_message_is_inferred(self._msg)
532
533 - def _set_inferred(self, value):
534 self._check(pn_message_set_inferred(self._msg, bool(value)))
535 536 inferred = property(_is_inferred, _set_inferred) 537
538 - def _is_durable(self):
539 return pn_message_is_durable(self._msg)
540
541 - def _set_durable(self, value):
542 self._check(pn_message_set_durable(self._msg, bool(value)))
543 544 durable = property(_is_durable, _set_durable, 545 doc=""" 546 The durable property indicates that the message should be held durably 547 by any intermediaries taking responsibility for the message. 548 """) 549
550 - def _get_priority(self):
551 return pn_message_get_priority(self._msg)
552
553 - def _set_priority(self, value):
554 self._check(pn_message_set_priority(self._msg, value))
555 556 priority = property(_get_priority, _set_priority, 557 doc=""" 558 The priority of the message. 559 """) 560
561 - def _get_ttl(self):
562 return pn_message_get_ttl(self._msg)
563
564 - def _set_ttl(self, value):
565 self._check(pn_message_set_ttl(self._msg, value))
566 567 ttl = property(_get_ttl, _set_ttl, 568 doc=""" 569 The time to live of the message measured in milliseconds. Expired 570 messages may be dropped. 571 """) 572
573 - def _is_first_acquirer(self):
574 return pn_message_is_first_acquirer(self._msg)
575
576 - def _set_first_acquirer(self, value):
577 self._check(pn_message_set_first_acquirer(self._msg, bool(value)))
578 579 first_acquirer = property(_is_first_acquirer, _set_first_acquirer, 580 doc=""" 581 True iff the recipient is the first to acquire the message. 582 """) 583
584 - def _get_delivery_count(self):
585 return pn_message_get_delivery_count(self._msg)
586
587 - def _set_delivery_count(self, value):
588 self._check(pn_message_set_delivery_count(self._msg, value))
589 590 delivery_count = property(_get_delivery_count, _set_delivery_count, 591 doc=""" 592 The number of delivery attempts made for this message. 593 """) 594 595
596 - def _get_id(self):
597 return self._id.get_object()
598 - def _set_id(self, value):
599 if type(value) in (int, long): 600 value = ulong(value) 601 self._id.rewind() 602 self._id.put_object(value)
603 id = property(_get_id, _set_id, 604 doc=""" 605 The id of the message. 606 """) 607
608 - def _get_user_id(self):
609 return pn_message_get_user_id(self._msg)
610
611 - def _set_user_id(self, value):
612 self._check(pn_message_set_user_id(self._msg, value))
613 614 user_id = property(_get_user_id, _set_user_id, 615 doc=""" 616 The user id of the message creator. 617 """) 618
619 - def _get_address(self):
620 return pn_message_get_address(self._msg)
621
622 - def _set_address(self, value):
623 self._check(pn_message_set_address(self._msg, value))
624 625 address = property(_get_address, _set_address, 626 doc=""" 627 The address of the message. 628 """) 629
630 - def _get_subject(self):
631 return pn_message_get_subject(self._msg)
632
633 - def _set_subject(self, value):
634 self._check(pn_message_set_subject(self._msg, value))
635 636 subject = property(_get_subject, _set_subject, 637 doc=""" 638 The subject of the message. 639 """) 640
641 - def _get_reply_to(self):
642 return pn_message_get_reply_to(self._msg)
643
644 - def _set_reply_to(self, value):
645 self._check(pn_message_set_reply_to(self._msg, value))
646 647 reply_to = property(_get_reply_to, _set_reply_to, 648 doc=""" 649 The reply-to address for the message. 650 """) 651
652 - def _get_correlation_id(self):
653 return self._correlation_id.get_object()
654 - def _set_correlation_id(self, value):
655 if type(value) in (int, long): 656 value = ulong(value) 657 self._correlation_id.rewind() 658 self._correlation_id.put_object(value)
659 660 correlation_id = property(_get_correlation_id, _set_correlation_id, 661 doc=""" 662 The correlation-id for the message. 663 """) 664
665 - def _get_content_type(self):
666 return pn_message_get_content_type(self._msg)
667
668 - def _set_content_type(self, value):
669 self._check(pn_message_set_content_type(self._msg, value))
670 671 content_type = property(_get_content_type, _set_content_type, 672 doc=""" 673 The content-type of the message. 674 """) 675
676 - def _get_content_encoding(self):
677 return pn_message_get_content_encoding(self._msg)
678
679 - def _set_content_encoding(self, value):
680 self._check(pn_message_set_content_encoding(self._msg, value))
681 682 content_encoding = property(_get_content_encoding, _set_content_encoding, 683 doc=""" 684 The content-encoding of the message. 685 """) 686
687 - def _get_expiry_time(self):
688 return pn_message_get_expiry_time(self._msg)
689
690 - def _set_expiry_time(self, value):
691 self._check(pn_message_set_expiry_time(self._msg, value))
692 693 expiry_time = property(_get_expiry_time, _set_expiry_time, 694 doc=""" 695 The expiry time of the message. 696 """) 697
698 - def _get_creation_time(self):
699 return pn_message_get_creation_time(self._msg)
700
701 - def _set_creation_time(self, value):
702 self._check(pn_message_set_creation_time(self._msg, value))
703 704 creation_time = property(_get_creation_time, _set_creation_time, 705 doc=""" 706 The creation time of the message. 707 """) 708
709 - def _get_group_id(self):
710 return pn_message_get_group_id(self._msg)
711
712 - def _set_group_id(self, value):
713 self._check(pn_message_set_group_id(self._msg, value))
714 715 group_id = property(_get_group_id, _set_group_id, 716 doc=""" 717 The group id of the message. 718 """) 719
720 - def _get_group_sequence(self):
721 return pn_message_get_group_sequence(self._msg)
722
723 - def _set_group_sequence(self, value):
724 self._check(pn_message_set_group_sequence(self._msg, value))
725 726 group_sequence = property(_get_group_sequence, _set_group_sequence, 727 doc=""" 728 The sequence of the message within its group. 729 """) 730
731 - def _get_reply_to_group_id(self):
732 return pn_message_get_reply_to_group_id(self._msg)
733
734 - def _set_reply_to_group_id(self, value):
735 self._check(pn_message_set_reply_to_group_id(self._msg, value))
736 737 reply_to_group_id = property(_get_reply_to_group_id, _set_reply_to_group_id, 738 doc=""" 739 The group-id for any replies. 740 """) 741 742 # XXX
743 - def _get_format(self):
744 return pn_message_get_format(self._msg)
745
746 - def _set_format(self, value):
747 self._check(pn_message_set_format(self._msg, value))
748 749 format = property(_get_format, _set_format, 750 doc=""" 751 The format of the message. 752 """) 753
754 - def encode(self):
755 self._pre_encode() 756 sz = 16 757 while True: 758 err, data = pn_message_encode(self._msg, sz) 759 if err == PN_OVERFLOW: 760 sz *= 2 761 continue 762 else: 763 self._check(err) 764 return data
765
766 - def decode(self, data):
767 self._check(pn_message_decode(self._msg, data, len(data))) 768 self._post_decode()
769
770 - def load(self, data):
771 self._check(pn_message_load(self._msg, data))
772
773 - def save(self):
774 sz = 16 775 while True: 776 err, data = pn_message_save(self._msg, sz) 777 if err == PN_OVERFLOW: 778 sz *= 2 779 continue 780 else: 781 self._check(err) 782 return data
783
784 -class DataException(ProtonException):
785 """ 786 The DataException class is the root of the Data exception hierarchy. 787 All exceptions raised by the Data class extend this exception. 788 """ 789 pass
790
791 -class UnmappedType:
792
793 - def __init__(self, msg):
794 self.msg = msg
795
796 - def __repr__(self):
797 return "UnmappedType(%s)" % self.msg
798
799 -class ulong(long):
800
801 - def __repr__(self):
802 return "ulong(%s)" % long.__repr__(self)
803
804 -class timestamp(long):
805
806 - def __repr__(self):
807 return "timestamp(%s)" % long.__repr__(self)
808
809 -class symbol(unicode):
810
811 - def __repr__(self):
812 return "symbol(%s)" % unicode.__repr__(self)
813
814 -class char(unicode):
815
816 - def __repr__(self):
817 return "char(%s)" % unicode.__repr__(self)
818
819 -class Described(object):
820
821 - def __init__(self, descriptor, value):
822 self.descriptor = descriptor 823 self.value = value
824
825 - def __repr__(self):
826 return "Described(%r, %r)" % (self.descriptor, self.value)
827
828 - def __eq__(self, o):
829 if isinstance(o, Described): 830 return self.descriptor == o.descriptor and self.value == o.value 831 else: 832 return False
833 834 UNDESCRIBED = Constant("UNDESCRIBED")
835 836 -class Array(object):
837
838 - def __init__(self, descriptor, type, *elements):
839 self.descriptor = descriptor 840 self.type = type 841 self.elements = elements
842
843 - def __repr__(self):
844 if self.elements: 845 els = ", %s" % (", ".join(map(repr, self.elements))) 846 else: 847 els = "" 848 return "Array(%r, %r%s)" % (self.descriptor, self.type, els)
849
850 - def __eq__(self, o):
851 if isinstance(o, Array): 852 return self.descriptor == o.descriptor and \ 853 self.type == o.type and self.elements == o.elements 854 else: 855 return False
856
857 -class Data:
858 """ 859 The L{Data} class provides an interface for decoding, extracting, 860 creating, and encoding arbitrary AMQP data. A L{Data} object 861 contains a tree of AMQP values. Leaf nodes in this tree correspond 862 to scalars in the AMQP type system such as L{ints<INT>} or 863 L{strings<STRING>}. Non-leaf nodes in this tree correspond to 864 compound values in the AMQP type system such as L{lists<LIST>}, 865 L{maps<MAP>}, L{arrays<ARRAY>}, or L{described values<DESCRIBED>}. 866 The root node of the tree is the L{Data} object itself and can have 867 an arbitrary number of children. 868 869 A L{Data} object maintains the notion of the current sibling node 870 and a current parent node. Siblings are ordered within their parent. 871 Values are accessed and/or added by using the L{next}, L{prev}, 872 L{enter}, and L{exit} methods to navigate to the desired location in 873 the tree and using the supplied variety of put_*/get_* methods to 874 access or add a value of the desired type. 875 876 The put_* methods will always add a value I{after} the current node 877 in the tree. If the current node has a next sibling the put_* method 878 will overwrite the value on this node. If there is no current node 879 or the current node has no next sibling then one will be added. The 880 put_* methods always set the added/modified node to the current 881 node. The get_* methods read the value of the current node and do 882 not change which node is current. 883 884 The following types of scalar values are supported: 885 886 - L{NULL} 887 - L{BOOL} 888 - L{UBYTE} 889 - L{USHORT} 890 - L{SHORT} 891 - L{UINT} 892 - L{INT} 893 - L{ULONG} 894 - L{LONG} 895 - L{FLOAT} 896 - L{DOUBLE} 897 - L{BINARY} 898 - L{STRING} 899 - L{SYMBOL} 900 901 The following types of compound values are supported: 902 903 - L{DESCRIBED} 904 - L{ARRAY} 905 - L{LIST} 906 - L{MAP} 907 """ 908 909 NULL = PN_NULL; "A null value." 910 BOOL = PN_BOOL; "A boolean value." 911 UBYTE = PN_UBYTE; "An unsigned byte value." 912 BYTE = PN_BYTE; "A signed byte value." 913 USHORT = PN_USHORT; "An unsigned short value." 914 SHORT = PN_SHORT; "A short value." 915 UINT = PN_UINT; "An unsigned int value." 916 INT = PN_INT; "A signed int value." 917 CHAR = PN_CHAR; "A character value." 918 ULONG = PN_ULONG; "An unsigned long value." 919 LONG = PN_LONG; "A signed long value." 920 TIMESTAMP = PN_TIMESTAMP; "A timestamp value." 921 FLOAT = PN_FLOAT; "A float value." 922 DOUBLE = PN_DOUBLE; "A double value." 923 DECIMAL32 = PN_DECIMAL32; "A DECIMAL32 value." 924 DECIMAL64 = PN_DECIMAL64; "A DECIMAL64 value." 925 DECIMAL128 = PN_DECIMAL128; "A DECIMAL128 value." 926 UUID = PN_UUID; "A UUID value." 927 BINARY = PN_BINARY; "A binary string." 928 STRING = PN_STRING; "A unicode string." 929 SYMBOL = PN_SYMBOL; "A symbolic string." 930 DESCRIBED = PN_DESCRIBED; "A described value." 931 ARRAY = PN_ARRAY; "An array value." 932 LIST = PN_LIST; "A list value." 933 MAP = PN_MAP; "A map value." 934
935 - def __init__(self, capacity=16):
936 if type(capacity) in (int, long): 937 self._data = pn_data(capacity) 938 self._free = True 939 else: 940 self._data = capacity 941 self._free = False
942
943 - def __del__(self):
944 if self._free and hasattr(self, "_data"): 945 pn_data_free(self._data) 946 del self._data
947
948 - def _check(self, err):
949 if err < 0: 950 exc = EXCEPTIONS.get(err, DataException) 951 raise exc("[%s]: %s" % (err, pn_data_error(self._data))) 952 else: 953 return err
954
955 - def clear(self):
956 """ 957 Clears the data object. 958 """ 959 pn_data_clear(self._data)
960
961 - def rewind(self):
962 """ 963 Clears current node and sets the parent to the root node. 964 """ 965 pn_data_rewind(self._data)
966
967 - def next(self):
968 """ 969 Advances the current node to its next sibling and returns its 970 type. If there is no next sibling the current node remains 971 unchanged and None is returned. 972 """ 973 found = pn_data_next(self._data) 974 if found: 975 return self.type() 976 else: 977 return None
978
979 - def prev(self):
980 """ 981 Advances the current node to its previous sibling and returns its 982 type. If there is no previous sibling the current node remains 983 unchanged and None is returned. 984 """ 985 found = pn_data_prev(self._data) 986 if found: 987 return self.type() 988 else: 989 return None
990
991 - def enter(self):
992 """ 993 Sets the parent node to the current node and clears the current node. 994 """ 995 return pn_data_enter(self._data)
996
997 - def exit(self):
998 """ 999 Sets the current node to the parent node and the parent node to 1000 its own parent. 1001 """ 1002 return pn_data_exit(self._data)
1003
1004 - def type(self):
1005 """ 1006 Returns the type of the current node. 1007 """ 1008 dtype = pn_data_type(self._data) 1009 if dtype == -1: 1010 return None 1011 else: 1012 return dtype
1013
1014 - def encode(self):
1015 """ 1016 Returns a representation of the data encoded in AMQP format. 1017 """ 1018 size = 1024 1019 while True: 1020 cd, enc = pn_data_encode(self._data, size) 1021 if cd == PN_OVERFLOW: 1022 size *= 2 1023 elif cd >= 0: 1024 return enc 1025 else: 1026 self._check(cd)
1027
1028 - def decode(self, encoded):
1029 """ 1030 Decodes the first value from supplied AMQP data and returns the 1031 number of bytes consumed. 1032 1033 @type encoded: binary 1034 @param encoded: AMQP encoded binary data 1035 """ 1036 return self._check(pn_data_decode(self._data, encoded))
1037
1038 - def put_list(self):
1039 """ 1040 Puts a list value. Elements may be filled by entering the list 1041 node and putting element values. 1042 1043 >>> data = Data() 1044 >>> data.put_list() 1045 >>> data.enter() 1046 >>> data.put_int(1) 1047 >>> data.put_int(2) 1048 >>> data.put_int(3) 1049 >>> data.exit() 1050 """ 1051 self._check(pn_data_put_list(self._data))
1052
1053 - def put_map(self):
1054 """ 1055 Puts a map value. Elements may be filled by entering the map node 1056 and putting alternating key value pairs. 1057 1058 >>> data = Data() 1059 >>> data.put_map() 1060 >>> data.enter() 1061 >>> data.put_string("key") 1062 >>> data.put_string("value") 1063 >>> data.exit() 1064 """ 1065 self._check(pn_data_put_map(self._data))
1066
1067 - def put_array(self, described, element_type):
1068 """ 1069 Puts an array value. Elements may be filled by entering the array 1070 node and putting the element values. The values must all be of the 1071 specified array element type. If an array is described then the 1072 first child value of the array is the descriptor and may be of any 1073 type. 1074 1075 >>> data = Data() 1076 >>> 1077 >>> data.put_array(False, Data.INT) 1078 >>> data.enter() 1079 >>> data.put_int(1) 1080 >>> data.put_int(2) 1081 >>> data.put_int(3) 1082 >>> data.exit() 1083 >>> 1084 >>> data.put_array(True, Data.DOUBLE) 1085 >>> data.enter() 1086 >>> data.put_symbol("array-descriptor") 1087 >>> data.put_double(1.1) 1088 >>> data.put_double(1.2) 1089 >>> data.put_double(1.3) 1090 >>> data.exit() 1091 1092 @type described: bool 1093 @param described: specifies whether the array is described 1094 @type element_type: int 1095 @param element_type: the type of the array elements 1096 """ 1097 self._check(pn_data_put_array(self._data, described, element_type))
1098
1099 - def put_described(self):
1100 """ 1101 Puts a described value. A described node has two children, the 1102 descriptor and the value. These are specified by entering the node 1103 and putting the desired values. 1104 1105 >>> data = Data() 1106 >>> data.put_described() 1107 >>> data.enter() 1108 >>> data.put_symbol("value-descriptor") 1109 >>> data.put_string("the value") 1110 >>> data.exit() 1111 """ 1112 self._check(pn_data_put_described(self._data))
1113
1114 - def put_null(self):
1115 """ 1116 Puts a null value. 1117 """ 1118 self._check(pn_data_put_null(self._data))
1119
1120 - def put_bool(self, b):
1121 """ 1122 Puts a boolean value. 1123 1124 @param b: a boolean value 1125 """ 1126 self._check(pn_data_put_bool(self._data, b))
1127
1128 - def put_ubyte(self, ub):
1129 """ 1130 Puts an unsigned byte value. 1131 1132 @param ub: an integral value 1133 """ 1134 self._check(pn_data_put_ubyte(self._data, ub))
1135
1136 - def put_byte(self, b):
1137 """ 1138 Puts a signed byte value. 1139 1140 @param b: an integral value 1141 """ 1142 self._check(pn_data_put_byte(self._data, b))
1143
1144 - def put_ushort(self, us):
1145 """ 1146 Puts an unsigned short value. 1147 1148 @param us: an integral value. 1149 """ 1150 self._check(pn_data_put_ushort(self._data, us))
1151
1152 - def put_short(self, s):
1153 """ 1154 Puts a signed short value. 1155 1156 @param s: an integral value 1157 """ 1158 self._check(pn_data_put_short(self._data, s))
1159
1160 - def put_uint(self, ui):
1161 """ 1162 Puts an unsigned int value. 1163 1164 @param ui: an integral value 1165 """ 1166 self._check(pn_data_put_uint(self._data, ui))
1167
1168 - def put_int(self, i):
1169 """ 1170 Puts a signed int value. 1171 1172 @param i: an integral value 1173 """ 1174 self._check(pn_data_put_int(self._data, i))
1175
1176 - def put_char(self, c):
1177 """ 1178 Puts a char value. 1179 1180 @param c: a single character 1181 """ 1182 self._check(pn_data_put_char(self._data, ord(c)))
1183
1184 - def put_ulong(self, ul):
1185 """ 1186 Puts an unsigned long value. 1187 1188 @param ul: an integral value 1189 """ 1190 self._check(pn_data_put_ulong(self._data, ul))
1191
1192 - def put_long(self, l):
1193 """ 1194 Puts a signed long value. 1195 1196 @param l: an integral value 1197 """ 1198 self._check(pn_data_put_long(self._data, l))
1199
1200 - def put_timestamp(self, t):
1201 """ 1202 Puts a timestamp value. 1203 1204 @param t: an integral value 1205 """ 1206 self._check(pn_data_put_timestamp(self._data, t))
1207
1208 - def put_float(self, f):
1209 """ 1210 Puts a float value. 1211 1212 @param f: a floating point value 1213 """ 1214 self._check(pn_data_put_float(self._data, f))
1215
1216 - def put_double(self, d):
1217 """ 1218 Puts a double value. 1219 1220 @param d: a floating point value. 1221 """ 1222 self._check(pn_data_put_double(self._data, d))
1223
1224 - def put_decimal32(self, d):
1225 """ 1226 Puts a decimal32 value. 1227 1228 @param d: a decimal32 value 1229 """ 1230 self._check(pn_data_put_decimal32(self._data, d))
1231
1232 - def put_decimal64(self, d):
1233 """ 1234 Puts a decimal64 value. 1235 1236 @param d: a decimal64 value 1237 """ 1238 self._check(pn_data_put_decimal64(self._data, d))
1239
1240 - def put_decimal128(self, d):
1241 """ 1242 Puts a decimal128 value. 1243 1244 @param d: a decimal128 value 1245 """ 1246 self._check(pn_data_put_decimal128(self._data, d))
1247
1248 - def put_uuid(self, u):
1249 """ 1250 Puts a UUID value. 1251 1252 @param u: a uuid value 1253 """ 1254 self._check(pn_data_put_uuid(self._data, u.bytes))
1255
1256 - def put_binary(self, b):
1257 """ 1258 Puts a binary value. 1259 1260 @type b: binary 1261 @param b: a binary value 1262 """ 1263 self._check(pn_data_put_binary(self._data, b))
1264
1265 - def put_string(self, s):
1266 """ 1267 Puts a unicode value. 1268 1269 @type s: unicode 1270 @param s: a unicode value 1271 """ 1272 self._check(pn_data_put_string(self._data, s.encode("utf8")))
1273
1274 - def put_symbol(self, s):
1275 """ 1276 Puts a symbolic value. 1277 1278 @type s: string 1279 @param s: the symbol name 1280 """ 1281 self._check(pn_data_put_symbol(self._data, s))
1282
1283 - def get_list(self):
1284 """ 1285 If the current node is a list, return the number of elements, 1286 otherwise return zero. List elements can be accessed by entering 1287 the list. 1288 1289 >>> count = data.get_list() 1290 >>> data.enter() 1291 >>> for i in range(count): 1292 ... type = data.next() 1293 ... if type == Data.STRING: 1294 ... print data.get_string() 1295 ... elif type == ...: 1296 ... ... 1297 >>> data.exit() 1298 """ 1299 return pn_data_get_list(self._data)
1300
1301 - def get_map(self):
1302 """ 1303 If the current node is a map, return the number of child elements, 1304 otherwise return zero. Key value pairs can be accessed by entering 1305 the map. 1306 1307 >>> count = data.get_map() 1308 >>> data.enter() 1309 >>> for i in range(count/2): 1310 ... type = data.next() 1311 ... if type == Data.STRING: 1312 ... print data.get_string() 1313 ... elif type == ...: 1314 ... ... 1315 >>> data.exit() 1316 """ 1317 return pn_data_get_map(self._data)
1318
1319 - def get_array(self):
1320 """ 1321 If the current node is an array, return a tuple of the element 1322 count, a boolean indicating whether the array is described, and 1323 the type of each element, otherwise return (0, False, None). Array 1324 data can be accessed by entering the array. 1325 1326 >>> # read an array of strings with a symbolic descriptor 1327 >>> count, described, type = data.get_array() 1328 >>> data.enter() 1329 >>> data.next() 1330 >>> print "Descriptor:", data.get_symbol() 1331 >>> for i in range(count): 1332 ... data.next() 1333 ... print "Element:", data.get_string() 1334 >>> data.exit() 1335 """ 1336 count = pn_data_get_array(self._data) 1337 described = pn_data_is_array_described(self._data) 1338 type = pn_data_get_array_type(self._data) 1339 if type == -1: 1340 type = None 1341 return count, described, type
1342
1343 - def is_described(self):
1344 """ 1345 Checks if the current node is a described value. The descriptor 1346 and value may be accessed by entering the described value. 1347 1348 >>> # read a symbolically described string 1349 >>> assert data.is_described() # will error if the current node is not described 1350 >>> data.enter() 1351 >>> print data.get_symbol() 1352 >>> print data.get_string() 1353 >>> data.exit() 1354 """ 1355 return pn_data_is_described(self._data)
1356
1357 - def is_null(self):
1358 """ 1359 Checks if the current node is a null. 1360 """ 1361 self._check(pn_data_get_null(self._data))
1362
1363 - def get_bool(self):
1364 """ 1365 If the current node is a boolean, returns its value, returns False 1366 otherwise. 1367 """ 1368 return pn_data_get_bool(self._data)
1369
1370 - def get_ubyte(self):
1371 """ 1372 If the current node is an unsigned byte, returns its value, 1373 returns 0 otherwise. 1374 """ 1375 return pn_data_get_ubyte(self._data)
1376
1377 - def get_byte(self):
1378 """ 1379 If the current node is a signed byte, returns its value, returns 0 1380 otherwise. 1381 """ 1382 return pn_data_get_byte(self._data)
1383
1384 - def get_ushort(self):
1385 """ 1386 If the current node is an unsigned short, returns its value, 1387 returns 0 otherwise. 1388 """ 1389 return pn_data_get_ushort(self._data)
1390
1391 - def get_short(self):
1392 """ 1393 If the current node is a signed short, returns its value, returns 1394 0 otherwise. 1395 """ 1396 return pn_data_get_short(self._data)
1397
1398 - def get_uint(self):
1399 """ 1400 If the current node is an unsigned int, returns its value, returns 1401 0 otherwise. 1402 """ 1403 return pn_data_get_uint(self._data)
1404
1405 - def get_int(self):
1406 """ 1407 If the current node is a signed int, returns its value, returns 0 1408 otherwise. 1409 """ 1410 return pn_data_get_int(self._data)
1411
1412 - def get_char(self):
1413 """ 1414 If the current node is a char, returns its value, returns 0 1415 otherwise. 1416 """ 1417 return char(unichr(pn_data_get_char(self._data)))
1418
1419 - def get_ulong(self):
1420 """ 1421 If the current node is an unsigned long, returns its value, 1422 returns 0 otherwise. 1423 """ 1424 return ulong(pn_data_get_ulong(self._data))
1425
1426 - def get_long(self):
1427 """ 1428 If the current node is an signed long, returns its value, returns 1429 0 otherwise. 1430 """ 1431 return pn_data_get_long(self._data)
1432
1433 - def get_timestamp(self):
1434 """ 1435 If the current node is a timestamp, returns its value, returns 0 1436 otherwise. 1437 """ 1438 return timestamp(pn_data_get_timestamp(self._data))
1439
1440 - def get_float(self):
1441 """ 1442 If the current node is a float, returns its value, raises 0 1443 otherwise. 1444 """ 1445 return pn_data_get_float(self._data)
1446
1447 - def get_double(self):
1448 """ 1449 If the current node is a double, returns its value, returns 0 1450 otherwise. 1451 """ 1452 return pn_data_get_double(self._data)
1453 1454 # XXX: need to convert
1455 - def get_decimal32(self):
1456 """ 1457 If the current node is a decimal32, returns its value, returns 0 1458 otherwise. 1459 """ 1460 return pn_data_get_decimal32(self._data)
1461 1462 # XXX: need to convert
1463 - def get_decimal64(self):
1464 """ 1465 If the current node is a decimal64, returns its value, returns 0 1466 otherwise. 1467 """ 1468 return pn_data_get_decimal64(self._data)
1469 1470 # XXX: need to convert
1471 - def get_decimal128(self):
1472 """ 1473 If the current node is a decimal128, returns its value, returns 0 1474 otherwise. 1475 """ 1476 return pn_data_get_decimal128(self._data)
1477
1478 - def get_uuid(self):
1479 """ 1480 If the current node is a UUID, returns its value, returns None 1481 otherwise. 1482 """ 1483 if pn_data_type(self._data) == Data.UUID: 1484 return uuid.UUID(bytes=pn_data_get_uuid(self._data)) 1485 else: 1486 return None
1487
1488 - def get_binary(self):
1489 """ 1490 If the current node is binary, returns its value, returns "" 1491 otherwise. 1492 """ 1493 return pn_data_get_binary(self._data)
1494
1495 - def get_string(self):
1496 """ 1497 If the current node is a string, returns its value, returns "" 1498 otherwise. 1499 """ 1500 return pn_data_get_string(self._data).decode("utf8")
1501
1502 - def get_symbol(self):
1503 """ 1504 If the current node is a symbol, returns its value, returns "" 1505 otherwise. 1506 """ 1507 return symbol(pn_data_get_symbol(self._data))
1508
1509 - def copy(self, src):
1510 self._check(pn_data_copy(self._data, src._data))
1511
1512 - def format(self):
1513 sz = 16 1514 while True: 1515 err, result = pn_data_format(self._data, sz) 1516 if err == PN_OVERFLOW: 1517 sz *= 2 1518 continue 1519 else: 1520 self._check(err) 1521 return result
1522
1523 - def dump(self):
1524 pn_data_dump(self._data)
1525
1526 - def put_dict(self, d):
1527 self.put_map() 1528 self.enter() 1529 try: 1530 for k, v in d.items(): 1531 self.put_object(k) 1532 self.put_object(v) 1533 finally: 1534 self.exit()
1535
1536 - def get_dict(self):
1537 if self.enter(): 1538 try: 1539 result = {} 1540 while self.next(): 1541 k = self.get_object() 1542 if self.next(): 1543 v = self.get_object() 1544 else: 1545 v = None 1546 result[k] = v 1547 finally: 1548 self.exit() 1549 return result
1550
1551 - def put_sequence(self, s):
1552 self.put_list() 1553 self.enter() 1554 try: 1555 for o in s: 1556 self.put_object(o) 1557 finally: 1558 self.exit()
1559
1560 - def get_sequence(self):
1561 if self.enter(): 1562 try: 1563 result = [] 1564 while self.next(): 1565 result.append(self.get_object()) 1566 finally: 1567 self.exit() 1568 return result
1569
1570 - def get_py_described(self):
1571 if self.enter(): 1572 try: 1573 self.next() 1574 descriptor = self.get_object() 1575 self.next() 1576 value = self.get_object() 1577 finally: 1578 self.exit() 1579 return Described(descriptor, value)
1580
1581 - def put_py_described(self, d):
1582 self.put_described() 1583 self.enter() 1584 try: 1585 self.put_object(d.descriptor) 1586 self.put_object(d.value) 1587 finally: 1588 self.exit()
1589
1590 - def get_py_array(self):
1591 count, described, type = self.get_array() 1592 if self.enter(): 1593 try: 1594 if described: 1595 self.next() 1596 descriptor = self.get_object() 1597 else: 1598 descriptor = UNDESCRIBED 1599 elements = [] 1600 while self.next(): 1601 elements.append(self.get_object()) 1602 finally: 1603 self.exit() 1604 return Array(descriptor, type, *elements)
1605
1606 - def put_py_array(self, a):
1607 self.put_array(a.descriptor != UNDESCRIBED, a.type) 1608 self.enter() 1609 try: 1610 for e in a.elements: 1611 self.put_object(e) 1612 finally: 1613 self.exit()
1614 1615 put_mappings = { 1616 None.__class__: lambda s, _: s.put_null(), 1617 bool: put_bool, 1618 dict: put_dict, 1619 list: put_sequence, 1620 tuple: put_sequence, 1621 unicode: put_string, 1622 bytes: put_binary, 1623 symbol: put_symbol, 1624 int: put_long, 1625 char: put_char, 1626 long: put_long, 1627 ulong: put_ulong, 1628 timestamp: put_timestamp, 1629 float: put_double, 1630 uuid.UUID: put_uuid, 1631 Described: put_py_described, 1632 Array: put_py_array 1633 } 1634 get_mappings = { 1635 NULL: lambda s: None, 1636 BOOL: get_bool, 1637 BYTE: get_byte, 1638 UBYTE: get_ubyte, 1639 SHORT: get_short, 1640 USHORT: get_ushort, 1641 INT: get_int, 1642 UINT: get_uint, 1643 CHAR: get_char, 1644 LONG: get_long, 1645 ULONG: get_ulong, 1646 TIMESTAMP: get_timestamp, 1647 FLOAT: get_float, 1648 DOUBLE: get_double, 1649 DECIMAL32: get_decimal32, 1650 DECIMAL64: get_decimal64, 1651 DECIMAL128: get_decimal128, 1652 UUID: get_uuid, 1653 BINARY: get_binary, 1654 STRING: get_string, 1655 SYMBOL: get_symbol, 1656 DESCRIBED: get_py_described, 1657 ARRAY: get_py_array, 1658 LIST: get_sequence, 1659 MAP: get_dict 1660 } 1661
1662 - def put_object(self, obj):
1663 putter = self.put_mappings[obj.__class__] 1664 putter(self, obj)
1665
1666 - def get_object(self):
1667 type = self.type() 1668 if type is None: return None 1669 getter = self.get_mappings.get(type) 1670 if getter: 1671 return getter(self) 1672 else: 1673 self.dump() 1674 return UnmappedType(str(type))
1675
1676 1677 -class ConnectionException(ProtonException):
1678 pass
1679
1680 -class Endpoint(object):
1681 1682 LOCAL_UNINIT = PN_LOCAL_UNINIT 1683 REMOTE_UNINIT = PN_REMOTE_UNINIT 1684 LOCAL_ACTIVE = PN_LOCAL_ACTIVE 1685 REMOTE_ACTIVE = PN_REMOTE_ACTIVE 1686 LOCAL_CLOSED = PN_LOCAL_CLOSED 1687 REMOTE_CLOSED = PN_REMOTE_CLOSED 1688
1689 - def __init__(self):
1690 self.condition = None
1691
1692 - def _update_cond(self):
1693 impl = self._get_cond_impl() 1694 pn_condition_clear(impl) 1695 if self.condition: 1696 pn_condition_set_name(impl, self.condition.name) 1697 pn_condition_set_description(impl, self.condition.description) 1698 info = Data(pn_condition_info(impl)) 1699 if self.condition.info: 1700 info.put_object(self.condition.info)
1701 1702 @property
1703 - def remote_condition(self):
1704 impl = self._get_remote_cond_impl() 1705 if pn_condition_is_set(impl): 1706 info_impl = Data(pn_condition_info(impl)) 1707 info_impl.rewind() 1708 info_impl.next() 1709 info = info_impl.get_object() 1710 info_impl.rewind() 1711 return Condition(pn_condition_get_name(impl), 1712 pn_condition_get_description(impl), 1713 info)
1714
1715 -class Condition:
1716
1717 - def __init__(self, name, description=None, info=None):
1718 self.name = name 1719 self.description = description 1720 self.info = info
1721
1722 - def __repr__(self):
1723 return "Condition(%s)" % ", ".join([repr(x) for x in 1724 (self.name, self.description, self.info) 1725 if x])
1726
1727 - def __eq__(self, o):
1728 if not isinstance(o, Condition): return False 1729 return self.name == o.name and \ 1730 self.description == o.description and \ 1731 self.info == o.info
1732
1733 -def wrap_connection(conn):
1734 if not conn: return None 1735 ctx = pn_connection_get_context(conn) 1736 if ctx: return ctx 1737 wrapper = Connection(_conn=conn) 1738 return wrapper
1739
1740 -class Connection(Endpoint):
1741
1742 - def __init__(self, _conn=None):
1743 Endpoint.__init__(self) 1744 if _conn: 1745 self._conn = _conn 1746 else: 1747 self._conn = pn_connection() 1748 pn_connection_set_context(self._conn, self)
1749
1750 - def __del__(self):
1751 if hasattr(self, "_conn"): 1752 pn_connection_free(self._conn) 1753 del self._conn
1754
1755 - def _check(self, err):
1756 if err < 0: 1757 exc = EXCEPTIONS.get(err, ConnectionException) 1758 raise exc("[%s]: %s" % (err, pn_connection_error(self._conn))) 1759 else: 1760 return err
1761
1762 - def _get_cond_impl(self):
1763 return pn_connection_condition(self._conn)
1764
1765 - def _get_remote_cond_impl(self):
1766 return pn_connection_remote_condition(self._conn)
1767
1768 - def _get_container(self):
1769 return pn_connection_get_container(self._conn)
1770 - def _set_container(self, name):
1771 return pn_connection_set_container(self._conn, name)
1772 1773 container = property(_get_container, _set_container) 1774
1775 - def _get_hostname(self):
1776 return pn_connection_get_hostname(self._conn)
1777 - def _set_hostname(self, name):
1778 return pn_connection_set_hostname(self._conn, name)
1779 1780 hostname = property(_get_hostname, _set_hostname) 1781 1782 @property
1783 - def remote_container(self):
1784 return pn_connection_remote_container(self._conn)
1785 1786 @property
1787 - def remote_hostname(self):
1788 return pn_connection_remote_hostname(self._conn)
1789 1790 @property
1791 - def offered_capabilities(self):
1792 return Data(pn_connection_offered_capabilities(self._conn))
1793 1794 @property
1795 - def desired_capabilities(self):
1796 return Data(pn_connection_desired_capabilities(self._conn))
1797 1798 @property
1800 return Data(pn_connection_remote_offered_capabilities(self._conn))
1801 1802 @property
1804 return Data(pn_connection_remote_desired_capabilities(self._conn))
1805
1806 - def open(self):
1807 pn_connection_open(self._conn)
1808
1809 - def close(self):
1810 self._update_cond() 1811 pn_connection_close(self._conn)
1812 1813 @property
1814 - def state(self):
1815 return pn_connection_state(self._conn)
1816 1817 @property
1818 - def writable(self):
1819 return pn_connection_writable(self._conn)
1820
1821 - def session(self):
1822 return wrap_session(pn_session(self._conn))
1823
1824 - def session_head(self, mask):
1825 return wrap_session(pn_session_head(self._conn, mask))
1826 1829 1830 @property
1831 - def work_head(self):
1832 return wrap_delivery(pn_work_head(self._conn))
1833
1834 -class SessionException(ProtonException):
1835 pass
1836
1837 -def wrap_session(ssn):
1838 if ssn is None: return None 1839 ctx = pn_session_get_context(ssn) 1840 if ctx: 1841 return ctx 1842 else: 1843 wrapper = Session(ssn) 1844 pn_session_set_context(ssn, wrapper) 1845 return wrapper
1846
1847 -class Session(Endpoint):
1848
1849 - def __init__(self, ssn):
1850 Endpoint.__init__(self) 1851 self._ssn = ssn
1852
1853 - def __del__(self):
1854 if hasattr(self, "_ssn"): 1855 pn_session_free(self._ssn) 1856 del self._ssn
1857
1858 - def _get_cond_impl(self):
1859 return pn_session_condition(self._ssn)
1860
1861 - def _get_remote_cond_impl(self):
1862 return pn_session_remote_condition(self._ssn)
1863
1864 - def open(self):
1865 pn_session_open(self._ssn)
1866
1867 - def close(self):
1868 self._update_cond() 1869 pn_session_close(self._ssn)
1870 1871 @property
1872 - def state(self):
1873 return pn_session_state(self._ssn)
1874 1875 @property
1876 - def connection(self):
1877 return wrap_connection(pn_session_connection(self._ssn))
1878
1879 - def sender(self, name):
1880 return wrap_link(pn_sender(self._ssn, name))
1881
1882 - def receiver(self, name):
1883 return wrap_link(pn_receiver(self._ssn, name))
1884
1885 -class LinkException(ProtonException):
1886 pass
1887 1900 1983
1984 -class Terminus(object):
1985 1986 UNSPECIFIED = PN_UNSPECIFIED 1987 SOURCE = PN_SOURCE 1988 TARGET = PN_TARGET 1989 COORDINATOR = PN_COORDINATOR 1990 1991 NONDURABLE = PN_NONDURABLE 1992 CONFIGURATION = PN_CONFIGURATION 1993 DELIVERIES = PN_DELIVERIES 1994
1995 - def __init__(self, impl):
1996 self._impl = impl
1997
1998 - def _check(self, err):
1999 if err < 0: 2000 exc = EXCEPTIONS.get(err, LinkException) 2001 raise exc("[%s]" % err) 2002 else: 2003 return err
2004
2005 - def _get_type(self):
2006 return pn_terminus_get_type(self._impl)
2007 - def _set_type(self, type):
2008 self._check(pn_terminus_set_type(self._impl, type))
2009 type = property(_get_type, _set_type) 2010
2011 - def _get_address(self):
2012 return pn_terminus_get_address(self._impl)
2013 - def _set_address(self, address):
2014 self._check(pn_terminus_set_address(self._impl, address))
2015 address = property(_get_address, _set_address) 2016
2017 - def _get_durability(self):
2018 return pn_terminus_get_durability(self._impl)
2019 - def _set_durability(self, seconds):
2020 self._check(pn_terminus_set_durability(self._impl, seconds))
2021 durability = property(_get_durability, _set_durability) 2022
2023 - def _get_expiry_policy(self):
2024 return pn_terminus_get_expiry_policy(self._impl)
2025 - def _set_expiry_policy(self, seconds):
2026 self._check(pn_terminus_set_expiry_policy(self._impl, seconds))
2027 expiry_policy = property(_get_expiry_policy, _set_expiry_policy) 2028
2029 - def _get_timeout(self):
2030 return pn_terminus_get_timeout(self._impl)
2031 - def _set_timeout(self, seconds):
2032 self._check(pn_terminus_set_timeout(self._impl, seconds))
2033 timeout = property(_get_timeout, _set_timeout) 2034
2035 - def _is_dynamic(self):
2036 return pn_terminus_is_dynamic(self._impl)
2037 - def _set_dynamic(self, dynamic):
2038 self._check(pn_terminus_set_dynamic(self._impl, dynamic))
2039 dynamic = property(_is_dynamic, _set_dynamic) 2040 2041 @property
2042 - def properties(self):
2043 return Data(pn_terminus_properties(self._impl))
2044 2045 @property
2046 - def capabilities(self):
2047 return Data(pn_terminus_capabilities(self._impl))
2048 2049 @property
2050 - def outcomes(self):
2051 return Data(pn_terminus_outcomes(self._impl))
2052 2053 @property
2054 - def filter(self):
2055 return Data(pn_terminus_filter(self._impl))
2056
2057 - def copy(self, src):
2058 self._check(pn_terminus_copy(self._impl, src._impl))
2059
2060 2061 -class Sender(Link):
2062
2063 - def offered(self, n):
2064 pn_link_offered(self._link, n)
2065
2066 - def send(self, bytes):
2067 return self._check(pn_link_send(self._link, bytes))
2068
2069 - def drained(self):
2070 pn_link_drained(self._link)
2071
2072 -class Receiver(Link):
2073
2074 - def flow(self, n):
2075 pn_link_flow(self._link, n)
2076
2077 - def recv(self, limit):
2078 n, bytes = pn_link_recv(self._link, limit) 2079 if n == PN_EOS: 2080 return None 2081 else: 2082 self._check(n) 2083 return bytes
2084
2085 - def drain(self, n):
2086 pn_link_drain(self._link, n)
2087
2088 -def wrap_delivery(dlv):
2089 if not dlv: return None 2090 ctx = pn_delivery_get_context(dlv) 2091 if ctx: return ctx 2092 wrapper = Delivery(dlv) 2093 pn_delivery_set_context(dlv, wrapper) 2094 return wrapper
2095
2096 -class Delivery(object):
2097 2098 ACCEPTED = PN_ACCEPTED 2099
2100 - def __init__(self, dlv):
2101 self._dlv = dlv
2102 2103 @property
2104 - def tag(self):
2105 return pn_delivery_tag(self._dlv)
2106 2107 @property
2108 - def writable(self):
2109 return pn_delivery_writable(self._dlv)
2110 2111 @property
2112 - def readable(self):
2113 return pn_delivery_readable(self._dlv)
2114 2115 @property
2116 - def updated(self):
2117 return pn_delivery_updated(self._dlv)
2118
2119 - def update(self, state):
2120 pn_delivery_update(self._dlv, state)
2121 2122 @property
2123 - def local_state(self):
2124 return pn_delivery_local_state(self._dlv)
2125 2126 @property
2127 - def remote_state(self):
2128 return pn_delivery_remote_state(self._dlv)
2129 2130 @property
2131 - def settled(self):
2132 return pn_delivery_settled(self._dlv)
2133
2134 - def settle(self):
2135 pn_delivery_settle(self._dlv)
2136 2137 @property
2138 - def work_next(self):
2139 return wrap_delivery(pn_work_next(self._dlv))
2140
2141 -class TransportException(ProtonException):
2142 pass
2143
2144 -class Transport(object):
2145 2146 TRACE_DRV = PN_TRACE_DRV 2147 TRACE_FRM = PN_TRACE_FRM 2148 TRACE_RAW = PN_TRACE_RAW 2149
2150 - def __init__(self):
2151 self._trans = pn_transport()
2152
2153 - def __del__(self):
2154 if hasattr(self, "_trans"): 2155 pn_transport_free(self._trans) 2156 del self._trans
2157
2158 - def _check(self, err):
2159 if err < 0: 2160 exc = EXCEPTIONS.get(err, TransportException) 2161 raise exc("[%s]: %s" % (err, pn_error_text(pn_transport_error(self._trans)))) 2162 else: 2163 return err
2164
2165 - def bind(self, connection):
2166 self._check(pn_transport_bind(self._trans, connection._conn))
2167
2168 - def trace(self, n):
2169 pn_transport_trace(self._trans, n)
2170
2171 - def tick(self, now):
2172 return pn_transport_tick(self._trans, now)
2173
2174 - def output(self, n):
2175 cd, out = pn_transport_output(self._trans, n) 2176 if cd == PN_EOS: 2177 return None 2178 else: 2179 self._check(cd) 2180 return out
2181
2182 - def input(self, binary):
2183 n = pn_transport_input(self._trans, binary) 2184 if n == PN_EOS: 2185 return None 2186 else: 2187 return self._check(n)
2188 2189 # AMQP 1.0 max-frame-size
2190 - def _get_max_frame_size(self):
2191 return pn_transport_get_max_frame(self._trans)
2192
2193 - def _set_max_frame_size(self, value):
2194 pn_transport_set_max_frame(self._trans, value)
2195 2196 max_frame_size = property(_get_max_frame_size, _set_max_frame_size, 2197 doc=""" 2198 Sets the maximum size for received frames (in bytes). 2199 """) 2200 2201 @property
2202 - def remote_max_frame_size(self):
2203 return pn_transport_get_remote_max_frame(self._trans)
2204 2205 # AMQP 1.0 idle-time-out
2206 - def _get_idle_timeout(self):
2207 return pn_transport_get_idle_timeout(self._trans)
2208
2209 - def _set_idle_timeout(self, value):
2210 pn_transport_set_idle_timeout(self._trans, value)
2211 2212 idle_timeout = property(_get_idle_timeout, _set_idle_timeout, 2213 doc=""" 2214 The idle timeout of the connection (in milliseconds). 2215 """) 2216 2217 @property
2218 - def remote_idle_timeout(self):
2219 return pn_transport_get_remote_idle_timeout(self._trans)
2220 2221 @property
2222 - def frames_output(self):
2223 return pn_transport_get_frames_output(self._trans)
2224 2225 @property
2226 - def frames_input(self):
2227 return pn_transport_get_frames_input(self._trans)
2228
2229 -class SASLException(TransportException):
2230 pass
2231
2232 -class SASL(object):
2233 2234 OK = PN_SASL_OK 2235 AUTH = PN_SASL_AUTH 2236
2237 - def __init__(self, transport):
2238 self._sasl = pn_sasl(transport._trans)
2239
2240 - def _check(self, err):
2241 if err < 0: 2242 exc = EXCEPTIONS.get(err, SASLException) 2243 raise exc("[%s]" % (err)) 2244 else: 2245 return err
2246
2247 - def mechanisms(self, mechs):
2248 pn_sasl_mechanisms(self._sasl, mechs)
2249
2250 - def client(self):
2251 pn_sasl_client(self._sasl)
2252
2253 - def server(self):
2254 pn_sasl_server(self._sasl)
2255
2256 - def plain(self, user, password):
2257 pn_sasl_plain(self._sasl, user, password)
2258
2259 - def send(self, data):
2260 self._check(pn_sasl_send(self._sasl, data, len(data)))
2261
2262 - def recv(self):
2263 sz = 16 2264 while True: 2265 n, data = pn_sasl_recv(self._sasl, sz) 2266 if n == PN_OVERFLOW: 2267 sz *= 2 2268 continue 2269 elif n == PN_EOS: 2270 return None 2271 else: 2272 self._check(n) 2273 return data
2274 2275 @property
2276 - def outcome(self):
2277 outcome = pn_sasl_outcome(self._sasl) 2278 if outcome == PN_SASL_NONE: 2279 return None 2280 else: 2281 return outcome
2282
2283 - def done(self, outcome):
2284 pn_sasl_done(self._sasl, outcome)
2285
2286 -class SSLException(TransportException):
2287 pass
2288
2289 -class SSLUnavailable(SSLException):
2290 pass
2291
2292 -class SSLDomain(object):
2293 2294 MODE_CLIENT = PN_SSL_MODE_CLIENT 2295 MODE_SERVER = PN_SSL_MODE_SERVER 2296 VERIFY_PEER = PN_SSL_VERIFY_PEER 2297 VERIFY_PEER_NAME = PN_SSL_VERIFY_PEER_NAME 2298 ANONYMOUS_PEER = PN_SSL_ANONYMOUS_PEER 2299
2300 - def __init__(self, mode):
2301 self._domain = pn_ssl_domain(mode) 2302 if self._domain is None: 2303 raise SSLUnavailable()
2304
2305 - def _check(self, err):
2306 if err < 0: 2307 exc = EXCEPTIONS.get(err, SSLException) 2308 raise exc("SSL failure.") 2309 else: 2310 return err
2311
2312 - def set_credentials(self, cert_file, key_file, password):
2313 return self._check( pn_ssl_domain_set_credentials(self._domain, 2314 cert_file, key_file, 2315 password) )
2316 - def set_trusted_ca_db(self, certificate_db):
2317 return self._check( pn_ssl_domain_set_trusted_ca_db(self._domain, 2318 certificate_db) )
2319 - def set_peer_authentication(self, verify_mode, trusted_CAs=None):
2320 return self._check( pn_ssl_domain_set_peer_authentication(self._domain, 2321 verify_mode, 2322 trusted_CAs) )
2323
2324 - def allow_unsecured_client(self):
2325 return self._check( pn_ssl_domain_allow_unsecured_client(self._domain) )
2326
2327 -class SSL(object):
2328
2329 - def _check(self, err):
2330 if err < 0: 2331 exc = EXCEPTIONS.get(err, SSLException) 2332 raise exc("SSL failure.") 2333 else: 2334 return err
2335
2336 - def __init__(self, transport, domain, session_details=None):
2337 session_id = None 2338 if session_details: 2339 session_id = session_details.get_session_id() 2340 self._ssl = pn_ssl( transport._trans ) 2341 if self._ssl is None: 2342 raise SSLUnavailable() 2343 pn_ssl_init( self._ssl, domain._domain, session_id )
2344
2345 - def cipher_name(self):
2346 rc, name = pn_ssl_get_cipher_name( self._ssl, 128 ) 2347 if rc: 2348 return name 2349 return None
2350
2351 - def protocol_name(self):
2352 rc, name = pn_ssl_get_protocol_name( self._ssl, 128 ) 2353 if rc: 2354 return name 2355 return None
2356 2357 RESUME_UNKNOWN = PN_SSL_RESUME_UNKNOWN 2358 RESUME_NEW = PN_SSL_RESUME_NEW 2359 RESUME_REUSED = PN_SSL_RESUME_REUSED 2360
2361 - def resume_status(self):
2362 return pn_ssl_resume_status( self._ssl )
2363
2364 - def _set_peer_hostname(self, hostname):
2365 self._check(pn_ssl_set_peer_hostname( self._ssl, hostname ))
2366 - def _get_peer_hostname(self):
2367 err, name = pn_ssl_get_peer_hostname( self._ssl, 1024 ) 2368 self._check(err) 2369 return name
2370 peer_hostname = property(_get_peer_hostname, _set_peer_hostname, 2371 doc=""" 2372 Manage the expected name of the remote peer. Used to authenticate the remote. 2373 """)
2374
2375 2376 -class SSLSessionDetails(object):
2377 """ Unique identifier for the SSL session. Used to resume previous session on a new 2378 SSL connection. 2379 """ 2380
2381 - def __init__(self, session_id):
2382 self._session_id = session_id
2383
2384 - def get_session_id(self):
2385 return self._session_id
2386 2387 __all__ = [ 2388 "LANGUAGE", 2389 "PN_SESSION_WINDOW", 2390 "ACCEPTED", 2391 "AUTOMATIC", 2392 "PENDING", 2393 "MANUAL", 2394 "REJECTED", 2395 "UNDESCRIBED", 2396 "Array", 2397 "Condition", 2398 "Connection", 2399 "Data", 2400 "Delivery", 2401 "Described", 2402 "Endpoint", 2403 "Link", 2404 "Message", 2405 "MessageException", 2406 "Messenger", 2407 "MessengerException", 2408 "ProtonException", 2409 "Receiver", 2410 "SASL", 2411 "Sender", 2412 "Session", 2413 "SSL", 2414 "SSLDomain", 2415 "SSLSessionDetails", 2416 "SSLUnavailable", 2417 "Terminus", 2418 "Timeout", 2419 "Transport", 2420 "TransportException", 2421 "char", 2422 "symbol", 2423 "timestamp", 2424 "ulong" 2425 ] 2426