├── AMQP.Types.pas ├── AMQPTest.dpr ├── AMQPTest.dproj ├── AMQPTest.dproj.local ├── AMQPTest.identcache ├── AMQPTest.res ├── LICENSE ├── README.md ├── TestBinding.dpr ├── TestBinding.dproj ├── TestBinding.dproj.local ├── TestBinding.identcache ├── TestCreateExchange.dpr ├── TestCreateExchange.dproj ├── TestCreateExchange.dproj.local ├── TestCreateExchange.identcache ├── TestRPCClient.dpr ├── TestRPCClient.dproj ├── TestRPCClient.dproj.local ├── TestRPCClient.identcache ├── TestRPCClient.res ├── TestRpcServer.dpr ├── TestRpcServer.dproj ├── TestRpcServer.dproj.local ├── TestRpcServer.identcache ├── TestRpcServer.lpi ├── TestRpcServer.lps ├── TestRpcServer.res ├── TestSendString.dpr ├── TestSendString.dproj ├── TestSendString.dproj.local ├── TestSendString.identcache ├── TestSendString.res ├── TestTimeout.dpr ├── TestTimeout.dproj ├── TestTimeout.dproj.local ├── TestTimeout.identcache ├── TestUnbind.dpr ├── TestUnbind.dproj ├── TestUnbind.dproj.local ├── TestUnbind.identcache ├── amqp.api.pas ├── amqp.connection.pas ├── amqp.consumer.pas ├── amqp.framing.pas ├── amqp.mem.pas ├── amqp.privt.pas ├── amqp.socket.pas ├── amqp.table.pas ├── amqp.tcp_socket.pas ├── amqp.time.pas ├── amqp_tcp_socket.pas └── config.inc /AMQPTest.dpr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/AMQPTest.dpr -------------------------------------------------------------------------------- /AMQPTest.dproj.local: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas 5 | 1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas 6 | 1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas 7 | 1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas 8 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas 9 | 1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas 10 | 1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas 11 | 1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas 12 | 1899-12-30 00:00:00.000.382,=D:\MyCode\AMQP-Delphi\Unit1.pas 13 | 1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 14 | 1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas 15 | 1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas 16 | 1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas 17 | 1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas 18 | 1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas 19 | 1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas 20 | 1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas 21 | 1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit2.pas 22 | 1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas= 23 | 1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas 24 | 1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 25 | 1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas 26 | 1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas 27 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\amqp.api.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 28 | 1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas= 29 | 1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas 30 | 1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas 31 | 1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Field.pas 32 | 1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas 33 | 1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas= 34 | 1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas= 35 | 1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas 36 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas 37 | 1899-12-30 00:00:00.000.044,D:\MyCode\AMQP-Delphi\amqp.consumer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 38 | 1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\amqp.socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 39 | 1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\amqp.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 40 | 1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas= 41 | 1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas= 42 | 1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas= 43 | 1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\amqp.framing.pas=D:\MyCode\AMQP-Delphi\framing.pas 44 | 1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas= 45 | 1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 46 | 1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\amqp.connection.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 47 | 1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 48 | 1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas= 49 | 1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas 50 | 1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\amqp.mem.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 51 | 1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\amqp.table.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 52 | 1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas= 53 | 1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 54 | 1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas 55 | 1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas 56 | 1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\amqp.time.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 57 | 1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas= 58 | 1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas 59 | 1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas 60 | 1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas 61 | 1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas 62 | 1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas 63 | 1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas 64 | 1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas= 65 | 1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 66 | 1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas 67 | 1899-12-30 00:00:00.000.090,D:\MyCode\Project1.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj 68 | 1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas 69 | 1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas 70 | 71 | 72 | -------------------------------------------------------------------------------- /AMQPTest.identcache: -------------------------------------------------------------------------------- 1 | -D:\MyCode\rabbitmq-Delphi\demo\AMQP.Types.pas0D:\MyCode\rabbitmq-Delphi\demo\amqp.consumer.pas2D:\MyCode\rabbitmq-Delphi\demo\amqp.connection.pas+D:\MyCode\rabbitmq-Delphi\demo\AMQPTest.dpr+D:\MyCode\rabbitmq-Delphi\demo\amqp.mem.pas.D:\MyCode\rabbitmq-Delphi\demo\amqp.socket.pas2D:\MyCode\rabbitmq-Delphi\demo\amqp.tcp_socket.pas+D:\MyCode\rabbitmq-Delphi\demo\amqp.api.pas,D:\MyCode\rabbitmq-Delphi\demo\amqp.time.pas)D:\MyCode\rabbitmq-Delphi\demo\MyFunc.pas/D:\MyCode\rabbitmq-Delphi\demo\amqp.framing.pas-D:\MyCode\rabbitmq-Delphi\demo\amqp.table.pas-D:\MyCode\rabbitmq-Delphi\demo\amqp.privt.pas -------------------------------------------------------------------------------- /AMQPTest.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/AMQPTest.res -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rabbitmq-delphi 2 | This project is directly translated from the open source project rabbitmq-c. On windows, it is compiled with Lazarus and Delphi XE2 and above. The network library used is https://github.com/winddriver/Delphi-Cross-Socket. 3 | If you don't know what rabbitmq,please read https://en.wikipedia.org/wiki/RabbitMQ or visit official web http://www.rabbitmq.com. 4 | -------------------------------------------------------------------------------- /TestBinding.dpr: -------------------------------------------------------------------------------- 1 | program TestBinding; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | amqp.api in '..\amqp.api.pas', 10 | amqp.connection in '..\amqp.connection.pas', 11 | amqp.consumer in '..\amqp.consumer.pas', 12 | amqp.framing in '..\amqp.framing.pas', 13 | amqp.mem in '..\amqp.mem.pas', 14 | amqp.privt in '..\amqp.privt.pas', 15 | amqp.socket in '..\amqp.socket.pas', 16 | amqp.table in '..\amqp.table.pas', 17 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 18 | amqp.time in '..\amqp.time.pas', 19 | AMQP.Types in '..\AMQP.Types.pas', 20 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 21 | 22 | {var MyEnum : TMyEnum; 23 | begin 24 | 25 | MyEnum := Two; 26 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 27 | 28 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 29 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 30 | readln; 31 | 32 | end. } 33 | 34 | function main:integer; 35 | var 36 | port, status : integer; 37 | ret : Tamqp_rpc_reply; 38 | socket : Pamqp_socket; 39 | conn : Pamqp_connection_state; 40 | props : Tamqp_basic_properties; 41 | hostname, bindkey, exchange, queue: PAnsiChar; 42 | vl: Tva_list; 43 | begin 44 | socket := nil; 45 | 46 | hostname := 'localhost'; 47 | port := 5672; 48 | exchange := 'Test.EX'; 49 | bindkey := 'test-key'; 50 | queue := 'Queue.Test'; 51 | 52 | if initializeWinsockIfNecessary() < 1 then 53 | begin 54 | Writeln('Failed to initialize "winsock": '); 55 | Exit; 56 | end; 57 | 58 | conn := amqp_new_connection(); 59 | socket := amqp_tcp_socket_new(conn); 60 | if not Assigned(socket) then begin 61 | Writeln('creating TCP socket failed!'); 62 | Exit; 63 | end; 64 | status := amqp_socket_open(socket, hostname, port); 65 | if status > 0 then begin 66 | Writeln('opening TCP socket failed!'); 67 | Exit; 68 | end; 69 | vl.username := 'sa'; 70 | vl.password := 'admin'; 71 | vl.identity := ''; 72 | ret := amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl); 73 | 74 | if ret.library_error < 0 then 75 | Exit; 76 | 77 | var P := amqp_channel_open(conn, 1); 78 | IF P = nil then 79 | Exit; 80 | var reply := amqp_get_rpc_reply(conn); 81 | if reply.library_error < 0 then 82 | Exit; 83 | 84 | amqp_queue_bind(conn, 1, amqp_cstring_bytes(queue), 85 | amqp_cstring_bytes(exchange), amqp_cstring_bytes(bindkey), 86 | amqp_empty_table); 87 | if reply.library_error < 0 then 88 | Exit; 89 | amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS); 90 | amqp_connection_close(conn, AMQP_REPLY_SUCCESS); 91 | amqp_destroy_connection(conn); 92 | Result := 0; 93 | end; 94 | 95 | 96 | begin 97 | try 98 | Main; 99 | except 100 | on e:Exception do 101 | WriteLn(e.Message); 102 | end; 103 | end. 104 | 105 | -------------------------------------------------------------------------------- /TestBinding.dproj.local: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas 5 | 1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas 6 | 1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas 7 | 1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas 8 | 1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 9 | 1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.pas 10 | 1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.mem.pas 11 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.api.pas 12 | 1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas 13 | 1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas 14 | 1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas 15 | 1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas 16 | 1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas 17 | 1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas 18 | 1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas 19 | 1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas 20 | 1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas 21 | 1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas 22 | 1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas 23 | 1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\framing.pas 24 | 1899-12-30 00:00:00.000.797,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas 25 | 1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\Unit2.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 26 | 1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas 27 | 1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas= 28 | 1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas 29 | 1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas= 30 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 31 | 1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas 32 | 1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 33 | 1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Login.pas 34 | 1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.connection.pas 35 | 1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.socket.pas 36 | 1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas 37 | 1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.table.pas 38 | 1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 39 | 1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas= 40 | 1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.time.pas 41 | 1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas= 42 | 1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas 43 | 1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas= 44 | 1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas= 45 | 1899-12-30 00:00:00.000.580,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas 46 | 1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 47 | 1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 48 | 1899-12-30 00:00:00.000.700,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas 49 | 1899-12-30 00:00:00.000.489,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas 50 | 1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas= 51 | 1899-12-30 00:00:00.000.669,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas 52 | 1899-12-30 00:00:00.000.470,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas 53 | 1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas 54 | 1899-12-30 00:00:00.000.605,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas 55 | 1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas= 56 | 1899-12-30 00:00:00.000.502,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas 57 | 1899-12-30 00:00:00.000.760,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas 58 | 1899-12-30 00:00:00.000.539,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas 59 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\TestBinding.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj 60 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 61 | 1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas= 62 | 1899-12-30 00:00:00.000.090,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\Project1.dproj 63 | 1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 64 | 1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas 65 | 1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas 66 | 1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas= 67 | 1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas 68 | 1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas 69 | 1899-12-30 00:00:00.000.727,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas 70 | 1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas 71 | 1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas 72 | 1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.framing.pas 73 | 1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 74 | 1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 75 | 1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas= 76 | 1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 77 | 1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas 78 | 1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas 79 | 1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas= 80 | 1899-12-30 00:00:00.000.634,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas 81 | 82 | 83 | -------------------------------------------------------------------------------- /TestBinding.identcache: -------------------------------------------------------------------------------- 1 | .D:\MyCode\rabbitmq-Delphi\demo\TestBinding.dpr(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas'D:\MyCode\rabbitmq-Delphi\amqp.time.pas-D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas(D:\MyCode\rabbitmq-Delphi\amqp.table.pas&D:\MyCode\rabbitmq-Delphi\amqp.api.pas)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas -------------------------------------------------------------------------------- /TestCreateExchange.dpr: -------------------------------------------------------------------------------- 1 | program TestCreateExchange; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | amqp.api in '..\amqp.api.pas', 10 | amqp.connection in '..\amqp.connection.pas', 11 | amqp.consumer in '..\amqp.consumer.pas', 12 | amqp.framing in '..\amqp.framing.pas', 13 | amqp.mem in '..\amqp.mem.pas', 14 | amqp.privt in '..\amqp.privt.pas', 15 | amqp.socket in '..\amqp.socket.pas', 16 | amqp.table in '..\amqp.table.pas', 17 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 18 | amqp.time in '..\amqp.time.pas', 19 | AMQP.Types in '..\AMQP.Types.pas', 20 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 21 | 22 | {var MyEnum : TMyEnum; 23 | begin 24 | 25 | MyEnum := Two; 26 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 27 | 28 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 29 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 30 | readln; 31 | 32 | end. } 33 | 34 | function main:integer; 35 | var 36 | port, status : integer; 37 | ret : Tamqp_rpc_reply; 38 | socket : Pamqp_socket; 39 | conn : Pamqp_connection_state; 40 | props : Tamqp_basic_properties; 41 | hostname, exchange, exchangetype: PAnsiChar; 42 | vl: Tva_list; 43 | begin 44 | socket := nil; 45 | 46 | hostname := 'localhost'; 47 | port := 5672; 48 | exchange := 'Test.X'; 49 | exchangetype := 'direct'; 50 | 51 | if initializeWinsockIfNecessary() < 1 then 52 | begin 53 | Writeln('Failed to initialize "winsock": '); 54 | Exit; 55 | end; 56 | 57 | conn := amqp_new_connection(); 58 | socket := amqp_tcp_socket_new(conn); 59 | if not Assigned(socket) then begin 60 | Writeln('creating TCP socket failed!'); 61 | Exit; 62 | end; 63 | status := amqp_socket_open(socket, hostname, port); 64 | if status > 0 then begin 65 | Writeln('opening TCP socket failed!'); 66 | Exit; 67 | end; 68 | vl.username := 'sa'; 69 | vl.password := 'admin'; 70 | vl.identity := ''; 71 | ret := amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl); 72 | 73 | if ret.library_error < 0 then 74 | Exit; 75 | 76 | var P := amqp_channel_open(conn, 1); 77 | IF P = nil then 78 | Exit; 79 | var reply := amqp_get_rpc_reply(conn); 80 | if reply.library_error < 0 then 81 | Exit; 82 | 83 | amqp_exchange_declare(conn, 1, amqp_cstring_bytes(exchange), 84 | amqp_cstring_bytes(exchangetype), 0, 0, 0, 0, 85 | amqp_empty_table); 86 | if reply.library_error < 0 then 87 | Exit; 88 | amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS); 89 | amqp_connection_close(conn, AMQP_REPLY_SUCCESS); 90 | amqp_destroy_connection(conn); 91 | Result := 0; 92 | end; 93 | 94 | 95 | begin 96 | try 97 | Main; 98 | except 99 | on e:Exception do 100 | WriteLn(e.Message); 101 | end; 102 | end. 103 | 104 | -------------------------------------------------------------------------------- /TestCreateExchange.dproj.local: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas 5 | 1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas 6 | 1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas 7 | 1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas 8 | 1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 9 | 1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.pas 10 | 1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.mem.pas 11 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.api.pas 12 | 1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas 13 | 1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas 14 | 1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas 15 | 1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas 16 | 1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas 17 | 1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas 18 | 1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas 19 | 1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas 20 | 1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas 21 | 1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas 22 | 1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas 23 | 1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\framing.pas 24 | 1899-12-30 00:00:00.000.615,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas 25 | 1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\Unit2.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 26 | 1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas 27 | 1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas= 28 | 1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas 29 | 1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas= 30 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 31 | 1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas 32 | 1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 33 | 1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Login.pas 34 | 1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.connection.pas 35 | 1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.socket.pas 36 | 1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas 37 | 1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.table.pas 38 | 1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 39 | 1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas= 40 | 1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.time.pas 41 | 1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas= 42 | 1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas 43 | 1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas= 44 | 1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 45 | 1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 46 | 1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas= 47 | 1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas= 48 | 1899-12-30 00:00:00.000.516,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas 49 | 1899-12-30 00:00:00.000.649,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas 50 | 1899-12-30 00:00:00.000.575,D:\MyCode\AMQP-Delphi\TestCreateExchange.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj 51 | 1899-12-30 00:00:00.000.481,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas 52 | 1899-12-30 00:00:00.000.366,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas 53 | 1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas 54 | 1899-12-30 00:00:00.000.394,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas 55 | 1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas= 56 | 1899-12-30 00:00:00.000.297,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas 57 | 1899-12-30 00:00:00.000.577,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas 58 | 1899-12-30 00:00:00.000.326,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas 59 | 1899-12-30 00:00:00.000.266,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas 60 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 61 | 1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas= 62 | 1899-12-30 00:00:00.000.090,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\Project1.dproj 63 | 1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 64 | 1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas 65 | 1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas 66 | 1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas= 67 | 1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas 68 | 1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas 69 | 1899-12-30 00:00:00.000.546,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas 70 | 1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas 71 | 1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas 72 | 1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.framing.pas 73 | 1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 74 | 1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 75 | 1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas= 76 | 1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 77 | 1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas 78 | 1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas 79 | 1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas= 80 | 1899-12-30 00:00:00.000.446,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas 81 | 82 | 83 | -------------------------------------------------------------------------------- /TestCreateExchange.identcache: -------------------------------------------------------------------------------- 1 | -D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas&D:\MyCode\rabbitmq-Delphi\amqp.api.pas+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas'D:\MyCode\rabbitmq-Delphi\amqp.time.pas(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas(D:\MyCode\rabbitmq-Delphi\amqp.table.pas5D:\MyCode\rabbitmq-Delphi\demo\TestCreateExchange.dpr)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas -------------------------------------------------------------------------------- /TestRPCClient.dpr: -------------------------------------------------------------------------------- 1 | program TestRPCClient; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | Net.Winsock2, 10 | amqp.api in '..\amqp.api.pas', 11 | amqp.connection in '..\amqp.connection.pas', 12 | amqp.consumer in '..\amqp.consumer.pas', 13 | amqp.framing in '..\amqp.framing.pas', 14 | amqp.mem in '..\amqp.mem.pas', 15 | amqp.privt in '..\amqp.privt.pas', 16 | amqp.socket in '..\amqp.socket.pas', 17 | amqp.table in '..\amqp.table.pas', 18 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 19 | amqp.time in '..\amqp.time.pas', 20 | AMQP.Types in '..\AMQP.Types.pas', 21 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 22 | 23 | {var MyEnum : TMyEnum; 24 | begin 25 | 26 | MyEnum := Two; 27 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 28 | 29 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 30 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 31 | readln; 32 | 33 | end. } 34 | 35 | function main:integer; 36 | var 37 | port, status : integer; 38 | ret : Tamqp_rpc_reply; 39 | socket : Pamqp_socket; 40 | conn : Pamqp_connection_state; 41 | props : Tamqp_basic_properties; 42 | host: Ansistring; 43 | hostname, exchange, queue, bindkey, messagebody, reply_Q: PAnsiChar; 44 | tval: Ttimeval ; 45 | tv: Ptimeval ; 46 | vl: Tva_list; 47 | frame: Tamqp_frame; 48 | reply_to_queue: Tamqp_bytes; 49 | begin 50 | socket := nil; 51 | 52 | { 53 | if ( ParamCount > 0 ) then 54 | host := ParamStr(1) 55 | else 56 | Exit; } 57 | 58 | hostname := 'localhost'; 59 | port := 5672; 60 | exchange := 'Test.EX'; 61 | queue := 'Test.Q'; 62 | bindkey := 'test-key'; 63 | messagebody := 'hello'; 64 | reply_Q := 'reply.Q'; 65 | if initializeWinsockIfNecessary() < 1 then 66 | begin 67 | Writeln('Failed to initialize "winsock": '); 68 | Exit; 69 | end; 70 | 71 | conn := amqp_new_connection(); 72 | socket := amqp_tcp_socket_new(conn); 73 | if socket = nil then begin 74 | Writeln('creating TCP socket failed!'); 75 | Exit; 76 | end; 77 | 78 | var res := amqp_socket_open(socket, hostname, port); 79 | if res < 0 then 80 | Exit; 81 | 82 | vl.username := 'sa'; 83 | vl.password := 'admin'; 84 | vl.identity := ''; 85 | die_on_amqp_error(amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl), 86 | 'Logging in'); 87 | 88 | 89 | 90 | amqp_channel_open(conn, 1); 91 | die_on_amqp_error(amqp_get_rpc_reply(conn), 'Opening channel'); 92 | 93 | //create private reply_to queue 94 | //var r := amqp_queue_declare(conn, 1, amqp_empty_bytes, 0, 0, 0, 1, amqp_empty_table); 95 | //die_on_amqp_error(amqp_get_rpc_reply(conn), 'Declaring queue'); 96 | 97 | reply_to_queue:= Tamqp_bytes.Create(reply_Q); 98 | 99 | if reply_to_queue.bytes = nil then 100 | begin 101 | Writeln('Out of memory while copying queue name'); 102 | Exit(1); 103 | end; 104 | 105 | { 106 | send the message 107 | } 108 | begin 109 | 110 | //set properties 111 | 112 | props._flags := AMQP_BASIC_CONTENT_TYPE_FLAG or AMQP_BASIC_DELIVERY_MODE_FLAG or 113 | AMQP_BASIC_REPLY_TO_FLAG or AMQP_BASIC_CORRELATION_ID_FLAG; 114 | props.content_type := amqp_cstring_bytes('text/plain'); 115 | props.delivery_mode := 2; { persistent delivery mode } 116 | {$if CompilerVersion < 34} 117 | props.reply_to := @reply_to_queue; 118 | {$ELSE} 119 | props.reply_to := reply_to_queue; 120 | {$ENDIF} 121 | if props.reply_to.bytes = nil then begin 122 | Write('Out of memory while copying queue name'); 123 | Exit(1); 124 | end; 125 | 126 | props.correlation_id := amqp_cstring_bytes('1'); 127 | die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange), 128 | amqp_cstring_bytes(bindkey), 0, 0, 129 | @props, amqp_cstring_bytes(messagebody) 130 | ), 'Publishing'); 131 | 132 | props.reply_to.Destroy; 133 | end; 134 | { 135 | wait an answer 136 | } 137 | begin 138 | 139 | amqp_basic_consume(conn, 1, reply_to_queue, amqp_empty_bytes, 0, 1, 0, 140 | amqp_empty_table); 141 | die_on_amqp_error(amqp_get_rpc_reply(conn), 'Consuming'); 142 | reply_to_queue.Destroy; 143 | 144 | begin 145 | while True do 146 | begin 147 | amqp_maybe_release_buffers(conn); 148 | result := amqp_simple_wait_frame(conn, frame); 149 | writeln(format('Result: %d',[result])); 150 | if result < 0 then begin 151 | break; 152 | end; 153 | writeln(format('Frame type: %u channel: %u',[frame.frame_type, frame.channel])); 154 | if frame.frame_type <> AMQP_FRAME_METHOD then begin 155 | continue; 156 | end; 157 | writeln(format('Method: %s',[amqp_method_name(frame.payload.method.id)])); 158 | if frame.payload.method.id <> AMQP_BASIC_DELIVER_METHOD then begin 159 | continue; 160 | end; 161 | var d := Pamqp_basic_deliver(frame.payload.method.decoded); 162 | Writeln('Delivery: %u exchange: %d %s routingkey: %d %s\n', 163 | d.delivery_tag, d.exchange.len, 164 | PAnsiChar(d.exchange.bytes), d.routing_key.len, 165 | PAnsiChar(d.routing_key.bytes)); 166 | result := amqp_simple_wait_frame(conn, frame); 167 | if result < 0 then begin 168 | break; 169 | end; 170 | if frame.frame_type <> AMQP_FRAME_HEADER then begin 171 | Write('Expected header!'); 172 | abort(); 173 | end; 174 | var p := Pamqp_basic_properties(frame.payload.properties.decoded); 175 | if (p._flags and AMQP_BASIC_CONTENT_TYPE_FLAG) > 0 then begin 176 | Writeln('Content-type: %d %s\n', p.content_type.len, 177 | PAnsiChar(p.content_type.bytes)); 178 | end; 179 | Writeln('----'); 180 | var body_target := size_t(frame.payload.properties.body_size); 181 | var body_received := 0; 182 | while body_received < body_target do 183 | begin 184 | result := amqp_simple_wait_frame(conn, frame); 185 | if result < 0 then 186 | break; 187 | 188 | if frame.frame_type <> AMQP_FRAME_BODY then 189 | begin 190 | Write('Expected body!'); 191 | abort(); 192 | end; 193 | body_received := body_received + frame.payload.body_fragment.len; 194 | assert(body_received <= body_target); 195 | amqp_dump(frame.payload.body_fragment.bytes, 196 | frame.payload.body_fragment.len); 197 | end; 198 | if body_received <> body_target then 199 | { Can only happen when amqp_simple_wait_frame returns <= 0 } 200 | { We break here to close the connection } 201 | break; 202 | 203 | { everything was fine, we can quit now because we received the reply } 204 | break; 205 | end; 206 | end; 207 | end; 208 | 209 | die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), 210 | 'Closing channel'); 211 | die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS), 212 | 'Closing connection'); 213 | die_on_error(amqp_destroy_connection(conn), 'Ending connection'); 214 | 215 | end; 216 | 217 | 218 | begin 219 | try 220 | Main; 221 | except 222 | on e:Exception do 223 | WriteLn(e.Message); 224 | end; 225 | end. 226 | 227 | -------------------------------------------------------------------------------- /TestRPCClient.dproj.local: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas 5 | 1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas 6 | 1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Field.pas 7 | 1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas 8 | 1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas 9 | 1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas 10 | 1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas 11 | 1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas 12 | 1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas 13 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas 14 | 1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas 15 | 1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas 16 | 1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas 17 | 1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas 18 | 1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas 19 | 1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas 20 | 1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas 21 | 1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas 22 | 1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas 23 | 1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas 24 | 1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas= 25 | 1899-12-30 00:00:00.000.385,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas 26 | 1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit2.pas 27 | 1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas 28 | 1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas= 29 | 1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas 30 | 1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas= 31 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\amqp.api.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 32 | 1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas 33 | 1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 34 | 1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas 35 | 1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas 36 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas 37 | 1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas 38 | 1899-12-30 00:00:00.000.382,=D:\MyCode\AMQP-Delphi\Unit1.pas 39 | 1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 40 | 1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas= 41 | 1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas 42 | 1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas 43 | 1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas 44 | 1899-12-30 00:00:00.000.053,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas 45 | 1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\amqp.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 46 | 1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\amqp.mem.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 47 | 1899-12-30 00:00:00.000.113,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas 48 | 1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas= 49 | 1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas= 50 | 1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\amqp.framing.pas=D:\MyCode\AMQP-Delphi\framing.pas 51 | 1899-12-30 00:00:00.000.044,D:\MyCode\AMQP-Delphi\amqp.consumer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 52 | 1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\amqp.socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 53 | 1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas 54 | 1899-12-30 00:00:00.000.083,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas 55 | 1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 56 | 1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 57 | 1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas= 58 | 1899-12-30 00:00:00.000.185,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas 59 | 1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas= 60 | 1899-12-30 00:00:00.000.346,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas 61 | 1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\amqp.connection.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 62 | 1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\amqp.table.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 63 | 1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas= 64 | 1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas 65 | 1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas 66 | 1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas 67 | 1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas 68 | 1899-12-30 00:00:00.000.184,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\AMQP-Delphi\TestRPCClient.dproj 69 | 1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas= 70 | 1899-12-30 00:00:00.000.314,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas 71 | 1899-12-30 00:00:00.000.090,D:\MyCode\Project1.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj 72 | 1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\amqp.time.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 73 | 1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas 74 | 1899-12-30 00:00:00.000.283,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas 75 | 1899-12-30 00:00:00.000.416,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas 76 | 1899-12-30 00:00:00.000.155,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas 77 | 1899-12-30 00:00:00.000.253,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas 78 | 1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas= 79 | 1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas= 80 | 1899-12-30 00:00:00.000.218,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas 81 | 1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 82 | 1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 83 | 84 | 85 | -------------------------------------------------------------------------------- /TestRPCClient.identcache: -------------------------------------------------------------------------------- 1 | -D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas0D:\MyCode\rabbitmq-Delphi\demo\TestRPCClient.dpr+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas'D:\MyCode\rabbitmq-Delphi\amqp.time.pas(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas(D:\MyCode\rabbitmq-Delphi\amqp.table.pas&D:\MyCode\rabbitmq-Delphi\amqp.api.pas)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas -------------------------------------------------------------------------------- /TestRPCClient.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/TestRPCClient.res -------------------------------------------------------------------------------- /TestRpcServer.dpr: -------------------------------------------------------------------------------- 1 | program TestRpcServer; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | {$APPTYPE CONSOLE} 8 | 9 | {$R *.res} 10 | 11 | uses 12 | {$IFNDEF FPC} 13 | System.SysUtils, 14 | Net.Winsock2, 15 | {$else} 16 | winsock2, SysUtils, 17 | {$ENDIF} 18 | 19 | 20 | amqp.connection, 21 | amqp.framing, 22 | AMQP.Types, 23 | amqp.time, 24 | amqp.socket, 25 | amqp.privt, 26 | amqp.table, 27 | amqp.mem, 28 | amqp.tcp_socket, 29 | amqp.api, 30 | amqp.consumer; 31 | 32 | {var MyEnum : TMyEnum; 33 | begin 34 | 35 | MyEnum := Two; 36 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 37 | 38 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 39 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 40 | readln; 41 | 42 | end. } 43 | 44 | function main:integer; 45 | var 46 | port, status : integer; 47 | ret : Tamqp_rpc_reply; 48 | socket : Pamqp_socket; 49 | conn : Pamqp_connection_state; 50 | props : Tamqp_basic_properties; 51 | host: Ansistring; 52 | hostname, exchange, queue, routingkey, messagebody: PAnsiChar; 53 | tval: Ttimeval ; 54 | tv: Ptimeval ; 55 | vl: Tva_list; 56 | frame: Tamqp_frame; 57 | recv_queue: Tamqp_bytes; 58 | envelope: Tamqp_envelope; 59 | s: string; 60 | res: int; 61 | reply_props :Tamqp_basic_properties; 62 | replyQ : Pansichar; 63 | begin 64 | socket := nil; 65 | 66 | { 67 | if ( ParamCount > 0 ) then 68 | host := ParamStr(1) 69 | else 70 | Exit; } 71 | 72 | hostname := 'localhost'; 73 | port := 5672; 74 | exchange := 'Test.EX'; 75 | queue := 'Test.Q'; 76 | routingkey := 'test-key'; 77 | messagebody := 'Hello RpcClient, I''v received your message!'; 78 | 79 | 80 | if initializeWinsockIfNecessary() < 1 then 81 | begin 82 | Writeln('Failed to initialize "winsock": '); 83 | Exit; 84 | end; 85 | 86 | 87 | conn := amqp_new_connection(); 88 | socket := amqp_tcp_socket_new(conn); 89 | if socket = nil then begin 90 | Writeln('creating TCP socket failed!'); 91 | 92 | Exit; 93 | end; 94 | 95 | res := socket.open( hostname, port); 96 | if res < 0 then 97 | Exit; 98 | 99 | vl.username := 'sa'; 100 | vl.password := 'admin'; 101 | vl.identity := ''; 102 | die_on_amqp_error(amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl), 103 | 'Logging in'); 104 | 105 | 106 | 107 | amqp_channel_open(conn, 1); 108 | die_on_amqp_error(amqp_get_rpc_reply(conn), 'Opening channel'); 109 | 110 | recv_queue := Tamqp_bytes.Create(queue); 111 | amqp_basic_consume(conn, 1, recv_queue, amqp_empty_bytes, 0, 1, 0, 112 | amqp_empty_table); 113 | 114 | die_on_amqp_error(amqp_get_rpc_reply(conn), 'Consuming'); 115 | { 116 | Get MSG 117 | 3. 获取消息的具体内容 118 | } 119 | begin 120 | while True do 121 | begin 122 | amqp_maybe_release_buffers(conn); 123 | ret := amqp_consume_message(conn, envelope, nil, 0); 124 | if AMQP_RESPONSE_NORMAL <> ret.reply_type then begin 125 | break; 126 | end; 127 | 128 | s := Format('Delivery %u, exchange %.*s routingkey %.*s\n', 129 | [envelope.delivery_tag, envelope.exchange.len, 130 | Pansichar(envelope.exchange.bytes), envelope.routing_key.len, 131 | PAnsiChar(envelope.routing_key.bytes)]); 132 | Writeln(s); 133 | Writeln('**************************************************************'); 134 | amqp_dump(envelope.message.body.bytes, envelope.message.body.len); 135 | { 136 | 4. 此处为作者个人修改部分 137 | 因为在发送的时候初始化props为0, 则如果不是一个RPC的消息类型,则此处的reply_to的长度应该是0,否则,不为0 138 | } 139 | if 0 <> envelope.message.properties.reply_to.len then 140 | begin 141 | Writeln('there is a RPC reply'); 142 | 143 | 144 | reply_props._flags := AMQP_BASIC_CONTENT_TYPE_FLAG or AMQP_BASIC_DELIVERY_MODE_FLAG; 145 | reply_props.content_type := amqp_cstring_bytes('text/plain'); 146 | reply_props.delivery_mode := 2; { persistent delivery mode } 147 | reply_props.correlation_id := envelope.message.properties.correlation_id; 148 | { 149 | 5. 重点需要照顾的部分 150 | 此处EXCHANGE_NAME也就是交换机的名称为空,如果填写了上面接收使用的名称,rpc client端将不会收到,或者使用其他的名称也不行 151 | 在原本需要写入ROUTE_KEY的部分则需要填入接收到的reply_to信息,只有当这两部分都填写正确rpc client才会收到回复的消息 152 | } 153 | replyQ := PAnsiChar(envelope.message.properties.reply_to.bytes); 154 | die_on_error(amqp_basic_publish(conn, 1, amqp_cstring_bytes(''), 155 | amqp_cstring_bytes(replyQ), 0, 0, 156 | @reply_props, amqp_cstring_bytes(messagebody)), 157 | 'Publishing'); 158 | end; 159 | envelope.destroy; 160 | end; 161 | end; 162 | 163 | die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), 164 | 'Closing channel'); 165 | die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS), 166 | 'Closing connection'); 167 | die_on_error(amqp_destroy_connection(conn), 'Ending connection'); 168 | 169 | end; 170 | 171 | begin 172 | try 173 | Main; 174 | except 175 | on e:Exception do 176 | WriteLn(e.Message); 177 | end; 178 | end. 179 | 180 | 181 | -------------------------------------------------------------------------------- /TestRpcServer.dproj.local: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 1899-12-30 00:00:00.000.382,=D:\MyCode\AMQP-Delphi\Unit1.pas 5 | 1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.time.pas 6 | 1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.mem.pas 7 | 1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.table.pas 8 | 1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas 9 | 1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas 10 | 1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas 11 | 1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas 12 | 1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.socket.pas 13 | 1899-12-30 00:00:00.000.044,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.consumer.pas 14 | 1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas 15 | 1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas 16 | 1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.connection.pas 17 | 1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Login.pas 18 | 1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.pas 19 | 1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas 20 | 1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 21 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 22 | 1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas= 23 | 1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 24 | 1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas= 25 | 1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas 26 | 1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\framing.pas 27 | 1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas 28 | 1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas= 29 | 1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas= 30 | 1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 31 | 1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas= 32 | 1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 33 | 1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas 34 | 1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas= 35 | 1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas= 36 | 1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\Unit2.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 37 | 1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas 38 | 1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas 39 | 1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas 40 | 1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas 41 | 1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas 42 | 1899-12-30 00:00:00.000.090,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\Project1.dproj 43 | 1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 44 | 1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas 45 | 1899-12-30 00:00:00.000.431,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\AMQP-Delphi\TestRpcServer.dproj 46 | 1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas= 47 | 1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.framing.pas 48 | 1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas= 49 | 1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 50 | 1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas= 51 | 1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas 52 | 1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 53 | 1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas 54 | 1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas= 55 | 1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas 56 | 1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas 57 | 1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas 58 | 1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas 59 | 1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas 60 | 1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas 61 | 1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.api.pas 62 | 1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas 63 | 1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas 64 | 1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas 65 | 1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas 66 | 1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas= 67 | 1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas 68 | 1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas 69 | 1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas 70 | 1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas 71 | 72 | 73 | -------------------------------------------------------------------------------- /TestRpcServer.identcache: -------------------------------------------------------------------------------- 1 | 0D:\MyCode\rabbitmq-Delphi\demo\TestRpcServer.dpr -------------------------------------------------------------------------------- /TestRpcServer.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <UseAppBundle Value="False"/> 17 | <ResourceType Value="res"/> 18 | </General> 19 | <BuildModes Count="1"> 20 | <Item1 Name="Default" Default="True"/> 21 | </BuildModes> 22 | <PublishOptions> 23 | <Version Value="2"/> 24 | <UseFileFilters Value="True"/> 25 | </PublishOptions> 26 | <RunParams> 27 | <FormatVersion Value="2"/> 28 | <Modes Count="0"/> 29 | </RunParams> 30 | <RequiredPackages Count="1"> 31 | <Item1> 32 | <PackageName Value="LCL"/> 33 | </Item1> 34 | </RequiredPackages> 35 | <Units Count="14"> 36 | <Unit0> 37 | <Filename Value="TestRpcServer.dpr"/> 38 | <IsPartOfProject Value="True"/> 39 | </Unit0> 40 | <Unit1> 41 | <Filename Value="amqp.connection.pas"/> 42 | <IsPartOfProject Value="True"/> 43 | </Unit1> 44 | <Unit2> 45 | <Filename Value="amqp.framing.pas"/> 46 | <IsPartOfProject Value="True"/> 47 | </Unit2> 48 | <Unit3> 49 | <Filename Value="AMQP.Types.pas"/> 50 | <IsPartOfProject Value="True"/> 51 | </Unit3> 52 | <Unit4> 53 | <Filename Value="amqp.time.pas"/> 54 | <IsPartOfProject Value="True"/> 55 | </Unit4> 56 | <Unit5> 57 | <Filename Value="amqp.socket.pas"/> 58 | <IsPartOfProject Value="True"/> 59 | </Unit5> 60 | <Unit6> 61 | <Filename Value="amqp.privt.pas"/> 62 | <IsPartOfProject Value="True"/> 63 | </Unit6> 64 | <Unit7> 65 | <Filename Value="amqp.table.pas"/> 66 | <IsPartOfProject Value="True"/> 67 | </Unit7> 68 | <Unit8> 69 | <Filename Value="amqp.mem.pas"/> 70 | <IsPartOfProject Value="True"/> 71 | </Unit8> 72 | <Unit9> 73 | <Filename Value="amqp.tcp_socket.pas"/> 74 | <IsPartOfProject Value="True"/> 75 | </Unit9> 76 | <Unit10> 77 | <Filename Value="amqp.api.pas"/> 78 | <IsPartOfProject Value="True"/> 79 | </Unit10> 80 | <Unit11> 81 | <Filename Value="MyFunc.pas"/> 82 | <IsPartOfProject Value="True"/> 83 | </Unit11> 84 | <Unit12> 85 | <Filename Value="amqp.consumer.pas"/> 86 | <IsPartOfProject Value="True"/> 87 | </Unit12> 88 | <Unit13> 89 | <Filename Value="D:\MyVCL\Delphi-Cross-Socket-master\Net\Net.Winsock2.pas"/> 90 | <IsPartOfProject Value="True"/> 91 | </Unit13> 92 | </Units> 93 | </ProjectOptions> 94 | <CompilerOptions> 95 | <Version Value="11"/> 96 | <PathDelim Value="\"/> 97 | <SearchPaths> 98 | <IncludeFiles Value="D:\MyVCL\Delphi-Cross-Socket-master\Net\;$(ProjOutDir)"/> 99 | <OtherUnitFiles Value="D:\MyVCL\Delphi-Cross-Socket-master\Net\"/> 100 | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> 101 | </SearchPaths> 102 | <Parsing> 103 | <SyntaxOptions> 104 | <SyntaxMode Value="Delphi"/> 105 | </SyntaxOptions> 106 | </Parsing> 107 | <Other> 108 | <CustomOptions Value="-dBorland -dVer150 -dDelphi7 -dCompiler6_Up -dPUREPASCAL"/> 109 | </Other> 110 | </CompilerOptions> 111 | <Debugging> 112 | <Exceptions Count="3"> 113 | <Item1> 114 | <Name Value="EAbort"/> 115 | </Item1> 116 | <Item2> 117 | <Name Value="ECodetoolError"/> 118 | </Item2> 119 | <Item3> 120 | <Name Value="EFOpenError"/> 121 | </Item3> 122 | </Exceptions> 123 | </Debugging> 124 | </CONFIG> 125 | -------------------------------------------------------------------------------- /TestRpcServer.lps: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <CONFIG> 3 | <ProjectSession> 4 | <PathDelim Value="\"/> 5 | <Version Value="11"/> 6 | <BuildModes Active="Default"/> 7 | <Units Count="22"> 8 | <Unit0> 9 | <Filename Value="TestRpcServer.dpr"/> 10 | <IsPartOfProject Value="True"/> 11 | <IsVisibleTab Value="True"/> 12 | <TopLine Value="108"/> 13 | <CursorPos X="45" Y="111"/> 14 | <UsageCount Value="72"/> 15 | <Loaded Value="True"/> 16 | <DefaultSyntaxHighlighter Value="Delphi"/> 17 | </Unit0> 18 | <Unit1> 19 | <Filename Value="amqp.connection.pas"/> 20 | <IsPartOfProject Value="True"/> 21 | <EditorIndex Value="1"/> 22 | <TopLine Value="324"/> 23 | <CursorPos Y="331"/> 24 | <UsageCount Value="72"/> 25 | <Loaded Value="True"/> 26 | <DefaultSyntaxHighlighter Value="Delphi"/> 27 | </Unit1> 28 | <Unit2> 29 | <Filename Value="amqp.framing.pas"/> 30 | <IsPartOfProject Value="True"/> 31 | <EditorIndex Value="-1"/> 32 | <UsageCount Value="72"/> 33 | <DefaultSyntaxHighlighter Value="Delphi"/> 34 | </Unit2> 35 | <Unit3> 36 | <Filename Value="AMQP.Types.pas"/> 37 | <IsPartOfProject Value="True"/> 38 | <EditorIndex Value="9"/> 39 | <TopLine Value="1729"/> 40 | <CursorPos Y="1737"/> 41 | <UsageCount Value="72"/> 42 | <Loaded Value="True"/> 43 | <DefaultSyntaxHighlighter Value="Delphi"/> 44 | </Unit3> 45 | <Unit4> 46 | <Filename Value="amqp.time.pas"/> 47 | <IsPartOfProject Value="True"/> 48 | <EditorIndex Value="2"/> 49 | <TopLine Value="96"/> 50 | <CursorPos Y="103"/> 51 | <UsageCount Value="72"/> 52 | <Loaded Value="True"/> 53 | <DefaultSyntaxHighlighter Value="Delphi"/> 54 | </Unit4> 55 | <Unit5> 56 | <Filename Value="amqp.socket.pas"/> 57 | <IsPartOfProject Value="True"/> 58 | <EditorIndex Value="4"/> 59 | <TopLine Value="747"/> 60 | <CursorPos Y="755"/> 61 | <UsageCount Value="72"/> 62 | <Loaded Value="True"/> 63 | <DefaultSyntaxHighlighter Value="Delphi"/> 64 | </Unit5> 65 | <Unit6> 66 | <Filename Value="amqp.privt.pas"/> 67 | <IsPartOfProject Value="True"/> 68 | <EditorIndex Value="-1"/> 69 | <UsageCount Value="72"/> 70 | <DefaultSyntaxHighlighter Value="Delphi"/> 71 | </Unit6> 72 | <Unit7> 73 | <Filename Value="amqp.table.pas"/> 74 | <IsPartOfProject Value="True"/> 75 | <EditorIndex Value="-1"/> 76 | <UsageCount Value="72"/> 77 | <DefaultSyntaxHighlighter Value="Delphi"/> 78 | </Unit7> 79 | <Unit8> 80 | <Filename Value="amqp.mem.pas"/> 81 | <IsPartOfProject Value="True"/> 82 | <EditorIndex Value="8"/> 83 | <CursorPos X="39" Y="5"/> 84 | <UsageCount Value="72"/> 85 | <Loaded Value="True"/> 86 | <DefaultSyntaxHighlighter Value="Delphi"/> 87 | </Unit8> 88 | <Unit9> 89 | <Filename Value="amqp.tcp_socket.pas"/> 90 | <IsPartOfProject Value="True"/> 91 | <EditorIndex Value="3"/> 92 | <TopLine Value="235"/> 93 | <CursorPos X="37" Y="239"/> 94 | <UsageCount Value="72"/> 95 | <Loaded Value="True"/> 96 | <DefaultSyntaxHighlighter Value="Delphi"/> 97 | </Unit9> 98 | <Unit10> 99 | <Filename Value="amqp.api.pas"/> 100 | <IsPartOfProject Value="True"/> 101 | <EditorIndex Value="-1"/> 102 | <UsageCount Value="72"/> 103 | <DefaultSyntaxHighlighter Value="Delphi"/> 104 | </Unit10> 105 | <Unit11> 106 | <Filename Value="MyFunc.pas"/> 107 | <IsPartOfProject Value="True"/> 108 | <EditorIndex Value="-1"/> 109 | <TopLine Value="258"/> 110 | <CursorPos X="33" Y="39"/> 111 | <UsageCount Value="72"/> 112 | <DefaultSyntaxHighlighter Value="Delphi"/> 113 | </Unit11> 114 | <Unit12> 115 | <Filename Value="amqp.consumer.pas"/> 116 | <IsPartOfProject Value="True"/> 117 | <EditorIndex Value="-1"/> 118 | <TopLine Value="165"/> 119 | <CursorPos X="84" Y="202"/> 120 | <UsageCount Value="72"/> 121 | <DefaultSyntaxHighlighter Value="Delphi"/> 122 | </Unit12> 123 | <Unit13> 124 | <Filename Value="D:\MyVCL\Delphi-Cross-Socket-master\Net\Net.Winsock2.pas"/> 125 | <IsPartOfProject Value="True"/> 126 | <EditorIndex Value="-1"/> 127 | <TopLine Value="177"/> 128 | <CursorPos X="4" Y="186"/> 129 | <UsageCount Value="72"/> 130 | <DefaultSyntaxHighlighter Value="Delphi"/> 131 | </Unit13> 132 | <Unit14> 133 | <Filename Value="D:\MyVCL\Delphi-Cross-Socket-master\Net\Net.Winsock.inc"/> 134 | <EditorIndex Value="-1"/> 135 | <TopLine Value="206"/> 136 | <CursorPos Y="223"/> 137 | <UsageCount Value="4"/> 138 | <DefaultSyntaxHighlighter Value="Delphi"/> 139 | </Unit14> 140 | <Unit15> 141 | <Filename Value="E:\lazarus\fpc\3.2.0\source\packages\rtl-extra\src\win\winsock2.pp"/> 142 | <UnitName Value="WinSock2"/> 143 | <EditorIndex Value="5"/> 144 | <TopLine Value="1482"/> 145 | <UsageCount Value="24"/> 146 | <Loaded Value="True"/> 147 | </Unit15> 148 | <Unit16> 149 | <Filename Value="C:\Users\Administrator\AppData\Local\lazarus\onlinepackagemanager\packages\Indy10\System\IdWship6.pas"/> 150 | <EditorIndex Value="-1"/> 151 | <TopLine Value="1430"/> 152 | <CursorPos X="33" Y="1430"/> 153 | <UsageCount Value="6"/> 154 | <DefaultSyntaxHighlighter Value="Delphi"/> 155 | </Unit16> 156 | <Unit17> 157 | <Filename Value="E:\lazarus\fpc\3.2.0\source\rtl\netwlibc\system.pp"/> 158 | <UnitName Value="System"/> 159 | <EditorIndex Value="-1"/> 160 | <TopLine Value="22"/> 161 | <CursorPos X="44" Y="34"/> 162 | <UsageCount Value="7"/> 163 | </Unit17> 164 | <Unit18> 165 | <Filename Value="E:\lazarus\fpc\3.2.0\source\rtl\netware\system.pp"/> 166 | <UnitName Value="System"/> 167 | <EditorIndex Value="-1"/> 168 | <TopLine Value="26"/> 169 | <CursorPos X="33" Y="37"/> 170 | <UsageCount Value="5"/> 171 | </Unit18> 172 | <Unit19> 173 | <Filename Value="E:\lazarus\fpc\3.2.0\source\packages\winunits-jedi\src\jwawinsock2.pas"/> 174 | <UnitName Value="JwaWinsock2"/> 175 | <EditorIndex Value="7"/> 176 | <CursorPos X="49" Y="798"/> 177 | <UsageCount Value="25"/> 178 | <Loaded Value="True"/> 179 | </Unit19> 180 | <Unit20> 181 | <Filename Value="E:\lazarus\fpc\3.2.0\source\packages\winunits-jedi\src\jwaws2tcpip.pas"/> 182 | <UnitName Value="JwaWS2tcpip"/> 183 | <EditorIndex Value="6"/> 184 | <TopLine Value="461"/> 185 | <CursorPos X="5" Y="471"/> 186 | <UsageCount Value="24"/> 187 | <Loaded Value="True"/> 188 | </Unit20> 189 | <Unit21> 190 | <Filename Value="C:\Users\Administrator\AppData\Local\lazarus\onlinepackagemanager\packages\Indy10\System\IdWinsock2.pas"/> 191 | <EditorIndex Value="-1"/> 192 | <TopLine Value="6072"/> 193 | <CursorPos Y="6080"/> 194 | <UsageCount Value="10"/> 195 | <DefaultSyntaxHighlighter Value="Delphi"/> 196 | </Unit21> 197 | </Units> 198 | <JumpHistory Count="30" HistoryIndex="29"> 199 | <Position1> 200 | <Filename Value="amqp.socket.pas"/> 201 | <Caret Line="22" Column="3" TopLine="13"/> 202 | </Position1> 203 | <Position2> 204 | <Filename Value="amqp.socket.pas"/> 205 | <Caret Line="36" Column="24" TopLine="13"/> 206 | </Position2> 207 | <Position3> 208 | <Filename Value="amqp.socket.pas"/> 209 | <Caret Line="1265" Column="36"/> 210 | </Position3> 211 | <Position4> 212 | <Filename Value="amqp.socket.pas"/> 213 | <Caret Line="38" Column="107" TopLine="19"/> 214 | </Position4> 215 | <Position5> 216 | <Filename Value="amqp.socket.pas"/> 217 | <Caret Line="1289" Column="42" TopLine="1278"/> 218 | </Position5> 219 | <Position6> 220 | <Filename Value="amqp.socket.pas"/> 221 | <Caret Line="1166" TopLine="1159"/> 222 | </Position6> 223 | <Position7> 224 | <Filename Value="TestRpcServer.dpr"/> 225 | <Caret Line="95" TopLine="88"/> 226 | </Position7> 227 | <Position8> 228 | <Filename Value="amqp.socket.pas"/> 229 | <Caret Line="1144" TopLine="1140"/> 230 | </Position8> 231 | <Position9> 232 | <Filename Value="amqp.socket.pas"/> 233 | <Caret Line="1166" TopLine="1159"/> 234 | </Position9> 235 | <Position10> 236 | <Filename Value="TestRpcServer.dpr"/> 237 | <Caret Line="95" TopLine="88"/> 238 | </Position10> 239 | <Position11> 240 | <Filename Value="amqp.socket.pas"/> 241 | <Caret Line="483" TopLine="476"/> 242 | </Position11> 243 | <Position12> 244 | <Filename Value="AMQP.Types.pas"/> 245 | <Caret Line="1737" TopLine="1729"/> 246 | </Position12> 247 | <Position13> 248 | <Filename Value="amqp.tcp_socket.pas"/> 249 | <Caret Line="238" TopLine="235"/> 250 | </Position13> 251 | <Position14> 252 | <Filename Value="amqp.socket.pas"/> 253 | <Caret Line="1102" Column="25" TopLine="1098"/> 254 | </Position14> 255 | <Position15> 256 | <Filename Value="TestRpcServer.dpr"/> 257 | <Caret Line="95" TopLine="88"/> 258 | </Position15> 259 | <Position16> 260 | <Filename Value="amqp.socket.pas"/> 261 | <Caret Line="482" TopLine="476"/> 262 | </Position16> 263 | <Position17> 264 | <Filename Value="AMQP.Types.pas"/> 265 | <Caret Line="1737" TopLine="1729"/> 266 | </Position17> 267 | <Position18> 268 | <Filename Value="TestRpcServer.dpr"/> 269 | <Caret Line="102" TopLine="97"/> 270 | </Position18> 271 | <Position19> 272 | <Filename Value="amqp.socket.pas"/> 273 | <Caret Line="227" TopLine="219"/> 274 | </Position19> 275 | <Position20> 276 | <Filename Value="TestRpcServer.dpr"/> 277 | <Caret Line="103" TopLine="97"/> 278 | </Position20> 279 | <Position21> 280 | <Filename Value="TestRpcServer.dpr"/> 281 | <Caret Line="102" TopLine="97"/> 282 | </Position21> 283 | <Position22> 284 | <Filename Value="TestRpcServer.dpr"/> 285 | <Caret Line="107" TopLine="97"/> 286 | </Position22> 287 | <Position23> 288 | <Filename Value="TestRpcServer.dpr"/> 289 | <Caret Line="108" TopLine="97"/> 290 | </Position23> 291 | <Position24> 292 | <Filename Value="amqp.socket.pas"/> 293 | <Caret Line="755" TopLine="747"/> 294 | </Position24> 295 | <Position25> 296 | <Filename Value="TestRpcServer.dpr"/> 297 | <Caret Line="110" TopLine="98"/> 298 | </Position25> 299 | <Position26> 300 | <Filename Value="TestRpcServer.dpr"/> 301 | <Caret Line="111" TopLine="99"/> 302 | </Position26> 303 | <Position27> 304 | <Filename Value="TestRpcServer.dpr"/> 305 | <Caret Line="114" TopLine="107"/> 306 | </Position27> 307 | <Position28> 308 | <Filename Value="amqp.socket.pas"/> 309 | <Caret Line="755" TopLine="747"/> 310 | </Position28> 311 | <Position29> 312 | <Filename Value="TestRpcServer.dpr"/> 313 | <Caret Line="122" TopLine="115"/> 314 | </Position29> 315 | <Position30> 316 | <Filename Value="TestRpcServer.dpr"/> 317 | <Caret Line="120" Column="41" TopLine="120"/> 318 | </Position30> 319 | </JumpHistory> 320 | <RunParams> 321 | <FormatVersion Value="2"/> 322 | <Modes Count="0" ActiveMode=""/> 323 | </RunParams> 324 | </ProjectSession> 325 | <Debugging> 326 | <BreakPoints Count="1"> 327 | <Item1> 328 | <Kind Value="bpkSource"/> 329 | <WatchScope Value="wpsLocal"/> 330 | <WatchKind Value="wpkWrite"/> 331 | <Source Value="amqp.socket.pas"/> 332 | <Line Value="1263"/> 333 | </Item1> 334 | </BreakPoints> 335 | </Debugging> 336 | </CONFIG> 337 | -------------------------------------------------------------------------------- /TestRpcServer.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/TestRpcServer.res -------------------------------------------------------------------------------- /TestSendString.dpr: -------------------------------------------------------------------------------- 1 | program TestSendString; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | amqp.api in '..\amqp.api.pas', 10 | amqp.connection in '..\amqp.connection.pas', 11 | amqp.consumer in '..\amqp.consumer.pas', 12 | amqp.framing in '..\amqp.framing.pas', 13 | amqp.mem in '..\amqp.mem.pas', 14 | amqp.privt in '..\amqp.privt.pas', 15 | amqp.socket in '..\amqp.socket.pas', 16 | amqp.table in '..\amqp.table.pas', 17 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 18 | amqp.time in '..\amqp.time.pas', 19 | AMQP.Types in '..\AMQP.Types.pas', 20 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 21 | 22 | {var MyEnum : TMyEnum; 23 | begin 24 | 25 | MyEnum := Two; 26 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 27 | 28 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 29 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 30 | readln; 31 | 32 | end. } 33 | 34 | function main:integer; 35 | var 36 | port, status : integer; 37 | ret : Tamqp_rpc_reply; 38 | socket : Pamqp_socket; 39 | conn : Pamqp_connection_state; 40 | props : Tamqp_basic_properties; 41 | hostname, routingkey, exchange, messagebody: PAnsiChar; 42 | vl: Tva_list; 43 | begin 44 | socket := nil; 45 | 46 | hostname := 'localhost'; 47 | port := 5672; 48 | exchange := 'Test.EX'; 49 | routingkey := 'test-key'; 50 | messagebody := 'Hello, World!'; 51 | 52 | if initializeWinsockIfNecessary() < 1 then 53 | begin 54 | Writeln('Failed to initialize "winsock": '); 55 | Exit; 56 | end; 57 | 58 | conn := amqp_new_connection(); 59 | socket := amqp_tcp_socket_new(conn); 60 | if not Assigned(socket) then begin 61 | Writeln('creating TCP socket failed!'); 62 | Exit; 63 | end; 64 | status := amqp_socket_open(socket, hostname, port); 65 | if status > 0 then begin 66 | Writeln('opening TCP socket failed!'); 67 | Exit; 68 | end; 69 | vl.username := 'sa'; 70 | vl.password := 'admin'; 71 | vl.identity := ''; 72 | die_on_amqp_error(amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl), 73 | 'Logging in'); 74 | 75 | amqp_channel_open(conn, 1); 76 | die_on_amqp_error(amqp_get_rpc_reply(conn), 'Opening channel'); 77 | 78 | begin 79 | props._flags := AMQP_BASIC_CONTENT_TYPE_FLAG or AMQP_BASIC_DELIVERY_MODE_FLAG; 80 | props.content_type := amqp_cstring_bytes('text/plain'); 81 | props.delivery_mode := 2; { persistent delivery mode } 82 | amqp_basic_publish(conn, 1, amqp_cstring_bytes(exchange), 83 | amqp_cstring_bytes(routingkey), 0, 0, 84 | @props, amqp_cstring_bytes(messagebody)); 85 | end; 86 | die_on_amqp_error(amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS), 87 | 'Closing channel'); 88 | die_on_amqp_error(amqp_connection_close(conn, AMQP_REPLY_SUCCESS), 89 | 'Closing connection'); 90 | die_on_error(amqp_destroy_connection(conn), 'Ending connection'); 91 | end; 92 | 93 | 94 | begin 95 | try 96 | Main; 97 | except 98 | on e:Exception do 99 | WriteLn(e.Message); 100 | end; 101 | end. 102 | 103 | -------------------------------------------------------------------------------- /TestSendString.dproj.local: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <BorlandProject> 3 | <Transactions> 4 | <Transaction>1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 5 | <Transaction>1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 6 | <Transaction>1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Field.pas</Transaction> 7 | <Transaction>1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 8 | <Transaction>1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 9 | <Transaction>1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 10 | <Transaction>1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas</Transaction> 11 | <Transaction>1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 12 | <Transaction>1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas</Transaction> 13 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas</Transaction> 14 | <Transaction>1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 15 | <Transaction>1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 16 | <Transaction>1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 17 | <Transaction>1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 18 | <Transaction>1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 19 | <Transaction>1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 20 | <Transaction>1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 21 | <Transaction>1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 22 | <Transaction>1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 23 | <Transaction>1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=</Transaction> 24 | <Transaction>1899-12-30 00:00:00.000.847,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas</Transaction> 25 | <Transaction>1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit2.pas</Transaction> 26 | <Transaction>1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas</Transaction> 27 | <Transaction>1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=</Transaction> 28 | <Transaction>1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas=</Transaction> 29 | <Transaction>1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 30 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\amqp.api.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 31 | <Transaction>1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 32 | <Transaction>1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 33 | <Transaction>1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas</Transaction> 34 | <Transaction>1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas</Transaction> 35 | <Transaction>1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas</Transaction> 36 | <Transaction>1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Types.pas</Transaction> 37 | <Transaction>1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas</Transaction> 38 | <Transaction>1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 39 | <Transaction>1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=</Transaction> 40 | <Transaction>1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 41 | <Transaction>1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 42 | <Transaction>1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 43 | <Transaction>1899-12-30 00:00:00.000.479,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas</Transaction> 44 | <Transaction>1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=</Transaction> 45 | <Transaction>1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\amqp.mem.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 46 | <Transaction>1899-12-30 00:00:00.000.544,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas</Transaction> 47 | <Transaction>1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\amqp.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 48 | <Transaction>1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\amqp.framing.pas=D:\MyCode\AMQP-Delphi\framing.pas</Transaction> 49 | <Transaction>1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=</Transaction> 50 | <Transaction>1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas=</Transaction> 51 | <Transaction>1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\amqp.socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 52 | <Transaction>1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas</Transaction> 53 | <Transaction>1899-12-30 00:00:00.000.513,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas</Transaction> 54 | <Transaction>1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 55 | <Transaction>1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 56 | <Transaction>1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=</Transaction> 57 | <Transaction>1899-12-30 00:00:00.000.618,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas</Transaction> 58 | <Transaction>1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=</Transaction> 59 | <Transaction>1899-12-30 00:00:00.000.807,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas</Transaction> 60 | <Transaction>1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\amqp.connection.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 61 | <Transaction>1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\amqp.table.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 62 | <Transaction>1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas</Transaction> 63 | <Transaction>1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas</Transaction> 64 | <Transaction>1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas</Transaction> 65 | <Transaction>1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas</Transaction> 66 | <Transaction>1899-12-30 00:00:00.000.096,D:\MyCode\AMQP-Delphi\TestSendString.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj</Transaction> 67 | <Transaction>1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=</Transaction> 68 | <Transaction>1899-12-30 00:00:00.000.755,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas</Transaction> 69 | <Transaction>1899-12-30 00:00:00.000.090,D:\MyCode\Project1.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj</Transaction> 70 | <Transaction>1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\amqp.time.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 71 | <Transaction>1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas</Transaction> 72 | <Transaction>1899-12-30 00:00:00.000.720,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas</Transaction> 73 | <Transaction>1899-12-30 00:00:00.000.879,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas</Transaction> 74 | <Transaction>1899-12-30 00:00:00.000.586,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas</Transaction> 75 | <Transaction>1899-12-30 00:00:00.000.686,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas</Transaction> 76 | <Transaction>1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=</Transaction> 77 | <Transaction>1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=</Transaction> 78 | <Transaction>1899-12-30 00:00:00.000.649,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas</Transaction> 79 | <Transaction>1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas</Transaction> 80 | <Transaction>1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas</Transaction> 81 | </Transactions> 82 | </BorlandProject> 83 | -------------------------------------------------------------------------------- /TestSendString.identcache: -------------------------------------------------------------------------------- 1 | ���-D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas������������(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas������������+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas������������1D:\MyCode\rabbitmq-Delphi\demo\TestSendString.dpr������������-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas������������*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas������������'D:\MyCode\rabbitmq-Delphi\amqp.time.pas������������(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas������������(D:\MyCode\rabbitmq-Delphi\amqp.table.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.api.pas������������)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas������������-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas������������ -------------------------------------------------------------------------------- /TestSendString.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/TestSendString.res -------------------------------------------------------------------------------- /TestTimeout.dpr: -------------------------------------------------------------------------------- 1 | program TestTimeout; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | Net.Winsock2, 10 | amqp.api in '..\amqp.api.pas', 11 | amqp.connection in '..\amqp.connection.pas', 12 | amqp.consumer in '..\amqp.consumer.pas', 13 | amqp.framing in '..\amqp.framing.pas', 14 | amqp.mem in '..\amqp.mem.pas', 15 | amqp.privt in '..\amqp.privt.pas', 16 | amqp.socket in '..\amqp.socket.pas', 17 | amqp.table in '..\amqp.table.pas', 18 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 19 | amqp.time in '..\amqp.time.pas', 20 | AMQP.Types in '..\AMQP.Types.pas', 21 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 22 | 23 | {var MyEnum : TMyEnum; 24 | begin 25 | 26 | MyEnum := Two; 27 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 28 | 29 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 30 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 31 | readln; 32 | 33 | end. } 34 | 35 | function main:integer; 36 | var 37 | port, status : integer; 38 | ret : Tamqp_rpc_reply; 39 | socket : Pamqp_socket; 40 | conn : Pamqp_connection_state; 41 | props : Tamqp_basic_properties; 42 | hostname, exchange, queue, bindkey: PAnsiChar; 43 | tval: Ttimeval ; 44 | tv: Ptimeval ; 45 | vl: Tva_list; 46 | begin 47 | socket := nil; 48 | 49 | hostname := 'localhost'; 50 | port := 5672; 51 | exchange := 'Test.EX'; 52 | queue := 'Queue.Test'; 53 | bindkey := 'test-key'; 54 | 55 | tv := @tval; 56 | //timeout 5' 57 | tv.tv_sec := 5; 58 | 59 | if initializeWinsockIfNecessary() < 1 then 60 | begin 61 | Writeln('Failed to initialize "winsock": '); 62 | Exit; 63 | end; 64 | 65 | conn := amqp_new_connection(); 66 | socket := amqp_tcp_socket_new(conn); 67 | if socket = nil then begin 68 | Writeln('creating TCP socket failed!'); 69 | Exit; 70 | end; 71 | 72 | var res := try_socket_open_noblock(socket, hostname, port, tv); 73 | if res < 0 then 74 | Exit; 75 | 76 | vl.username := 'sa'; 77 | vl.password := 'admin'; 78 | vl.identity := ''; 79 | ret := amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl); 80 | 81 | if ret.library_error < 0 then 82 | Exit; 83 | 84 | 85 | 86 | amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS); 87 | amqp_connection_close(conn, AMQP_REPLY_SUCCESS); 88 | amqp_destroy_connection(conn); 89 | 90 | end; 91 | 92 | 93 | begin 94 | try 95 | Main; 96 | except 97 | on e:Exception do 98 | WriteLn(e.Message); 99 | end; 100 | end. 101 | 102 | -------------------------------------------------------------------------------- /TestTimeout.dproj.local: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <BorlandProject> 3 | <Transactions> 4 | <Transaction>1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 5 | <Transaction>1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas</Transaction> 6 | <Transaction>1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 7 | <Transaction>1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 8 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.api.pas</Transaction> 9 | <Transaction>1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.mem.pas</Transaction> 10 | <Transaction>1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.socket.pas</Transaction> 11 | <Transaction>1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 12 | <Transaction>1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.pas</Transaction> 13 | <Transaction>1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 14 | <Transaction>1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 15 | <Transaction>1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 16 | <Transaction>1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 17 | <Transaction>1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 18 | <Transaction>1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 19 | <Transaction>1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 20 | <Transaction>1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 21 | <Transaction>1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 22 | <Transaction>1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 23 | <Transaction>1899-12-30 00:00:00.000.372,D:\MyCode\AMQP-Delphi\TestTimeout.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj</Transaction> 24 | <Transaction>1899-12-30 00:00:00.000.712,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas</Transaction> 25 | <Transaction>1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas</Transaction> 26 | <Transaction>1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\framing.pas</Transaction> 27 | <Transaction>1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=</Transaction> 28 | <Transaction>1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 29 | <Transaction>1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas=</Transaction> 30 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 31 | <Transaction>1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 32 | <Transaction>1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\Unit2.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas</Transaction> 33 | <Transaction>1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.connection.pas</Transaction> 34 | <Transaction>1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.table.pas</Transaction> 35 | <Transaction>1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas</Transaction> 36 | <Transaction>1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Login.pas</Transaction> 37 | <Transaction>1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\amqp.time.pas</Transaction> 38 | <Transaction>1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=</Transaction> 39 | <Transaction>1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 40 | <Transaction>1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=</Transaction> 41 | <Transaction>1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 42 | <Transaction>1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 43 | <Transaction>1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas=</Transaction> 44 | <Transaction>1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 45 | <Transaction>1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 46 | <Transaction>1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=</Transaction> 47 | <Transaction>1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=</Transaction> 48 | <Transaction>1899-12-30 00:00:00.000.744,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas</Transaction> 49 | <Transaction>1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 50 | <Transaction>1899-12-30 00:00:00.000.542,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas</Transaction> 51 | <Transaction>1899-12-30 00:00:00.000.580,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas</Transaction> 52 | <Transaction>1899-12-30 00:00:00.000.412,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas</Transaction> 53 | <Transaction>1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas</Transaction> 54 | <Transaction>1899-12-30 00:00:00.000.459,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas</Transaction> 55 | <Transaction>1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=</Transaction> 56 | <Transaction>1899-12-30 00:00:00.000.313,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas</Transaction> 57 | <Transaction>1899-12-30 00:00:00.000.672,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas</Transaction> 58 | <Transaction>1899-12-30 00:00:00.000.358,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas</Transaction> 59 | <Transaction>1899-12-30 00:00:00.000.272,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas</Transaction> 60 | <Transaction>1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 61 | <Transaction>1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=</Transaction> 62 | <Transaction>1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 63 | <Transaction>1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=</Transaction> 64 | <Transaction>1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas</Transaction> 65 | <Transaction>1899-12-30 00:00:00.000.090,D:\MyCode\AMQP-Delphi\AMQPTest.dproj=D:\MyCode\Project1.dproj</Transaction> 66 | <Transaction>1899-12-30 00:00:00.000.636,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas</Transaction> 67 | <Transaction>1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 68 | <Transaction>1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 69 | <Transaction>1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 70 | <Transaction>1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 71 | <Transaction>1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas</Transaction> 72 | <Transaction>1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 73 | <Transaction>1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas</Transaction> 74 | <Transaction>1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=</Transaction> 75 | <Transaction>1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.framing.pas</Transaction> 76 | <Transaction>1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=</Transaction> 77 | <Transaction>1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas</Transaction> 78 | <Transaction>1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas</Transaction> 79 | <Transaction>1899-12-30 00:00:00.000.499,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas</Transaction> 80 | <Transaction>1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas</Transaction> 81 | </Transactions> 82 | </BorlandProject> 83 | -------------------------------------------------------------------------------- /TestTimeout.identcache: -------------------------------------------------------------------------------- 1 | ���-D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas������������(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas������������+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas������������-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas������������.D:\MyCode\rabbitmq-Delphi\demo\TestTimeout.dpr������������*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas������������'D:\MyCode\rabbitmq-Delphi\amqp.time.pas������������(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas������������(D:\MyCode\rabbitmq-Delphi\amqp.table.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.api.pas������������)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas������������-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas������������ -------------------------------------------------------------------------------- /TestUnbind.dpr: -------------------------------------------------------------------------------- 1 | program TestUnbind; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | amqp.api in '..\amqp.api.pas', 10 | amqp.connection in '..\amqp.connection.pas', 11 | amqp.consumer in '..\amqp.consumer.pas', 12 | amqp.framing in '..\amqp.framing.pas', 13 | amqp.mem in '..\amqp.mem.pas', 14 | amqp.privt in '..\amqp.privt.pas', 15 | amqp.socket in '..\amqp.socket.pas', 16 | amqp.table in '..\amqp.table.pas', 17 | amqp.tcp_socket in '..\amqp.tcp_socket.pas', 18 | amqp.time in '..\amqp.time.pas', 19 | AMQP.Types in '..\AMQP.Types.pas', 20 | amqp_tcp_socket in '..\amqp_tcp_socket.pas'; 21 | 22 | {var MyEnum : TMyEnum; 23 | begin 24 | 25 | MyEnum := Two; 26 | writeln(Ord(MyEnum)); // writes 1, because first element in enumeration is numbered zero 27 | 28 | MyEnum := TMyEnum(2); // Use TMyEnum as if it were a function 29 | Writeln (GetEnumName(TypeInfo(TMyEnum), Ord(MyEnum))); // Use RTTI to return the enum value's name 30 | readln; 31 | 32 | end. } 33 | 34 | function main:integer; 35 | var 36 | port, status : integer; 37 | ret : Tamqp_rpc_reply; 38 | socket : Pamqp_socket; 39 | conn : Pamqp_connection_state; 40 | props : Tamqp_basic_properties; 41 | hostname, exchange, queue, bindkey: PAnsiChar; 42 | vl: Tva_list; 43 | begin 44 | socket := nil; 45 | 46 | hostname := 'localhost'; 47 | port := 5672; 48 | exchange := 'Test.EX'; 49 | queue := 'Queue.Test'; 50 | bindkey := 'test-key'; 51 | 52 | if initializeWinsockIfNecessary() < 1 then 53 | begin 54 | Writeln('Failed to initialize "winsock": '); 55 | Exit; 56 | end; 57 | 58 | conn := amqp_new_connection(); 59 | socket := amqp_tcp_socket_new(conn); 60 | if not Assigned(socket) then begin 61 | Writeln('creating TCP socket failed!'); 62 | Exit; 63 | end; 64 | status := amqp_socket_open(socket, hostname, port); 65 | if status > 0 then begin 66 | Writeln('opening TCP socket failed!'); 67 | Exit; 68 | end; 69 | vl.username := 'sa'; 70 | vl.password := 'admin'; 71 | vl.identity := ''; 72 | ret := amqp_login(conn, '/', 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, vl); 73 | 74 | if ret.library_error < 0 then 75 | Exit; 76 | 77 | var P := amqp_channel_open(conn, 1); 78 | IF P = nil then 79 | Exit; 80 | var reply := amqp_get_rpc_reply(conn); 81 | if reply.library_error < 0 then 82 | Exit; 83 | 84 | amqp_queue_unbind(conn, 1, amqp_cstring_bytes(queue), 85 | amqp_cstring_bytes(exchange), 86 | amqp_cstring_bytes(bindkey), amqp_empty_table); 87 | if reply.library_error < 0 then 88 | Exit; 89 | amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS); 90 | amqp_connection_close(conn, AMQP_REPLY_SUCCESS); 91 | amqp_destroy_connection(conn); 92 | 93 | end; 94 | 95 | 96 | begin 97 | try 98 | Main; 99 | except 100 | on e:Exception do 101 | WriteLn(e.Message); 102 | end; 103 | end. 104 | 105 | -------------------------------------------------------------------------------- /TestUnbind.dproj.local: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <BorlandProject> 3 | <Transactions> 4 | <Transaction>1899-12-30 00:00:00.000.724,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 5 | <Transaction>1899-12-30 00:00:00.000.640,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 6 | <Transaction>1899-12-30 00:00:00.000.732,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Field.pas</Transaction> 7 | <Transaction>1899-12-30 00:00:00.000.659,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 8 | <Transaction>1899-12-30 00:00:00.000.438,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 9 | <Transaction>1899-12-30 00:00:00.000.180,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 10 | <Transaction>1899-12-30 00:00:00.000.437,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas</Transaction> 11 | <Transaction>1899-12-30 00:00:00.000.014,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 12 | <Transaction>1899-12-30 00:00:00.000.816,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas</Transaction> 13 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas</Transaction> 14 | <Transaction>1899-12-30 00:00:00.000.214,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 15 | <Transaction>1899-12-30 00:00:00.000.966,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 16 | <Transaction>1899-12-30 00:00:00.000.200,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 17 | <Transaction>1899-12-30 00:00:00.000.582,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 18 | <Transaction>1899-12-30 00:00:00.000.528,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 19 | <Transaction>1899-12-30 00:00:00.000.292,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 20 | <Transaction>1899-12-30 00:00:00.000.772,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 21 | <Transaction>1899-12-30 00:00:00.000.001,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 22 | <Transaction>1899-12-30 00:00:00.000.417,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 23 | <Transaction>1899-12-30 00:00:00.000.658,D:\MyCode\AMQP-Delphi\AMQP.Field.pas=</Transaction> 24 | <Transaction>1899-12-30 00:00:00.000.643,=D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas</Transaction> 25 | <Transaction>1899-12-30 00:00:00.000.204,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit2.pas</Transaction> 26 | <Transaction>1899-12-30 00:00:00.000.567,=D:\MyCode\AMQP-Delphi\Unit2.pas</Transaction> 27 | <Transaction>1899-12-30 00:00:00.000.761,D:\MyCode\AMQP-Delphi\AMQP.MethodFrame.pas=</Transaction> 28 | <Transaction>1899-12-30 00:00:00.000.714,D:\MyCode\AMQP-Delphi\MyFunc.pas=</Transaction> 29 | <Transaction>1899-12-30 00:00:00.000.655,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 30 | <Transaction>1899-12-30 00:00:00.000.284,D:\MyCode\AMQP-Delphi\amqp.api.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 31 | <Transaction>1899-12-30 00:00:00.000.832,=D:\MyCode\AMQP-Delphi\MyFunc.pas</Transaction> 32 | <Transaction>1899-12-30 00:00:00.000.472,D:\MyCode\AMQP-Delphi\amqp.privt.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 33 | <Transaction>1899-12-30 00:00:00.000.595,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas</Transaction> 34 | <Transaction>1899-12-30 00:00:00.000.159,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas</Transaction> 35 | <Transaction>1899-12-30 00:00:00.000.724,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas</Transaction> 36 | <Transaction>1899-12-30 00:00:00.000.483,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.Types.pas</Transaction> 37 | <Transaction>1899-12-30 00:00:00.000.316,D:\MyCode\AMQP-Delphi\Unit1.pas=D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas</Transaction> 38 | <Transaction>1899-12-30 00:00:00.000.129,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 39 | <Transaction>1899-12-30 00:00:00.000.887,D:\MyCode\AMQP-Delphi\AMQP.Watchable.pas=</Transaction> 40 | <Transaction>1899-12-30 00:00:00.000.231,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 41 | <Transaction>1899-12-30 00:00:00.000.620,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 42 | <Transaction>1899-12-30 00:00:00.000.004,=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 43 | <Transaction>1899-12-30 00:00:00.000.253,=D:\MyCode\rabbitmq-Delphi\amqp.api.pas</Transaction> 44 | <Transaction>1899-12-30 00:00:00.000.642,D:\MyCode\AMQP-Delphi\AMQP.BasicAckFrame.pas=</Transaction> 45 | <Transaction>1899-12-30 00:00:00.000.567,D:\MyCode\AMQP-Delphi\amqp.mem.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 46 | <Transaction>1899-12-30 00:00:00.000.322,=D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas</Transaction> 47 | <Transaction>1899-12-30 00:00:00.000.666,D:\MyCode\AMQP-Delphi\amqp.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 48 | <Transaction>1899-12-30 00:00:00.000.485,D:\MyCode\AMQP-Delphi\amqp.framing.pas=D:\MyCode\AMQP-Delphi\framing.pas</Transaction> 49 | <Transaction>1899-12-30 00:00:00.000.926,D:\MyCode\AMQP-Delphi\AMQP.ConnectionImpl.pas=</Transaction> 50 | <Transaction>1899-12-30 00:00:00.000.566,D:\MyCode\AMQP-Delphi\amqp.pas=</Transaction> 51 | <Transaction>1899-12-30 00:00:00.000.997,D:\MyCode\AMQP-Delphi\amqp.socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 52 | <Transaction>1899-12-30 00:00:00.000.119,D:\MyCode\AMQP-Delphi\amqp.tcp_socket.pas=D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas</Transaction> 53 | <Transaction>1899-12-30 00:00:00.000.288,=D:\MyCode\rabbitmq-Delphi\amqp.connection.pas</Transaction> 54 | <Transaction>1899-12-30 00:00:00.000.617,D:\MyCode\AMQP-Delphi\amqp_tcp_socket.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 55 | <Transaction>1899-12-30 00:00:00.000.506,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 56 | <Transaction>1899-12-30 00:00:00.000.711,D:\MyCode\AMQP-Delphi\AMQP.Login.pas=</Transaction> 57 | <Transaction>1899-12-30 00:00:00.000.398,=D:\MyCode\rabbitmq-Delphi\amqp.mem.pas</Transaction> 58 | <Transaction>1899-12-30 00:00:00.000.984,D:\MyCode\AMQP-Delphi\AMQP.ExtFrame.pas=</Transaction> 59 | <Transaction>1899-12-30 00:00:00.000.602,=D:\MyCode\rabbitmq-Delphi\amqp.time.pas</Transaction> 60 | <Transaction>1899-12-30 00:00:00.000.706,D:\MyCode\AMQP-Delphi\amqp.connection.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 61 | <Transaction>1899-12-30 00:00:00.000.312,D:\MyCode\AMQP-Delphi\amqp.table.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 62 | <Transaction>1899-12-30 00:00:00.000.980,=D:\MyCode\Unit1.pas</Transaction> 63 | <Transaction>1899-12-30 00:00:00.000.058,=D:\MyCode\Unit1.pas</Transaction> 64 | <Transaction>1899-12-30 00:00:00.000.261,=D:\MyCode\Unit1.pas</Transaction> 65 | <Transaction>1899-12-30 00:00:00.000.090,=D:\MyCode\Unit1.pas</Transaction> 66 | <Transaction>1899-12-30 00:00:00.000.569,=D:\MyCode\Unit1.pas</Transaction> 67 | <Transaction>1899-12-30 00:00:00.000.805,D:\MyCode\AMQP-Delphi\AMQP.OutBuffer.pas=</Transaction> 68 | <Transaction>1899-12-30 00:00:00.000.569,=D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas</Transaction> 69 | <Transaction>1899-12-30 00:00:00.000.090,D:\MyCode\Project1.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj</Transaction> 70 | <Transaction>1899-12-30 00:00:00.000.607,D:\MyCode\AMQP-Delphi\amqp.time.pas=D:\MyCode\AMQP-Delphi\Unit1.pas</Transaction> 71 | <Transaction>1899-12-30 00:00:00.000.448,=D:\MyCode\rabbitmq-Delphi\amqp.privt.pas</Transaction> 72 | <Transaction>1899-12-30 00:00:00.000.503,=D:\MyCode\rabbitmq-Delphi\amqp.socket.pas</Transaction> 73 | <Transaction>1899-12-30 00:00:00.000.536,=D:\MyCode\rabbitmq-Delphi\amqp.table.pas</Transaction> 74 | <Transaction>1899-12-30 00:00:00.000.576,D:\MyCode\AMQP-Delphi\TestUnbind.dproj=D:\MyCode\AMQP-Delphi\AMQPTest.dproj</Transaction> 75 | <Transaction>1899-12-30 00:00:00.000.365,=D:\MyCode\rabbitmq-Delphi\amqp.framing.pas</Transaction> 76 | <Transaction>1899-12-30 00:00:00.000.680,=D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas</Transaction> 77 | <Transaction>1899-12-30 00:00:00.000.500,=D:\MyCode\AMQP-Delphi\AMQP.Types.pas</Transaction> 78 | <Transaction>1899-12-30 00:00:00.000.844,D:\MyCode\AMQP-Delphi\AMQP.Types.pas=</Transaction> 79 | <Transaction>1899-12-30 00:00:00.000.862,D:\MyCode\AMQP-Delphi\AMQP.BasicFrame.pas=</Transaction> 80 | <Transaction>1899-12-30 00:00:00.000.623,D:\MyCode\AMQP-Delphi\framing.pas=D:\MyCode\AMQP-Delphi\amqp.privt.pas</Transaction> 81 | </Transactions> 82 | </BorlandProject> 83 | -------------------------------------------------------------------------------- /TestUnbind.identcache: -------------------------------------------------------------------------------- 1 | ���-D:\MyCode\rabbitmq-Delphi\demo\TestUnbind.dpr������������(D:\MyCode\rabbitmq-Delphi\amqp.privt.pas������������+D:\MyCode\rabbitmq-Delphi\amqp.consumer.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.mem.pas������������-D:\MyCode\rabbitmq-Delphi\amqp.connection.pas������������*D:\MyCode\rabbitmq-Delphi\amqp.framing.pas������������'D:\MyCode\rabbitmq-Delphi\amqp.time.pas������������-D:\MyCode\rabbitmq-Delphi\amqp_tcp_socket.pas������������-D:\MyCode\rabbitmq-Delphi\amqp.tcp_socket.pas������������(D:\MyCode\rabbitmq-Delphi\amqp.table.pas������������&D:\MyCode\rabbitmq-Delphi\amqp.api.pas������������)D:\MyCode\rabbitmq-Delphi\amqp.socket.pas������������(D:\MyCode\rabbitmq-Delphi\AMQP.Types.pas������������ -------------------------------------------------------------------------------- /amqp.api.pas: -------------------------------------------------------------------------------- 1 | unit amqp.api; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | interface 8 | uses {$IFDEF FPC}SysUtils,{$Else} System.SysUtils, {$ENDIF} amqp.framing, AMQP.Types; 9 | 10 | function amqp_basic_publish( state : Pamqp_connection_state; channel : amqp_channel_t; 11 | exchange, routing_key : Tamqp_bytes; 12 | mandatory, immediate : amqp_boolean_t; 13 | properties: Pamqp_basic_properties; 14 | body : Tamqp_bytes):integer; 15 | function amqp_channel_close( state : Pamqp_connection_state; channel : amqp_channel_t; code : integer): Tamqp_rpc_reply; 16 | function amqp_connection_close( state : Pamqp_connection_state; code : integer):Tamqp_rpc_reply; 17 | 18 | implementation 19 | 20 | uses amqp.socket, amqp.connection, amqp.privt, amqp.time; 21 | 22 | 23 | 24 | function amqp_connection_close( state : Pamqp_connection_state; code : integer):Tamqp_rpc_reply; 25 | var 26 | codestr : array[0..12] of AMQPChar; 27 | replies : Tamqp_methods; 28 | req : Tamqp_channel_close; 29 | s: Ansistring; 30 | i, Size: Integer; 31 | begin 32 | SetLength(replies,2); 33 | replies[0] := AMQP_CONNECTION_CLOSE_OK_METHOD; 34 | replies[1] := 0; 35 | 36 | if (code < 0) or (code > UINT16_MAX) then 37 | Exit(amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER)); 38 | 39 | req.reply_code := uint16_t(code); 40 | req.reply_text.bytes := @codestr; 41 | s := Format('%d', [code]); 42 | size:=Length(S); 43 | For i:=1 To size Do 44 | Begin 45 | codestr[i-1]:=S[i]; 46 | If (i = size) Then Break; 47 | End; 48 | req.reply_text.len := size; 49 | req.class_id := 0; 50 | req.method_id := 0; 51 | Result := amqp_simple_rpc(state, 0, AMQP_CONNECTION_CLOSE_METHOD, replies, @req); 52 | SetLength(replies,0); 53 | end; 54 | 55 | function amqp_channel_close( state : Pamqp_connection_state; channel : amqp_channel_t; code : integer): Tamqp_rpc_reply; 56 | var 57 | codestr : array[0..12] of AMQPChar; 58 | replies : Tamqp_methods; 59 | req : Tamqp_channel_close; 60 | s: Ansistring; 61 | i, Size: Integer; 62 | begin 63 | SetLength(replies,2); 64 | replies[0] := AMQP_CHANNEL_CLOSE_OK_METHOD; 65 | replies[1] := 0; 66 | 67 | if (code < 0) or (code > UINT16_MAX) then 68 | Exit(amqp_rpc_reply_error(AMQP_STATUS_INVALID_PARAMETER)); 69 | 70 | req.reply_code := uint16_t(code); 71 | req.reply_text.bytes := @codestr; 72 | s := Format('%d', [code]); 73 | size:=Length(S); 74 | For i:=1 To size Do 75 | Begin 76 | codestr[i-1]:=S[i]; 77 | If (i = size) Then Break; 78 | End; 79 | req.reply_text.len := size; 80 | req.class_id := 0; 81 | req.method_id := 0; 82 | Result := amqp_simple_rpc(state, channel, AMQP_CHANNEL_CLOSE_METHOD, replies, @req); 83 | SetLength(replies,0); 84 | end; 85 | 86 | function amqp_basic_publish( state : Pamqp_connection_state; channel : amqp_channel_t; 87 | exchange, routing_key : Tamqp_bytes; 88 | mandatory, immediate : amqp_boolean_t; 89 | properties: Pamqp_basic_properties; 90 | body : Tamqp_bytes):integer; 91 | var 92 | f : Tamqp_frame; 93 | body_offset, 94 | usable_body_payload_size : size_t; 95 | res, 96 | flagz : integer; 97 | m : Tamqp_basic_publish; 98 | default_properties : Tamqp_basic_properties; 99 | remaining : size_t; 100 | begin 101 | usable_body_payload_size := state.frame_max - (HEADER_SIZE + FOOTER_SIZE); 102 | m.exchange := exchange; 103 | m.routing_key := routing_key; 104 | m.mandatory := mandatory; 105 | m.immediate := immediate; 106 | m.ticket := 0; 107 | { TODO(alanxz): this heartbeat check is happening in the wrong place, it 108 | * should really be done in amqp_try_send/writev } 109 | res := amqp_time_has_past(state.next_recv_heartbeat); 110 | if Int(AMQP_STATUS_TIMER_FAILURE) = res then 111 | Exit(res) 112 | 113 | else 114 | if (Int(AMQP_STATUS_TIMEOUT) = res) then 115 | begin 116 | res := amqp_try_recv(state); 117 | if Int(AMQP_STATUS_TIMEOUT) = res then 118 | Exit(Int(AMQP_STATUS_HEARTBEAT_TIMEOUT)) 119 | else if int(AMQP_STATUS_OK) <> res then 120 | Exit(res); 121 | 122 | end; 123 | res := amqp_send_method_inner(state, channel, AMQP_BASIC_PUBLISH_METHOD, @m, 124 | Int(AMQP_SF_MORE), Tamqp_time.infinite()); 125 | if res < 0 then 126 | Exit(res); 127 | 128 | if properties = nil then 129 | begin 130 | memset(default_properties, 0, sizeof(default_properties)); 131 | properties := @default_properties; 132 | end; 133 | f.frame_type := AMQP_FRAME_HEADER; 134 | f.channel := channel; 135 | f.payload.properties.class_id := AMQP_BASIC_CLASS; 136 | f.payload.properties.body_size := body.len; 137 | f.payload.properties.decoded := Pointer(properties); 138 | if body.len > 0 then 139 | flagz := Int(AMQP_SF_MORE) 140 | else 141 | flagz := Int(AMQP_SF_NONE); 142 | 143 | res := amqp_send_frame_inner(state, f, flagz, Tamqp_time.infinite); 144 | if res < 0 then 145 | Exit(res); 146 | 147 | body_offset := 0; 148 | while body_offset < body.len do 149 | begin 150 | remaining := body.len - body_offset; 151 | if remaining = 0 then 152 | break; 153 | 154 | f.frame_type := AMQP_FRAME_BODY; 155 | f.channel := channel; 156 | f.payload.body_fragment.bytes := amqp_offset(body.bytes, body_offset); 157 | if remaining >= usable_body_payload_size then 158 | begin 159 | f.payload.body_fragment.len := usable_body_payload_size; 160 | flagz := Int(AMQP_SF_MORE); 161 | end 162 | else 163 | begin 164 | f.payload.body_fragment.len := remaining; 165 | flagz := Int(AMQP_SF_NONE); 166 | end; 167 | body_offset := body_offset + f.payload.body_fragment.len; 168 | res := amqp_send_frame_inner(state, f, flagz, Tamqp_time.infinite()); 169 | if res < 0 then 170 | Exit(res); 171 | 172 | end; 173 | Result := Int(AMQP_STATUS_OK); 174 | end; 175 | 176 | initialization 177 | 178 | end. 179 | -------------------------------------------------------------------------------- /amqp.connection.pas: -------------------------------------------------------------------------------- 1 | unit amqp.connection; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | {$INCLUDE config.inc} 8 | interface 9 | uses {$IFDEF FPC}SysUtils,{$Else} System.SysUtils, {$ENDIF}amqp.socket, AMQP.Types, 10 | amqp.framing, amqp.time, amqp.table, 11 | amqp.privt, amqp.mem, amqp.tcp_socket; 12 | 13 | function amqp_new_connection:Pamqp_connection_state; 14 | procedure amqp_set_sockfd( state : Pamqp_connection_state; sockfd : integer); 15 | 16 | function amqp_tune_connection( state : Pamqp_connection_state; channel_max, frame_max, heartbeat : integer):integer; 17 | function amqp_destroy_connection( state : Pamqp_connection_state):integer; 18 | procedure return_to_idle( state : Pamqp_connection_state); 19 | function consume_data(state : Pamqp_connection_state; out received_data : Tamqp_bytes):size_t; 20 | 21 | function amqp_release_buffers_ok( state : Pamqp_connection_state):amqp_boolean_t; 22 | procedure amqp_release_buffers( state : Pamqp_connection_state); 23 | procedure amqp_maybe_release_buffers( state : Pamqp_connection_state); 24 | procedure amqp_maybe_release_buffers_on_channel( state : Pamqp_connection_state; channel : amqp_channel_t); 25 | function amqp_frame_to_bytes(const Aframe : Tamqp_frame; Abuffer : Tamqp_bytes; out Aencoded : Tamqp_bytes):integer; 26 | 27 | function amqp_send_frame(Astate : Pamqp_connection_state;const Aframe : Pamqp_frame):integer; 28 | function amqp_send_frame_inner(Astate : Pamqp_connection_state;const Aframe : Tamqp_frame; Aflags : integer; Adeadline : Tamqp_time):integer; 29 | 30 | function amqp_handle_input(Astate : Pamqp_connection_state; 31 | var Areceived_data : Tamqp_bytes; 32 | out Adecoded_frame : Tamqp_frame):integer; 33 | //function amqp_heartbeat_send(state: Pamqp_connection_state): int; 34 | function amqp_heartbeat_recv(state: Pamqp_connection_state): int; 35 | 36 | const 37 | AMQP_INITIAL_FRAME_POOL_PAGE_SIZE = 65536; 38 | AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE = 131072; 39 | AMQP_DEFAULT_LOGIN_TIMEOUT_SEC = 12; 40 | 41 | implementation 42 | 43 | function amqp_send_frame_inner(Astate : Pamqp_connection_state;const Aframe : Tamqp_frame; 44 | Aflags : integer; Adeadline : Tamqp_time):integer; 45 | var 46 | Lres, count, Level : integer; 47 | Lsent : ssize_t; 48 | Lencoded : Tamqp_bytes; 49 | Lnext_timeout : Tamqp_time; 50 | label start_send ; 51 | begin 52 | { TODO: if the AMQP_SF_MORE socket optimization can be shown to work 53 | * correctly, then this could be un-done so that body-frames are sent as 3 54 | * send calls, getting rid of the copy of the body content, some testing 55 | * would need to be done to see if this would actually a win for performance. 56 | * } 57 | Inc(gLevel); 58 | Level := gLevel; 59 | count := 0; 60 | {$IFDEF _DEBUG_} 61 | DebugOut(Level, 'step into amqp.connection:: amqp_frame_to_bytes==>'); 62 | {$ENDIF} 63 | 64 | Lres := amqp_frame_to_bytes(Aframe, Astate.outbound_buffer, Lencoded); 65 | {$IFDEF _DEBUG_} 66 | DebugOut(Level, 'step over amqp.connection::amqp_frame_to_bytes, res=' + IntToStr(Lres)); 67 | {$ENDIF} 68 | if Int(AMQP_STATUS_OK) <> Lres then 69 | Exit(Lres); 70 | 71 | start_send: 72 | Inc(count); 73 | Lnext_timeout := amqp_time_first(Adeadline, Astate.next_recv_heartbeat); 74 | {$IFDEF _DEBUG_} 75 | DebugOut(Level, 'step into amqp.socket:: amqp_try_send==>, start_send:' + IntToStr(count)); 76 | {$ENDIF} 77 | Lsent := amqp_try_send(Astate, Lencoded.bytes, Lencoded.len, Lnext_timeout, Aflags); 78 | {$IFDEF _DEBUG_} 79 | DebugOut(Level, 'step over amqp.socket:: amqp_try_send, res=' + IntToStr(Lsent)); 80 | {$ENDIF} 81 | if 0 > Lsent then 82 | Exit(int(Lsent)); 83 | 84 | { A partial send has occurred, because of a heartbeat timeout (so try recv 85 | * something) or common timeout (so return AMQP_STATUS_TIMEOUT) } 86 | if ssize_t(Lencoded.len) <> Lsent then 87 | begin 88 | if Lnext_timeout = Adeadline then 89 | { timeout of method was received, so return from method} 90 | Exit(Integer(AMQP_STATUS_TIMEOUT)); 91 | 92 | Lres := amqp_try_recv(Astate); 93 | if Int(AMQP_STATUS_TIMEOUT) = Lres then 94 | Exit(Integer(AMQP_STATUS_HEARTBEAT_TIMEOUT)) 95 | else 96 | if (Int(AMQP_STATUS_OK) <> Lres) then 97 | Exit(Lres); 98 | 99 | Inc(Lencoded.bytes ,Lsent); 100 | Lencoded.len := Lencoded.len - Lsent; 101 | goto start_send; 102 | end; 103 | Lres := amqp_time_s_from_now(Astate.next_send_heartbeat, 104 | Astate.heartbeat); 105 | Result := Lres; 106 | end; 107 | 108 | 109 | function amqp_heartbeat_recv( state: Pamqp_connection_state): int; 110 | begin 111 | Result := 2 * state.heartbeat; 112 | end; 113 | 114 | 115 | function amqp_handle_input(Astate : Pamqp_connection_state; 116 | var Areceived_data : Tamqp_bytes; 117 | out Adecoded_frame : Tamqp_frame):integer; 118 | var 119 | bytes_consumed : size_t; 120 | raw_frame : PAMQPChar; 121 | channel : amqp_channel_t; 122 | channel_pool : Pamqp_pool; 123 | frame_size : uint32; 124 | encoded : Tamqp_bytes; 125 | res,Level : integer; 126 | 127 | begin 128 | { Returning frame_type of zero indicates either insufficient input, 129 | or a complete, ignored frame was read. } 130 | Inc(gLevel); 131 | Level := gLevel; 132 | Adecoded_frame.frame_type := 0; 133 | if Areceived_data.len = 0 then 134 | Exit(Int(AMQP_STATUS_OK)); 135 | 136 | if Astate.state = CONNECTION_STATE_IDLE then 137 | Astate.state := CONNECTION_STATE_HEADER; 138 | {$IFDEF _DEBUG_} 139 | DebugOut(Level, 'step into amqp.connection:: consume_data==>'); 140 | {$ENDIF} 141 | bytes_consumed := consume_data(Astate, Areceived_data); 142 | {$IFDEF _DEBUG_} 143 | DebugOut(Level, 'step over amqp.connection:: consume_data, bytes_consumed=' + IntToStr(bytes_consumed)); 144 | {$ENDIF} 145 | { do we have target_size data yet? if not, return with the 146 | expectation that more will arrive } 147 | if Astate.inbound_offset < Astate.target_size then 148 | Exit(int(bytes_consumed)); 149 | 150 | raw_frame := (Astate.inbound_buffer.bytes); 151 | //var p := PAnsiChar( state.inbound_buffer.bytes); 152 | case Astate.state of 153 | CONNECTION_STATE_INITIAL, 154 | CONNECTION_STATE_HEADER, 155 | CONNECTION_STATE_BODY: 156 | begin 157 | { check for a protocol header from the server } 158 | if CompareMem(raw_frame, PAnsiChar('AMQP'), 4) then 159 | //if PAnsiChar(raw_frame) = 'AMQP' then 160 | begin 161 | Adecoded_frame.frame_type := Ord(AMQP_PSEUDOFRAME_PROTOCOL_HEADER); 162 | Adecoded_frame.channel := 0; 163 | Adecoded_frame.payload.protocol_header.transport_high := amqp_d8(amqp_offset(raw_frame, 4)); 164 | Adecoded_frame.payload.protocol_header.transport_low := amqp_d8(amqp_offset(raw_frame, 5)); 165 | Adecoded_frame.payload.protocol_header.protocol_version_major := amqp_d8(amqp_offset(raw_frame, 6)); 166 | Adecoded_frame.payload.protocol_header.protocol_version_minor := amqp_d8(amqp_offset(raw_frame, 7)); 167 | return_to_idle(Astate); 168 | Exit(int(bytes_consumed)); 169 | end; 170 | 171 | //CONNECTION_STATE_HEADER: 172 | 173 | channel := amqp_d16(amqp_offset(raw_frame, 1)); 174 | { frame length is 3 bytes in } 175 | frame_size := amqp_d32(amqp_offset(raw_frame, 3)); 176 | { To prevent the target_size calculation below from overflowing, check 177 | * that the stated frame_size is smaller than a signed 32-bit. Given 178 | * the library only allows configuring frame_max as an int32_t, and 179 | * frame_size is uint32_t, the math below is safe from overflow. } 180 | if frame_size >= INT32_MAX then 181 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 182 | 183 | Astate.target_size := frame_size + HEADER_SIZE + FOOTER_SIZE; 184 | if size_t(Astate.frame_max) < Astate.target_size then 185 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 186 | 187 | {$IFDEF _DEBUG_} 188 | DebugOut(Level, 'step into amqp.mem:: amqp_get_or_create_channel_pool==>'); 189 | {$ENDIF} 190 | channel_pool := Astate.get_or_create_channel_pool(channel); 191 | {$IFDEF _DEBUG_} 192 | DebugOut(Level, 'step over amqp.mem:: amqp_get_or_create_channel_pool.'); 193 | {$ENDIF} 194 | if nil = channel_pool then 195 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 196 | 197 | channel_pool.alloc_bytes( Astate.target_size, Astate.inbound_buffer); 198 | if nil = Astate.inbound_buffer.bytes then 199 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 200 | 201 | memcpy(Astate.inbound_buffer.bytes, @Astate.header_buffer, HEADER_SIZE); 202 | raw_frame := Astate.inbound_buffer.bytes; 203 | Astate.state := CONNECTION_STATE_BODY; 204 | bytes_consumed := bytes_consumed + consume_data(Astate, Areceived_data); 205 | { do we have target_size data yet? if not, return with the 206 | expectation that more will arrive } 207 | if Astate.inbound_offset < Astate.target_size then 208 | Exit(int(bytes_consumed)); 209 | 210 | 211 | { fall through to process body } 212 | //CONNECTION_STATE_BODY: 213 | 214 | { Check frame end marker (footer) } 215 | if amqp_d8(amqp_offset(raw_frame, Astate.target_size - 1 )) <> AMQP_FRAME_END then 216 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 217 | 218 | Adecoded_frame.frame_type := amqp_d8(amqp_offset(raw_frame, 0)); 219 | Adecoded_frame.channel := amqp_d16(amqp_offset(raw_frame, 1)); 220 | {$IFDEF _DEBUG_} 221 | DebugOut(Level, 'step into amqp.mem:: amqp_get_or_create_channel_pool==>'); 222 | {$ENDIF} 223 | channel_pool := Astate.get_or_create_channel_pool(Adecoded_frame.channel); 224 | {$IFDEF _DEBUG_} 225 | DebugOut(Level, 'step over amqp.mem:: amqp_get_or_create_channel_pool.'); 226 | {$ENDIF} 227 | if nil = channel_pool then 228 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 229 | 230 | case Adecoded_frame.frame_type of 231 | AMQP_FRAME_METHOD: 232 | begin 233 | Adecoded_frame.payload.method.id := amqp_d32(amqp_offset(raw_frame, HEADER_SIZE)); 234 | encoded.bytes := amqp_offset(raw_frame, HEADER_SIZE + 4); 235 | encoded.len := Astate.target_size - HEADER_SIZE - 4 - FOOTER_SIZE; 236 | {$IFDEF _DEBUG_} 237 | DebugOut(Level, 'AMQP_FRAME_METHOD step into amqp.framming:: amqp_decode_method==>'); 238 | {$ENDIF} 239 | res := amqp_decode_method(Adecoded_frame.payload.method.id, 240 | channel_pool, encoded, 241 | Adecoded_frame.payload.method.decoded); 242 | {$IFDEF _DEBUG_} 243 | DebugOut(Level, 'AMQP_FRAME_METHOD step over amqp.framming:: amqp_decode_method, res=' + IntToStr(res)); 244 | {$ENDIF} 245 | if res < 0 then 246 | Exit(res); 247 | end; 248 | 249 | AMQP_FRAME_HEADER: 250 | begin 251 | Adecoded_frame.payload.properties.class_id := amqp_d16(amqp_offset(raw_frame, HEADER_SIZE)); 252 | { unused 2-byte weight field goes here } 253 | Adecoded_frame.payload.properties.body_size := amqp_d64(amqp_offset(raw_frame, HEADER_SIZE + 4)); 254 | encoded.bytes := amqp_offset(raw_frame, HEADER_SIZE + 12); 255 | encoded.len := Astate.target_size - HEADER_SIZE - 12 - FOOTER_SIZE; 256 | Adecoded_frame.payload.properties.raw := encoded; 257 | {$IFDEF _DEBUG_} 258 | DebugOut(Level, 'AMQP_FRAME_HEADER step into amqp.framming:: amqp_decode_properties==>'); 259 | {$ENDIF} 260 | res := amqp_decode_properties(Adecoded_frame.payload.properties.class_id, 261 | channel_pool, encoded, 262 | @Adecoded_frame.payload.properties.decoded); 263 | {$IFDEF _DEBUG_} 264 | DebugOut(Level, 'AMQP_FRAME_HEADER step over amqp.framming:: amqp_decode_properties, res=' + IntToStr(res)); 265 | {$ENDIF} 266 | if res < 0 then 267 | Exit(res); 268 | end; 269 | 270 | AMQP_FRAME_BODY: 271 | begin 272 | Adecoded_frame.payload.body_fragment.len := Astate.target_size - HEADER_SIZE - FOOTER_SIZE; 273 | Adecoded_frame.payload.body_fragment.bytes := amqp_offset(raw_frame, HEADER_SIZE); 274 | end; 275 | AMQP_FRAME_HEARTBEAT: 276 | begin 277 | // 278 | end; 279 | else 280 | begin 281 | { Ignore the frame } 282 | Adecoded_frame.frame_type := 0; 283 | end; 284 | end; 285 | return_to_idle(Astate); 286 | Exit(int(bytes_consumed)) ; 287 | end; 288 | else 289 | raise Exception.Create('Internal error: invalid amqp_connection_state_t.state ' 290 | + IntToStr(Int(Astate.state))); 291 | end; 292 | end; 293 | 294 | function amqp_new_connection:Pamqp_connection_state; 295 | var 296 | res : integer; 297 | state : Pamqp_connection_state; 298 | label out_nomem; 299 | 300 | begin 301 | state := Pamqp_connection_state(AllocMem(1* sizeof(Tamqp_connection_state))); 302 | if state = nil then 303 | Exit(nil); 304 | 305 | res := amqp_tune_connection(state, 0, AMQP_INITIAL_FRAME_POOL_PAGE_SIZE, 0); 306 | if 0 <> res then 307 | goto out_nomem; 308 | 309 | state.inbound_buffer.bytes := @state.header_buffer; 310 | state.inbound_buffer.len := sizeof(state.header_buffer); 311 | state.state := CONNECTION_STATE_INITIAL; 312 | { the server protocol version response is 8 bytes, which conveniently 313 | is also the minimum frame size } 314 | state.target_size := 8; 315 | state.sock_inbound_buffer.len := AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE; 316 | state.sock_inbound_buffer.bytes := malloc(AMQP_INITIAL_INBOUND_SOCK_BUFFER_SIZE); 317 | if state.sock_inbound_buffer.bytes = nil then 318 | goto out_nomem; 319 | 320 | //init_amqp_pool(@state.properties_pool, 512); 321 | state.properties_pool.Create(512); 322 | { Use address of the internal_handshake_timeout object by default. } 323 | state.internal_handshake_timeout.tv_sec := AMQP_DEFAULT_LOGIN_TIMEOUT_SEC; 324 | state.internal_handshake_timeout.tv_usec := 0; 325 | state.handshake_timeout := @state.internal_handshake_timeout; 326 | Exit(state); 327 | out_nomem: 328 | free(state.sock_inbound_buffer.bytes); 329 | free(state); 330 | Result := nil; 331 | end; 332 | 333 | 334 | procedure amqp_set_sockfd( state : Pamqp_connection_state; sockfd : integer); 335 | var 336 | socket : Pamqp_socket; 337 | begin 338 | socket := amqp_tcp_socket_new(state); 339 | if not Assigned(socket) then 340 | //amqp_abort('%s', strerror(errno)); 341 | raise Exception.Create('CRAETE new socket error!!!'); 342 | 343 | amqp_tcp_socket_set_sockfd(socket, sockfd); 344 | end; 345 | 346 | 347 | procedure ENFORCE_STATE( statevec : Pamqp_connection_state; statenum : Tamqp_connection_state_enum); 348 | var 349 | _check_state : Pamqp_connection_state; 350 | _wanted_state : Tamqp_connection_state_enum; 351 | s: string; 352 | begin 353 | _check_state := (statevec); 354 | _wanted_state := (statenum); 355 | if _check_state.state <> _wanted_state then 356 | begin 357 | s := Format('Programming error: invalid AMQP connection state: expected %d, '+ 358 | 'got %d', 359 | [Int(_wanted_state), Int(_check_state.state)]); 360 | raise Exception.Create(s); 361 | end; 362 | end; 363 | 364 | 365 | function amqp_tune_connection( state : Pamqp_connection_state; channel_max, frame_max, heartbeat : integer):integer; 366 | var 367 | newbuf : Pointer; 368 | res : integer; 369 | begin 370 | ENFORCE_STATE(state, CONNECTION_STATE_IDLE); 371 | state.channel_max := channel_max; 372 | state.frame_max := frame_max; 373 | state.heart_beat := heartbeat; 374 | if 0 > state.heart_beat then 375 | state.heart_beat := 0; 376 | 377 | res := amqp_time_s_from_now(state.next_send_heartbeat, state.heartbeat); 378 | if Int(AMQP_STATUS_OK) <> res then 379 | Exit(res); 380 | 381 | res := amqp_time_s_from_now(state.next_recv_heartbeat, 382 | amqp_heartbeat_recv(state)); 383 | if Int(AMQP_STATUS_OK) <> res then 384 | Exit(res); 385 | 386 | state.outbound_buffer.len := frame_max; 387 | //newbuf := realloc(state.outbound_buffer.bytes, frame_max); 388 | reallocMem(state.outbound_buffer.bytes, frame_max); 389 | newbuf := state.outbound_buffer.bytes; 390 | if newbuf = nil then 391 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 392 | 393 | //state.outbound_buffer.bytes := newbuf; 394 | Result := Int(AMQP_STATUS_OK); 395 | end; 396 | 397 | function amqp_destroy_connection( state : Pamqp_connection_state):integer; 398 | var 399 | status, 400 | i : integer; 401 | entry, 402 | todelete : Pamqp_pool_table_entry; 403 | begin 404 | status := Int(AMQP_STATUS_OK); 405 | if Assigned(state) then 406 | begin //++i 407 | for i := 0 to POOL_TABLE_SIZE -1 do 408 | begin 409 | //Inc(i); 410 | entry := state.pool_table[i]; 411 | while nil <> entry do 412 | begin 413 | todelete := entry; 414 | entry.pool.empty; 415 | entry := entry.next; 416 | free(todelete); 417 | end; 418 | end; 419 | free(state.outbound_buffer.bytes); 420 | 421 | free(state.sock_inbound_buffer.bytes); 422 | state.Fsocket.delete; 423 | state.properties_pool.empty; 424 | free(state); 425 | end; 426 | Result := status; 427 | end; 428 | 429 | 430 | procedure return_to_idle( state : Pamqp_connection_state); 431 | begin 432 | state.inbound_buffer.len := sizeof(state.header_buffer); 433 | state.inbound_buffer.bytes := @state.header_buffer; 434 | state.inbound_offset := 0; 435 | state.target_size := HEADER_SIZE; 436 | state.state := CONNECTION_STATE_IDLE; 437 | end; 438 | 439 | 440 | function consume_data(state : Pamqp_connection_state; out received_data : Tamqp_bytes):size_t; 441 | var 442 | bytes_consumed : size_t; 443 | begin 444 | { how much data is available and will fit? } 445 | bytes_consumed := state.target_size - state.inbound_offset; 446 | if received_data.len < bytes_consumed then 447 | bytes_consumed := received_data.len; 448 | 449 | //此句执行后导致state.Fsock不可访问 450 | memcpy(amqp_offset(state.inbound_buffer.bytes, state.inbound_offset), received_data.bytes, bytes_consumed); 451 | state.inbound_offset := state.inbound_offset + bytes_consumed; 452 | //received_data.bytes := 453 | Inc(received_data.bytes, bytes_consumed); 454 | received_data.len := received_data.len - bytes_consumed; 455 | Result := bytes_consumed; 456 | end; 457 | 458 | 459 | function amqp_release_buffers_ok( state : Pamqp_connection_state):amqp_boolean_t; 460 | begin 461 | if (state.state = CONNECTION_STATE_IDLE) then 462 | Result := 1 463 | else 464 | Result := 0; 465 | end; 466 | 467 | 468 | procedure amqp_release_buffers( state : Pamqp_connection_state); 469 | var 470 | i : integer; 471 | Lentry : Pamqp_pool_table_entry; 472 | begin 473 | ENFORCE_STATE(state, CONNECTION_STATE_IDLE); 474 | for i := 0 to POOL_TABLE_SIZE-1 do 475 | begin 476 | Lentry := state.pool_table[i]; 477 | While nil <> Lentry do 478 | begin 479 | amqp_maybe_release_buffers_on_channel(state, Lentry.channel); 480 | Lentry := Lentry.next; 481 | end; 482 | end; 483 | end; 484 | 485 | procedure amqp_maybe_release_buffers( state : Pamqp_connection_state); 486 | begin 487 | if amqp_release_buffers_ok(state) > 0 then 488 | amqp_release_buffers(state); 489 | 490 | end; 491 | 492 | 493 | procedure amqp_maybe_release_buffers_on_channel( state : Pamqp_connection_state; channel : amqp_channel_t); 494 | var 495 | queued_link : Pamqp_link; 496 | pool : Pamqp_pool; 497 | frame : Pamqp_frame; 498 | begin 499 | if CONNECTION_STATE_IDLE <> state.state then 500 | exit; 501 | 502 | queued_link := state.first_queued_frame; 503 | while nil <> queued_link do 504 | begin 505 | frame := queued_link.data; 506 | if channel = frame.channel then 507 | Exit; 508 | 509 | queued_link := queued_link.next; 510 | end; 511 | 512 | pool := state.get_channel_pool(channel); 513 | if pool <> nil then 514 | pool.recycle; 515 | 516 | end; 517 | 518 | 519 | function amqp_frame_to_bytes(const Aframe : Tamqp_frame; Abuffer : Tamqp_bytes; 520 | out Aencoded : Tamqp_bytes):integer; 521 | var 522 | Lout_frame : PAMQPChar; 523 | Lout_frame_len : size_t; 524 | Lres ,Level : integer; 525 | Lproperties_encoded, 526 | Lmethod_encoded : Tamqp_bytes; 527 | Lbody : Tamqp_bytes; 528 | 529 | begin 530 | Inc(gLevel); 531 | Level := gLevel; 532 | Lout_frame := Abuffer.bytes; 533 | amqp_e8(Aframe.frame_type, amqp_offset(Lout_frame, 0)); 534 | amqp_e16(Aframe.channel, amqp_offset(Lout_frame, 1)); 535 | case Aframe.frame_type of 536 | AMQP_FRAME_BODY: 537 | begin 538 | {$IFDEF _DEBUG_} 539 | DebugOut(Level, ' frame_type = AMQP_FRAME_BODY'); 540 | {$ENDIF} 541 | 542 | Lbody := Aframe.payload.body_fragment; 543 | memcpy(amqp_offset(Lout_frame, HEADER_SIZE), Lbody.bytes, Lbody.len); 544 | Lout_frame_len := Lbody.len; 545 | 546 | end; 547 | 548 | AMQP_FRAME_METHOD: 549 | begin 550 | {$IFDEF _DEBUG_} 551 | DebugOut(Level, ' frame_type = AMQP_FRAME_METHOD'); 552 | {$ENDIF} 553 | amqp_e32(Aframe.payload.method.id, amqp_offset(Lout_frame, HEADER_SIZE)); 554 | Lmethod_encoded.bytes := amqp_offset(Lout_frame, HEADER_SIZE + 4); 555 | Lmethod_encoded.len := Abuffer.len - HEADER_SIZE - 4 - FOOTER_SIZE; 556 | Lres := amqp_encode_method(Aframe.payload.method.id, 557 | Aframe.payload.method.decoded, Lmethod_encoded); 558 | if Lres < 0 then 559 | Exit(Lres); 560 | 561 | Lout_frame_len := Lres + 4; 562 | 563 | end; 564 | 565 | AMQP_FRAME_HEADER: 566 | begin 567 | {$IFDEF _DEBUG_} 568 | DebugOut(Level, ' frame_type = AMQP_FRAME_HEADER'); 569 | {$ENDIF} 570 | amqp_e16(Aframe.payload.properties.class_id, 571 | amqp_offset(Lout_frame, HEADER_SIZE)); 572 | amqp_e16(0, amqp_offset(Lout_frame, HEADER_SIZE + 2)); { 'weight' } 573 | amqp_e64(Aframe.payload.properties.body_size, 574 | amqp_offset(Lout_frame, HEADER_SIZE + 4)); 575 | Lproperties_encoded.bytes := amqp_offset(Lout_frame, HEADER_SIZE + 12); 576 | Lproperties_encoded.len := Abuffer.len - HEADER_SIZE - 12 - FOOTER_SIZE; 577 | Lres := amqp_encode_properties(Aframe.payload.properties.class_id, 578 | Aframe.payload.properties.decoded, 579 | Lproperties_encoded); 580 | if Lres < 0 then 581 | Exit(Lres); 582 | 583 | Lout_frame_len := Lres + 12; 584 | 585 | end; 586 | AMQP_FRAME_HEARTBEAT: 587 | begin 588 | {$IFDEF _DEBUG_} 589 | DebugOut(Level, ' frame_type = AMQP_FRAME_HEARTBEAT'); 590 | {$ENDIF} 591 | Lout_frame_len := 0; 592 | end; 593 | 594 | else 595 | Exit(Int(AMQP_STATUS_INVALID_PARAMETER)); 596 | end; 597 | 598 | amqp_e32(uint32_t(Lout_frame_len), amqp_offset(Lout_frame, 3)); 599 | amqp_e8(AMQP_FRAME_END, amqp_offset(Lout_frame, HEADER_SIZE + Lout_frame_len)); 600 | Aencoded.bytes := Lout_frame; 601 | Aencoded.len := Lout_frame_len + HEADER_SIZE + FOOTER_SIZE; 602 | Result := Int(AMQP_STATUS_OK); 603 | end; 604 | 605 | 606 | function amqp_send_frame(Astate : Pamqp_connection_state;const Aframe : Pamqp_frame):integer; 607 | begin 608 | Result := amqp_send_frame_inner(Astate, Aframe^, Int(AMQP_SF_NONE), Tamqp_time.infinite); 609 | end; 610 | 611 | initialization 612 | 613 | 614 | end. 615 | -------------------------------------------------------------------------------- /amqp.consumer.pas: -------------------------------------------------------------------------------- 1 | unit amqp.consumer; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | {$INCLUDE config.inc} 8 | interface 9 | 10 | uses {$IFNDEF FPC} 11 | {$IFDEF _WIN32} 12 | Net.Winsock2, 13 | {$ELSE} 14 | Net.SocketAPI, 15 | {$ENDIF} 16 | {$ELSE} 17 | Winsock2, 18 | {$ENDIF} 19 | amqp.mem, amqp.table, amqp.socket, AMQP.Types; 20 | 21 | function amqp_consume_message(Astate : Pamqp_connection_state; 22 | out Aenvelope : Tamqp_envelope; 23 | const Atimeout: Ptimeval; 24 | Aflags: int ):Tamqp_rpc_reply; 25 | 26 | function amqp_read_message(state : Pamqp_connection_state; 27 | channel : amqp_channel_t; 28 | out Amessage : Tamqp_message; 29 | flags: int):Tamqp_rpc_reply; 30 | function amqp_basic_consume( state : Pamqp_connection_state; 31 | channel : amqp_channel_t; 32 | queue, consumer_tag : Tamqp_bytes; 33 | no_local, no_ack, exclusive : amqp_boolean_t; 34 | arguments : Tamqp_table): Pamqp_basic_consume_ok; 35 | implementation 36 | 37 | function amqp_basic_consume( state : Pamqp_connection_state; 38 | channel : amqp_channel_t; 39 | queue, consumer_tag : Tamqp_bytes; 40 | no_local, no_ack, exclusive : amqp_boolean_t; 41 | arguments : Tamqp_table): Pamqp_basic_consume_ok; 42 | var 43 | req : Tamqp_basic_consume; 44 | begin 45 | req.ticket := 0; 46 | req.queue := queue; 47 | req.consumer_tag := consumer_tag; 48 | req.no_local := no_local; 49 | req.no_ack := no_ack; 50 | req.exclusive := exclusive; 51 | req.nowait := 0; 52 | req.arguments := arguments; 53 | Result := amqp_simple_rpc_decoded(state, channel, AMQP_BASIC_CONSUME_METHOD, 54 | AMQP_BASIC_CONSUME_OK_METHOD, @req); 55 | end; 56 | 57 | function amqp_consume_message(Astate : Pamqp_connection_state; 58 | out Aenvelope : Tamqp_envelope; 59 | const Atimeout: Ptimeval; Aflags: int):Tamqp_rpc_reply; 60 | var 61 | res : integer; 62 | Lframe : Tamqp_frame; 63 | delivery_method : Pamqp_basic_deliver; 64 | ret : Tamqp_rpc_reply; 65 | label error_out1; 66 | label error_out2; 67 | begin 68 | memset(ret, 0, sizeof(ret)); 69 | memset(Aenvelope, 0, sizeof(Tamqp_envelope)); 70 | res := amqp_simple_wait_frame_noblock(Astate, Lframe, Atimeout); 71 | if Int(AMQP_STATUS_OK) <> res then 72 | begin 73 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 74 | ret.library_error := res; 75 | goto error_out1; 76 | end; 77 | 78 | if (AMQP_FRAME_METHOD <> Lframe.frame_type) or 79 | (AMQP_BASIC_DELIVER_METHOD <> Lframe.payload.method.id) then 80 | begin 81 | amqp_put_back_frame(Astate, @Lframe); 82 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 83 | ret.library_error := Int(AMQP_STATUS_UNEXPECTED_STATE); 84 | goto error_out1; 85 | end; 86 | 87 | delivery_method := Pamqp_basic_deliver(Lframe.payload.method.decoded); 88 | Aenvelope.channel := Lframe.channel; 89 | Aenvelope.consumer_tag := (@delivery_method.consumer_tag); 90 | Aenvelope.exchange := (@delivery_method.exchange); 91 | Aenvelope.routing_key := (@delivery_method.routing_key); 92 | 93 | Aenvelope.delivery_tag := delivery_method.delivery_tag; 94 | Aenvelope.redelivered := delivery_method.redelivered; 95 | if (Aenvelope.consumer_tag.malloc_dup_failed > 0) or 96 | (Aenvelope.exchange.malloc_dup_failed > 0) or 97 | (Aenvelope.routing_key.malloc_dup_failed > 0) then 98 | begin 99 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 100 | ret.library_error := Int(AMQP_STATUS_NO_MEMORY); 101 | goto error_out2; 102 | end; 103 | 104 | ret := amqp_read_message(Astate, Aenvelope.channel, Aenvelope.message, 0); 105 | if AMQP_RESPONSE_NORMAL <> ret.reply_type then 106 | begin 107 | goto error_out2; 108 | end; 109 | 110 | ret.reply_type := AMQP_RESPONSE_NORMAL; 111 | Exit(ret); 112 | 113 | error_out2: 114 | Aenvelope.routing_key.Destroy; 115 | Aenvelope.exchange.Destroy; 116 | Aenvelope.consumer_tag.Destroy; 117 | error_out1: 118 | Result := ret; 119 | end; 120 | 121 | 122 | function amqp_read_message(state : Pamqp_connection_state; 123 | channel : amqp_channel_t; 124 | out Amessage : Tamqp_message; flags: int):Tamqp_rpc_reply; 125 | var 126 | frame : Tamqp_frame; 127 | ret : Tamqp_rpc_reply; 128 | body_read : size_t; 129 | body_read_ptr : PAMQPChar; 130 | res : integer; 131 | label error_out1; 132 | label error_out2; 133 | label error_out3; 134 | begin 135 | memset(ret, 0, sizeof(ret)); 136 | memset(Amessage, 0, sizeof( Tamqp_message)); 137 | res := amqp_simple_wait_frame_on_channel(state, channel, frame); 138 | if Int(AMQP_STATUS_OK) <> res then 139 | begin 140 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 141 | ret.library_error := res; 142 | goto error_out1; 143 | end; 144 | 145 | if frame.frame_type <> AMQP_FRAME_HEADER then 146 | begin 147 | if (AMQP_FRAME_METHOD = frame.frame_type) and 148 | ( (AMQP_CHANNEL_CLOSE_METHOD = frame.payload.method.id) or 149 | (AMQP_CONNECTION_CLOSE_METHOD = frame.payload.method.id) ) then 150 | begin 151 | ret.reply_type := AMQP_RESPONSE_SERVER_EXCEPTION; 152 | ret.reply := frame.payload.method; 153 | end 154 | else 155 | begin 156 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 157 | ret.library_error := Int(AMQP_STATUS_UNEXPECTED_STATE); 158 | amqp_put_back_frame(state, @frame); 159 | end; 160 | goto error_out1; 161 | end; 162 | 163 | //init_amqp_pool(@Amessage.pool, 4096); 164 | Amessage.pool.Create(4096); 165 | res := Pamqp_basic_properties(frame.payload.properties.decoded)^.clone( 166 | Amessage.properties, @Amessage.pool); 167 | if Int(AMQP_STATUS_OK) <> res then 168 | begin 169 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 170 | ret.library_error := res; 171 | goto error_out3; 172 | end; 173 | 174 | if 0 = frame.payload.properties.body_size then 175 | begin 176 | Amessage.body := amqp_empty_bytes; 177 | end 178 | else 179 | begin 180 | if SIZE_MAX < frame.payload.properties.body_size then 181 | begin 182 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 183 | ret.library_error := Int(AMQP_STATUS_NO_MEMORY); 184 | goto error_out1; 185 | end; 186 | Amessage.body := Tamqp_bytes.Create(size_t(frame.payload.properties.body_size)); 187 | if nil = Amessage.body.bytes then 188 | begin 189 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 190 | ret.library_error := Int(AMQP_STATUS_NO_MEMORY); 191 | goto error_out1; 192 | end; 193 | end; 194 | 195 | body_read := 0; 196 | body_read_ptr := Amessage.body.bytes; 197 | while body_read < Amessage.body.len do 198 | begin 199 | res := amqp_simple_wait_frame_on_channel(state, channel, &frame); 200 | if Int(AMQP_STATUS_OK) <> res then 201 | begin 202 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 203 | ret.library_error := res; 204 | goto error_out2; 205 | end; 206 | 207 | if AMQP_FRAME_BODY <> frame.frame_type then 208 | begin 209 | if (AMQP_FRAME_METHOD = frame.frame_type ) and 210 | ( (AMQP_CHANNEL_CLOSE_METHOD = frame.payload.method.id) or 211 | (AMQP_CONNECTION_CLOSE_METHOD = frame.payload.method.id)) then 212 | begin 213 | ret.reply_type := AMQP_RESPONSE_SERVER_EXCEPTION; 214 | ret.reply := frame.payload.method; 215 | end 216 | else 217 | begin 218 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 219 | ret.library_error := Int(AMQP_STATUS_BAD_AMQP_DATA); 220 | end; 221 | goto error_out2; 222 | end; 223 | 224 | if body_read + frame.payload.body_fragment.len > Amessage.body.len then 225 | begin 226 | ret.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 227 | ret.library_error := Int(AMQP_STATUS_BAD_AMQP_DATA); 228 | goto error_out2; 229 | end; 230 | memcpy(body_read_ptr, frame.payload.body_fragment.bytes, 231 | frame.payload.body_fragment.len); 232 | body_read := body_read + frame.payload.body_fragment.len; 233 | body_read_ptr := body_read_ptr + frame.payload.body_fragment.len; 234 | end; 235 | ret.reply_type := AMQP_RESPONSE_NORMAL; 236 | Exit(ret); 237 | 238 | error_out2: 239 | Amessage.body.Destroy; 240 | 241 | error_out3: 242 | Amessage.pool.empty; 243 | 244 | error_out1: 245 | Result := ret; 246 | end; 247 | 248 | end. 249 | 250 | 251 | -------------------------------------------------------------------------------- /amqp.mem.pas: -------------------------------------------------------------------------------- 1 | unit amqp.mem; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | {$INCLUDE config.inc} 8 | interface 9 | uses {$IFDEF FPC}SysUtils,{$Else} System.SysUtils, {$ENDIF} AMQP.Types; 10 | 11 | 12 | function amqp_cstring_bytes( const cstr: PAnsiChar):Tamqp_bytes; 13 | 14 | procedure amqp_dump( const buffer:Pointer; len : size_t); 15 | 16 | implementation 17 | 18 | 19 | function isprint( c : byte):byte; 20 | begin 21 | if (c >= $20 ) and (c <= $7e) then 22 | Exit(1); 23 | Result := 0; 24 | end; 25 | 26 | procedure dump_row(count : longint; numinrow : integer;chs : Pinteger); 27 | var 28 | i : integer; 29 | begin 30 | {$PointerMath on} 31 | write(format('%.8x:',[count - numinrow])); 32 | if numinrow > 0 then 33 | begin 34 | for i := 0 to numinrow-1 do 35 | begin 36 | if i = 8 then 37 | Write(':'); 38 | 39 | write(format(' %.2x',[chs[i]])); 40 | end; 41 | for i := numinrow to 15 do 42 | begin 43 | if i = 8 then 44 | Write(':'); 45 | 46 | Write(''); 47 | end; 48 | Write(''); 49 | 50 | for i := 0 to numinrow-1 do 51 | begin 52 | if isprint(chs[i])>0 then 53 | write(format('%s',[Chr(chs[i])])) 54 | else 55 | Write('.'); 56 | 57 | end; 58 | end; 59 | Writeln; 60 | {$PointerMath off} 61 | end; 62 | 63 | function rows_eq(a, b : Pinteger):Boolean; 64 | var 65 | i : integer; 66 | begin 67 | {$PointerMath on} 68 | for i := 0 to 15 do 69 | if a[i] <> b[i] then 70 | Exit(False); 71 | 72 | Result := True; 73 | {$PointerMath off} 74 | end; 75 | 76 | procedure amqp_dump( const buffer:Pointer; len : size_t); 77 | var 78 | buf : Pbyte; 79 | count : longint; 80 | numinrow : integer; 81 | chs, 82 | oldchs : array[0..15] of integer; 83 | showed_dots : integer; 84 | i : size_t; 85 | ch, 86 | j : integer; 87 | begin 88 | buf := PByte(buffer); 89 | count := 0; 90 | numinrow := 0; 91 | 92 | showed_dots := 0; 93 | for i := 0 to len-1 do 94 | begin 95 | ch := buf[i]; 96 | if numinrow = 16 then 97 | begin 98 | if rows_eq(@oldchs, @chs) then 99 | begin 100 | if 0>= showed_dots then 101 | begin 102 | showed_dots := 1; 103 | Writeln( 104 | ' .. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..\n'); 105 | end; 106 | end 107 | else 108 | begin 109 | showed_dots := 0; 110 | dump_row(count, numinrow, @chs); 111 | end; 112 | for j := 0 to 15 do 113 | oldchs[j] := chs[j]; 114 | 115 | numinrow := 0; 116 | end; 117 | Inc(count); 118 | chs[numinrow] := ch; 119 | Inc(numinrow); 120 | end; 121 | dump_row(count, numinrow, @chs); 122 | if numinrow <> 0 then begin 123 | writeln(format('%.8x:',[count])); 124 | end; 125 | end; 126 | 127 | { replaced by Tamqp_bytes.Implicit 128 | function amqp_bytes_malloc_dup( src : Tamqp_bytes): Tamqp_bytes; 129 | begin 130 | result.len := src.len; 131 | result.bytes := malloc(src.len); 132 | if result.bytes <> nil then begin 133 | memcpy(result.bytes, src.bytes, src.len); 134 | end; 135 | 136 | end; } 137 | 138 | function amqp_cstring_bytes( const cstr: PAnsiChar):Tamqp_bytes; 139 | begin 140 | result.len := Length(cstr); 141 | result.bytes := PAMQPChar(cstr); 142 | end; 143 | 144 | initialization 145 | 146 | end. 147 | -------------------------------------------------------------------------------- /amqp.privt.pas: -------------------------------------------------------------------------------- 1 | unit amqp.privt; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | interface 8 | uses AMQP.Types; 9 | 10 | type 11 | Tbint = record 12 | case integer of 13 | 0: (i: uint32_t); 14 | 1: (c: array[0..3] of Byte); 15 | 16 | end; 17 | 18 | 19 | function is_bigendian: bool; 20 | function amqp_offset(data: PByte; offset : size_t): PByte; 21 | function amqp_rpc_reply_error( status : Tamqp_status_enum):Tamqp_rpc_reply; 22 | 23 | procedure amqp_e8(Aval : uint8_t; Adata: Pointer); 24 | procedure amqp_e16(Aval : uint16_t;Adata: Pointer); 25 | procedure amqp_e32(val : uint32_t;data: Pointer); 26 | procedure amqp_e64(val : uint64_t; data: Pointer); 27 | 28 | function amqp_encode_n(bits: Byte; encoded : Tamqp_bytes;offset : Psize_t; input : uint64_t):integer; 29 | function amqp_encode_bytes(encoded : Tamqp_bytes;offset : Psize_t; input : Tamqp_bytes):integer; 30 | 31 | function amqp_d8(data: Pointer):uint8_t; 32 | function amqp_d16(data: Pointer):uint16_t; 33 | function amqp_d32(data: Pointer):uint32_t; 34 | function amqp_d64(data: Pointer):uint64_t; 35 | 36 | function amqp_decode_8(encoded: Tamqp_bytes; offset: Psize_t; out output: uint8_t): int; 37 | function amqp_decode_16(encoded: Tamqp_bytes; offset: Psize_t; out output: uint16_t): int; 38 | function amqp_decode_32(encoded: Tamqp_bytes; offset: Psize_t; out output: uint32_t): int; 39 | function amqp_decode_64(encoded: Tamqp_bytes; offset: Psize_t; out output: uint64_t): int; 40 | function amqp_decode_bytes(encoded : Tamqp_bytes;offset : Psize_t; out output : Tamqp_bytes; len : size_t):integer; 41 | 42 | 43 | 44 | implementation 45 | 46 | function amqp_offset(data: PByte; offset : size_t): PByte; 47 | begin 48 | Inc(data , offset); 49 | Result := data; 50 | end; 51 | 52 | function amqp_rpc_reply_error( status : Tamqp_status_enum):Tamqp_rpc_reply; 53 | var 54 | reply : Tamqp_rpc_reply; 55 | begin 56 | reply.reply_type := AMQP_RESPONSE_LIBRARY_EXCEPTION; 57 | reply.library_error := Int(status); 58 | Result := reply; 59 | end; 60 | 61 | function amqp_decode_bytes(encoded : Tamqp_bytes;offset : Psize_t; out output : Tamqp_bytes; len : size_t):integer; 62 | var 63 | o : size_t; 64 | begin 65 | o := offset^; 66 | offset^ := o + len; 67 | if offset^ <= encoded.len then 68 | begin 69 | output.bytes := amqp_offset(encoded.bytes, o); 70 | output.len := len; 71 | Exit(1); 72 | end 73 | else 74 | Exit(0); 75 | 76 | end; 77 | 78 | function amqp_d32(data: Pointer):uint32_t; 79 | var 80 | val : uint32_t; 81 | begin 82 | memcpy(@val, data, sizeof(val)); 83 | if not is_bigendian then 84 | begin 85 | val := ((val and $FF000000) shr 24) or ((val and $00FF0000) shr 8) or 86 | ((val and $0000FF00) shl 8) or ((val and $000000FF) shl 24); 87 | end; 88 | Result := val; 89 | end; 90 | 91 | procedure amqp_e64(val : uint64; data: Pointer); 92 | begin 93 | if not is_bigendian then 94 | begin 95 | val := ((val and 18374686479671623680) shr 56) or 96 | ((val and 71776119061217280) shr 40) or 97 | ((val and 280375465082880) shr 24) or 98 | ((val and 1095216660480) shr 8 ) or 99 | ((val and 4278190080) shl 8 ) or 100 | ((val and 16711680) shl 24) or 101 | ((val and 65280) shl 40) or 102 | ((val and 255) shl 56); 103 | end; 104 | memcpy(data, @val, sizeof(val)); 105 | end; 106 | 107 | function amqp_d64(data: Pointer):uint64_t; 108 | var 109 | val : uint64_t; 110 | begin 111 | memcpy(@val, data, sizeof(val)); 112 | if not is_bigendian then 113 | begin 114 | val := ((val and 18374686479671623680) shr 56) or 115 | ((val and 71776119061217280) shr 40) or 116 | ((val and 280375465082880) shr 24) or 117 | ((val and 1095216660480) shr 8 ) or 118 | ((val and 4278190080) shl 8 ) or 119 | ((val and 16711680) shl 24) or 120 | ((val and 65280) shl 40) or 121 | ((val and 255) shl 56); 122 | end; 123 | Result := val; 124 | end; 125 | 126 | 127 | function amqp_d16(data: Pointer):uint16_t; 128 | var 129 | val : uint16_t; 130 | begin 131 | memcpy(@val, data, sizeof(val)); 132 | if not is_bigendian then 133 | val := ((val and $FF00) shr 8) or ((val and $00FF) shl 8); 134 | 135 | Result := val; 136 | end; 137 | 138 | 139 | function amqp_d8(data: Pointer):uint8_t; 140 | var 141 | val : uint8_t; 142 | begin 143 | memcpy(@val, data, sizeof(val)); 144 | Result := val; 145 | end; 146 | 147 | 148 | function amqp_encode_bytes(encoded : Tamqp_bytes;offset : Psize_t; input : Tamqp_bytes):integer; 149 | var 150 | o : size_t; 151 | begin 152 | o := offset^; 153 | { The memcpy below has undefined behavior if the input is nil. It is valid 154 | * for a 0-length amqp_bytes_t to have .bytes = nil. Thus we should check 155 | * before encoding. 156 | } 157 | if input.len = 0 then 158 | Exit(1); 159 | 160 | 161 | offset^ := o + input.len; 162 | if offset^ <= encoded.len then 163 | begin 164 | memcpy(amqp_offset(encoded.bytes, o), input.bytes, input.len); 165 | Exit(1); 166 | end 167 | else 168 | Exit(0); 169 | 170 | end; 171 | 172 | function amqp_decode_8(encoded: Tamqp_bytes; offset: Psize_t; out output: uint8_t): int; 173 | var 174 | o : size_t; 175 | begin 176 | o := offset^; 177 | offset^ := o + 1;//Round(8 / 8); 178 | if offset^ <= encoded.len then 179 | begin 180 | output := amqp_d8(amqp_offset(encoded.bytes, o)); 181 | Exit(1); 182 | end; 183 | Result := 0; 184 | end; 185 | 186 | function amqp_decode_16(encoded: Tamqp_bytes; offset: Psize_t; out output: uint16_t): int; 187 | var 188 | o : size_t; 189 | begin 190 | o := offset^; 191 | offset^ := o + 2;//Round(16 / 8); 192 | if offset^ <= encoded.len then 193 | begin 194 | output := amqp_d16(amqp_offset(encoded.bytes, o)); 195 | Exit(1); 196 | end; 197 | Result := 0; 198 | end; 199 | 200 | function amqp_decode_32(encoded: Tamqp_bytes; offset: Psize_t; out output: uint32_t): int; 201 | var 202 | o : size_t; 203 | begin 204 | o := offset^; 205 | offset^ := o + 32 DIV 8; 206 | if offset^ <= encoded.len then 207 | begin 208 | output := amqp_d32(amqp_offset(encoded.bytes, o)); 209 | Exit(1); 210 | end; 211 | Result := 0; 212 | end; 213 | 214 | function amqp_decode_64(encoded: Tamqp_bytes; offset: Psize_t; out output: uint64_t): int; 215 | var 216 | o : size_t; 217 | begin 218 | o := offset^; 219 | offset^ := o + 8;//Round(64 / 8); 220 | if offset^ <= encoded.len then 221 | begin 222 | output := amqp_d64(amqp_offset(encoded.bytes, o)); 223 | Exit(1); 224 | end; 225 | Result := 0; 226 | end; 227 | 228 | function amqp_encode_n(bits: Byte; encoded : Tamqp_bytes;offset : Psize_t; input : uint64_t):integer; 229 | var 230 | o : size_t; 231 | begin 232 | 233 | o := offset^; 234 | offset^ := o + bits div 8; 235 | if offset^ <= encoded.len then 236 | begin 237 | case bits of 238 | 8: 239 | amqp_e8(input, amqp_offset(encoded.bytes, o)); 240 | 16: 241 | amqp_e16(input, amqp_offset(encoded.bytes, o)); 242 | 32: 243 | amqp_e32(input, amqp_offset(encoded.bytes, o)); 244 | 64: 245 | amqp_e64(input, amqp_offset(encoded.bytes, o)); 246 | end; 247 | Exit( 1); 248 | end; 249 | 250 | Exit( 0); 251 | end; 252 | 253 | procedure amqp_e8(Aval : uint8_t; Adata: Pointer); 254 | begin 255 | memcpy(Adata, @Aval, sizeof(Aval)); 256 | end; 257 | 258 | procedure amqp_e16(Aval : uint16;Adata: Pointer); 259 | begin 260 | if not is_bigendian() then 261 | begin 262 | Aval := ((Aval and uint32_t($FF00)) shr uint32_t(8)) or ((Aval and uint32_t($00FF)) shl uint32_t(8)); 263 | end; 264 | memcpy(Adata, @Aval, sizeof(Aval)); 265 | end; 266 | 267 | procedure amqp_e32(val : uint32;data: Pointer); 268 | begin 269 | if not is_bigendian then 270 | begin 271 | val := ((val and UInt32($FF000000)) shr UInt32(24)) or ((val and UInt32($00FF0000)) shr UInt32(8)) or 272 | ((val and UInt32($0000FF00)) shl UInt32(8)) or ((val and UInt32($000000FF)) shl UInt32(24)); 273 | end; 274 | memcpy(data, @val, sizeof(val)); 275 | end; 276 | 277 | 278 | 279 | function is_bigendian: bool; 280 | var 281 | bint: Tbint; 282 | begin 283 | bint.i := $01020304; 284 | Result := Ord(bint.c[0]) = 1; 285 | end; 286 | 287 | 288 | initialization 289 | 290 | end. 291 | -------------------------------------------------------------------------------- /amqp.table.pas: -------------------------------------------------------------------------------- 1 | unit amqp.table; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | interface 8 | uses AMQP.Types, amqp.privt, amqp.mem; 9 | 10 | 11 | function amqp_decode_table(encoded : Tamqp_bytes; pool : Pamqp_pool; out output : Tamqp_table; offset : Psize_t):integer; 12 | function amqp_encode_table(encoded : Tamqp_bytes; input : Pamqp_table; offset : Psize_t):integer; 13 | 14 | function amqp_encode_field_value(encoded : Tamqp_bytes;const entry : Pamqp_field_value; offset : Psize_t):integer; 15 | function amqp_decode_field_value(encoded : Tamqp_bytes; pool : Pamqp_pool; out entry : Tamqp_field_value; offset : Psize_t):integer; 16 | //function amqp_table_get_entry_by_key(const table : Pamqp_table;const key : Tamqp_bytes):Pamqp_table_entry; 17 | function amqp_decode_array(encoded : Tamqp_bytes; pool : Pamqp_pool; out output : Tamqp_array; offset : Psize_t):integer; 18 | //function amqp_table_clone(const original: Tamqp_table;out clone : Tamqp_table; pool : Pamqp_pool):integer; 19 | //function amqp_table_entry_clone(const original: Pamqp_table_entry; clone : Pamqp_table_entry; pool : Pamqp_pool):integer; 20 | //function amqp_field_value_clone(const original: Pamqp_field_value; clone : Pamqp_field_value; pool : Pamqp_pool):integer; 21 | 22 | const 23 | INITIAL_ARRAY_SIZE =16; 24 | INITIAL_TABLE_SIZE =16; 25 | 26 | implementation 27 | 28 | 29 | function amqp_decode_array(encoded : Tamqp_bytes; pool : Pamqp_pool; 30 | out output : Tamqp_array; offset : Psize_t):integer; 31 | var 32 | arraysize : uint32; 33 | num_entries, 34 | allocated_entries : integer; 35 | entries : Pamqp_field_value; 36 | limit : size_t; 37 | res : integer; 38 | newentries : Pointer; 39 | label _out; 40 | begin 41 | {$POINTERMATH ON} 42 | num_entries := 0; 43 | allocated_entries := INITIAL_ARRAY_SIZE; 44 | if 0= amqp_decode_32(encoded, offset, &arraysize ) then 45 | begin 46 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 47 | end; 48 | if arraysize + offset^ > encoded.len then 49 | begin 50 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 51 | end; 52 | entries := allocMem(allocated_entries * sizeof(Tamqp_field_value)); 53 | if entries = nil then 54 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 55 | 56 | limit := offset^ + arraysize; 57 | while offset^ < limit do 58 | begin 59 | if num_entries >= allocated_entries then 60 | begin 61 | allocated_entries := allocated_entries * 2; 62 | reallocMem(entries, allocated_entries * sizeof(Tamqp_field_value)); 63 | res := Int(AMQP_STATUS_NO_MEMORY); 64 | if entries = nil then 65 | goto _out; 66 | end; 67 | res := amqp_decode_field_value(encoded, pool, entries[num_entries], offset); 68 | if res < 0 then 69 | goto _out; 70 | Inc(num_entries); 71 | end; 72 | output.num_entries := num_entries; 73 | output.entries := pool.alloc( num_entries * sizeof(Tamqp_field_value)); 74 | { nil is legitimate if we requested a zero-length block. } 75 | if output.entries = nil then 76 | begin 77 | if num_entries = 0 then 78 | res := Int(AMQP_STATUS_OK) 79 | else 80 | res := Int(AMQP_STATUS_NO_MEMORY); 81 | 82 | end; 83 | memcpy(output.entries, entries, num_entries * sizeof(Tamqp_field_value)); 84 | res := Int(AMQP_STATUS_OK); 85 | _out: 86 | freeMem(entries); 87 | Result := res; 88 | {$POINTERMATH OFF} 89 | end; 90 | 91 | function amqp_decode_field_value(encoded : Tamqp_bytes;pool : Pamqp_pool; 92 | out entry : Tamqp_field_value; offset : Psize_t):integer; 93 | var 94 | res : integer; 95 | len : uint32; 96 | label _out; 97 | 98 | procedure SIMPLE_FIELD_DECODER(bits: Byte; dest: string); 99 | var 100 | Lval8: uint8_t; 101 | Lval16: uint16_t; 102 | Lval32: uint32_t; 103 | Lval64: uint64_t; 104 | label _out; 105 | begin 106 | case bits of 107 | 8: 108 | begin 109 | if (0=amqp_decode_8(encoded, offset, Lval8)) then 110 | goto _out; 111 | if dest = 'i8' then 112 | entry.value.i8 := Lval8 113 | else 114 | if dest = 'boolean' then 115 | begin 116 | if Lval8 > 0 then 117 | entry.value.boolean := 1 118 | else 119 | entry.value.boolean := 0; 120 | end; 121 | end; 122 | 16: 123 | begin 124 | 125 | if (0=amqp_decode_16(encoded, offset, Lval16)) then 126 | goto _out; 127 | if dest = 'i16' then 128 | entry.value.i16 := Lval16; 129 | end; 130 | 32: 131 | begin 132 | 133 | if (0=amqp_decode_32(encoded, offset, Lval32)) then 134 | goto _out; 135 | if dest = 'i32' then 136 | entry.value.i32 := Lval32; 137 | end; 138 | 64: 139 | begin 140 | 141 | if (0=amqp_decode_64(encoded, offset, Lval64)) then 142 | goto _out; 143 | if dest = 'i64' then 144 | entry.value.i64 := Lval64 145 | end; 146 | 147 | end; 148 | 149 | _out: 150 | Result := res; 151 | end; 152 | 153 | procedure TRIVIAL_FIELD_DECODER(bits: byte); 154 | label _out; 155 | begin 156 | case bits of 157 | 8: 158 | if 0=amqp_decode_8(encoded, offset, entry.value.u8) then 159 | goto _out; 160 | 16: 161 | if 0=amqp_decode_16(encoded, offset, entry.value.u16) then 162 | goto _out; 163 | 32: 164 | if 0=amqp_decode_32(encoded, offset, entry.value.u32) then 165 | goto _out; 166 | end; 167 | 168 | _out: 169 | Result := res; 170 | end; 171 | 172 | begin 173 | res := Int(AMQP_STATUS_BAD_AMQP_DATA); 174 | if 0= amqp_decode_8(encoded, offset, entry.kind ) then 175 | goto _out; 176 | case entry.kind of 177 | Int(AMQP_FIELD_KIND_BOOLEAN): 178 | SIMPLE_FIELD_DECODER(8, 'boolean'); 179 | Int(AMQP_FIELD_KIND_I8): 180 | SIMPLE_FIELD_DECODER(8, 'i8'); 181 | Int(AMQP_FIELD_KIND_U8): 182 | TRIVIAL_FIELD_DECODER(8); 183 | Int(AMQP_FIELD_KIND_I16): 184 | SIMPLE_FIELD_DECODER(16, 'i16'); 185 | Int(AMQP_FIELD_KIND_U16): 186 | TRIVIAL_FIELD_DECODER(16); 187 | Int(AMQP_FIELD_KIND_I32): 188 | SIMPLE_FIELD_DECODER(32, 'i32'); 189 | Int(AMQP_FIELD_KIND_U32): 190 | TRIVIAL_FIELD_DECODER(32); 191 | Int(AMQP_FIELD_KIND_I64): 192 | SIMPLE_FIELD_DECODER(64, 'i64'); 193 | Int(AMQP_FIELD_KIND_U64): 194 | TRIVIAL_FIELD_DECODER(64); 195 | Int(AMQP_FIELD_KIND_F32): 196 | TRIVIAL_FIELD_DECODER(32); 197 | { and by punning, f32 magically gets the right value...! } 198 | Int(AMQP_FIELD_KIND_F64): 199 | TRIVIAL_FIELD_DECODER(64); 200 | { and by punning, f64 magically gets the right value...! } 201 | Int(AMQP_FIELD_KIND_DECIMAL): 202 | if (0= amqp_decode_8(encoded, offset, entry.value.decimal.decimals)) or 203 | (0= amqp_decode_32(encoded, offset, entry.value.decimal.value))then 204 | goto _out; 205 | 206 | Int(AMQP_FIELD_KIND_UTF8), 207 | { AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the 208 | same implementation, but different interpretations. } 209 | { fall through } 210 | Int(AMQP_FIELD_KIND_BYTES): 211 | begin 212 | if (0= amqp_decode_32(encoded, offset, &len)) or 213 | (0= amqp_decode_bytes(encoded, offset, entry.value.bytes, len)) then 214 | goto _out; 215 | 216 | end; 217 | Int(AMQP_FIELD_KIND_ARRAY): 218 | res := amqp_decode_array(encoded, pool, entry.value.&array, offset); 219 | Int(AMQP_FIELD_KIND_TIMESTAMP): 220 | TRIVIAL_FIELD_DECODER(64); 221 | Int(AMQP_FIELD_KIND_TABLE): 222 | res := amqp_decode_table(encoded, pool, entry.value.table, offset); 223 | Int(AMQP_FIELD_KIND_VOID): 224 | 225 | else goto _out; 226 | end; 227 | res := Int(AMQP_STATUS_OK); 228 | _out: 229 | Result := res; 230 | end; 231 | 232 | function amqp_decode_table(encoded : Tamqp_bytes; pool : Pamqp_pool; 233 | out output : Tamqp_table; offset : Psize_t):integer; 234 | var 235 | tablesize : uint32; 236 | num_entries : integer; 237 | entries : Pamqp_table_entry; 238 | allocated_entries : integer; 239 | limit : size_t; 240 | res : integer; 241 | keylen : byte; 242 | 243 | newentries : Pointer; 244 | label _out; 245 | begin 246 | {$POINTERMATH ON} 247 | num_entries := 0; 248 | allocated_entries := INITIAL_TABLE_SIZE; 249 | if 0= amqp_decode_32(encoded, offset, &tablesize )then 250 | begin 251 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 252 | end; 253 | if tablesize + offset^ > encoded.len then 254 | begin 255 | Exit(Int(AMQP_STATUS_BAD_AMQP_DATA)); 256 | end; 257 | entries := allocMem(allocated_entries * sizeof(Tamqp_table_entry)); 258 | if entries = nil then 259 | Exit(Int(AMQP_STATUS_NO_MEMORY)); 260 | 261 | limit := offset^ + tablesize; 262 | while offset^ < limit do 263 | begin 264 | res := Int(AMQP_STATUS_BAD_AMQP_DATA); 265 | if 0= amqp_decode_8(encoded, offset, &keylen )then 266 | goto _out; 267 | if num_entries >= allocated_entries then 268 | begin 269 | allocated_entries := allocated_entries * 2; 270 | reallocMem(entries, allocated_entries * sizeof(Tamqp_table_entry)); 271 | res := Int(AMQP_STATUS_NO_MEMORY); 272 | if entries = nil then 273 | goto _out; 274 | 275 | end; 276 | res := Int(AMQP_STATUS_BAD_AMQP_DATA); 277 | if 0= amqp_decode_bytes(encoded, offset, entries[num_entries].key, keylen) then 278 | goto _out; 279 | res := amqp_decode_field_value(encoded, pool, entries[num_entries].value,offset); 280 | if res < 0 then 281 | goto _out; 282 | Inc(num_entries); 283 | end; 284 | 285 | output.num_entries := num_entries; 286 | output.entries := pool.alloc( num_entries * sizeof(Tamqp_table_entry)); 287 | { nil is legitimate if we requested a zero-length block. } 288 | if output.entries = nil then 289 | begin 290 | if num_entries = 0 then 291 | res := Int(AMQP_STATUS_OK) 292 | else 293 | res := Int(AMQP_STATUS_NO_MEMORY); 294 | 295 | end; 296 | memcpy(output.entries, entries, num_entries * sizeof(Tamqp_table_entry)); 297 | res := Int(AMQP_STATUS_OK); 298 | 299 | _out: 300 | freemem(entries); 301 | Result := res; 302 | {$POINTERMATH OFF} 303 | end; 304 | 305 | function amqp_encode_array(encoded : Tamqp_bytes; input : Pamqp_array; offset : Psize_t):integer; 306 | var 307 | start : size_t; 308 | i, res : integer; 309 | label _out; 310 | begin 311 | {$POINTERMATH ON} 312 | start := offset^; 313 | offset^ := offset^ + 4; 314 | for i := 0 to input.num_entries-1 do 315 | begin 316 | res := amqp_encode_field_value(encoded, @input.entries[i], offset); 317 | if res < 0 then 318 | goto _out; 319 | end; 320 | 321 | if 0= amqp_encode_n(32, encoded, @start, uint32_t( offset^ - start - 4)) then 322 | begin 323 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 324 | goto _out; 325 | end; 326 | res := Integer(AMQP_STATUS_OK); 327 | _out: 328 | Result := res; 329 | {$POINTERMATH OFF} 330 | end; 331 | 332 | function amqp_encode_field_value(encoded : Tamqp_bytes;const entry : Pamqp_field_value; offset : Psize_t):integer; 333 | var 334 | res, value : integer; 335 | label _out; 336 | procedure FIELD_ENCODER(bits, val: Byte); 337 | begin 338 | if 0= amqp_encode_n(bits, encoded, offset, val) then 339 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 340 | end; 341 | 342 | begin 343 | res := Integer(AMQP_STATUS_BAD_AMQP_DATA); 344 | if 0= amqp_encode_n(8, encoded, offset, entry.kind) then 345 | goto _out; 346 | 347 | case entry.kind of 348 | uint8(AMQP_FIELD_KIND_BOOLEAN): 349 | begin 350 | if entry.value.boolean > 0 then 351 | value := 1 352 | else 353 | value := 0; 354 | FIELD_ENCODER(8, value); 355 | end; 356 | uint8(AMQP_FIELD_KIND_I8): 357 | FIELD_ENCODER(8, entry.value.i8); 358 | uint8(AMQP_FIELD_KIND_U8): 359 | FIELD_ENCODER(8, entry.value.u8); 360 | uint8(AMQP_FIELD_KIND_I16): 361 | FIELD_ENCODER(16, entry.value.i16); 362 | uint8(AMQP_FIELD_KIND_U16): 363 | FIELD_ENCODER(16, entry.value.u16); 364 | uint8(AMQP_FIELD_KIND_I32): 365 | FIELD_ENCODER(32, entry.value.i32); 366 | uint8(AMQP_FIELD_KIND_U32): 367 | FIELD_ENCODER(32, entry.value.u32); 368 | uint8(AMQP_FIELD_KIND_I64): 369 | FIELD_ENCODER(64, entry.value.i64); 370 | uint8(AMQP_FIELD_KIND_U64): 371 | FIELD_ENCODER(64, entry.value.u64); 372 | uint8(AMQP_FIELD_KIND_F32): 373 | { by punning, u32 magically gets the right value...! } 374 | FIELD_ENCODER(32, entry.value.u32); 375 | uint8(AMQP_FIELD_KIND_F64): 376 | { by punning, u64 magically gets the right value...! } 377 | FIELD_ENCODER(64, entry.value.u64); 378 | uint8(AMQP_FIELD_KIND_DECIMAL): 379 | begin 380 | if (0= amqp_encode_n(8, encoded, offset, entry.value.decimal.decimals)) or 381 | (0= amqp_encode_n(32, encoded, offset, entry.value.decimal.value)) then 382 | begin 383 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 384 | goto _out; 385 | end; 386 | end; 387 | 388 | uint8(AMQP_FIELD_KIND_UTF8), 389 | { AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the 390 | same implementation, but different interpretations. } 391 | { fall through } 392 | uint8(AMQP_FIELD_KIND_BYTES): 393 | begin 394 | if (0= amqp_encode_n(32, encoded, offset, uint32_t (entry.value.bytes.len))) or 395 | (0= amqp_encode_bytes(encoded, offset, entry.value.bytes)) then 396 | begin 397 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 398 | goto _out; 399 | end; 400 | end; 401 | uint8(AMQP_FIELD_KIND_ARRAY): 402 | begin 403 | res := amqp_encode_array(encoded, @entry.value.&array, offset); 404 | goto _out; 405 | end; 406 | uint8(AMQP_FIELD_KIND_TIMESTAMP): 407 | FIELD_ENCODER(64, entry.value.u64); 408 | uint8(AMQP_FIELD_KIND_TABLE): 409 | begin 410 | res := amqp_encode_table(encoded, @entry.value.table, offset); 411 | goto _out; 412 | end; 413 | uint8(AMQP_FIELD_KIND_VOID): 414 | begin 415 | // 416 | end; 417 | else 418 | res := Integer(AMQP_STATUS_INVALID_PARAMETER); 419 | end; 420 | res := Integer(AMQP_STATUS_OK); 421 | _out: 422 | Result := res; 423 | end; 424 | 425 | function amqp_encode_table(encoded : Tamqp_bytes; input : Pamqp_table; offset : Psize_t):integer; 426 | var 427 | start : size_t; 428 | i, res : integer; 429 | label _out; 430 | begin 431 | {$POINTERMATH ON} 432 | start := offset^; 433 | offset^ := offset^ + 4; 434 | for i := 0 to input.num_entries-1 do 435 | begin 436 | if 0= amqp_encode_n(8, encoded, offset, uint8_t(input.entries[i].key.len)) then 437 | begin 438 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 439 | goto _out; 440 | end; 441 | if 0= amqp_encode_bytes(encoded, offset, input.entries[i].key ) then 442 | begin 443 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 444 | goto _out; 445 | end; 446 | res := amqp_encode_field_value(encoded, @input.entries[i].value, offset); 447 | if res < 0 then 448 | goto _out; 449 | 450 | end; 451 | 452 | if 0= amqp_encode_n(32, encoded, @start, uint32_t( offset^ - start - 4)) then 453 | begin 454 | res := Integer(AMQP_STATUS_TABLE_TOO_BIG); 455 | goto _out; 456 | end; 457 | res := Integer(AMQP_STATUS_OK); 458 | _out: 459 | Result := res; 460 | {$POINTERMATH OFF} 461 | end; 462 | 463 | initialization 464 | 465 | end. 466 | -------------------------------------------------------------------------------- /amqp.tcp_socket.pas: -------------------------------------------------------------------------------- 1 | unit amqp.tcp_socket; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | {$INCLUDE config.inc} 8 | 9 | //DEFINE EAGAIN Operation would have caused the process to be suspended. 10 | interface 11 | uses AMQP.Types, amqp.socket, 12 | {$IFNDEF FPC} 13 | 14 | {$IFDEF _WIN32} 15 | Net.Winsock2, Net.Wship6, 16 | {$ELSE} 17 | Net.SocketAPI, 18 | {$ENDIF} 19 | System.SysUtils; 20 | {$ELSE} 21 | winsock2, SysUtils; 22 | {$ENDIF} 23 | 24 | function amqp_tcp_socket_new( state : Pamqp_connection_state):Pamqp_socket; 25 | function amqp_tcp_socket_recv(base: Pointer; buf: Pointer; len : size_t; flags : integer):ssize_t; 26 | function amqp_tcp_socket_open( base: Pointer; const host : PAnsiChar; port : integer;const timeout: Ptimeval):integer; 27 | function amqp_tcp_socket_get_sockfd(base: Pointer):int; 28 | function amqp_tcp_socket_close(base: Pointer; force: Tamqp_socket_close_enum):integer; 29 | function amqp_tcp_socket_send(base: Pointer;const buf: Pointer; len : size_t; flags : integer):ssize_t; 30 | procedure amqp_tcp_socket_set_sockfd(base : Pamqp_socket; sockfd : integer); 31 | procedure amqp_tcp_socket_delete(base: Pointer); 32 | 33 | 34 | const 35 | //Record Constants Record constants cannot contain file-type values at any level. 36 | amqp_tcp_socket_class: Tamqp_socket_class = ( 37 | send : amqp_tcp_socket_send; 38 | recv : amqp_tcp_socket_recv; 39 | open : amqp_tcp_socket_open; 40 | close : amqp_tcp_socket_close; 41 | get_sockfd : amqp_tcp_socket_get_sockfd; 42 | delete : amqp_tcp_socket_delete); 43 | 44 | implementation 45 | 46 | (*TCP_CORK is Linux only; TCP_NOPUSH is BSD only; Windows does its own thing: 47 | https://baus.net/on-tcp_cork/ 48 | https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-tcp-socket-options 49 | *) 50 | procedure amqp_tcp_socket_set_sockfd(base : Pamqp_socket; sockfd : integer); 51 | var 52 | self : Pamqp_tcp_socket; 53 | s: string; 54 | begin 55 | if base.klass <> @amqp_tcp_socket_class then 56 | begin 57 | s := Format('<%p> is not of type Tamqp_tcp_socket', [base]); 58 | raise Exception.Create(s); 59 | end; 60 | self := Pamqp_tcp_socket(base); 61 | self.sockfd := sockfd; 62 | end; 63 | 64 | procedure amqp_tcp_socket_delete(base: Pointer); 65 | var 66 | self : Pamqp_tcp_socket; 67 | begin 68 | self := Pamqp_tcp_socket(base); 69 | if Assigned(self) then 70 | begin 71 | amqp_tcp_socket_close(self, AMQP_SC_NONE); 72 | freeMem(self); 73 | end; 74 | end; 75 | 76 | function amqp_tcp_socket_get_sockfd(base: Pointer):int; 77 | var 78 | self : Pamqp_tcp_socket; 79 | begin 80 | self := Pamqp_tcp_socket(base); 81 | Result := self.sockfd; 82 | end; 83 | 84 | function amqp_tcp_socket_close(base: Pointer; force: Tamqp_socket_close_enum):integer; 85 | var 86 | self : Pamqp_tcp_socket; 87 | begin 88 | self := Pamqp_tcp_socket(base); 89 | if -1 = self.sockfd then 90 | Exit(Int(AMQP_STATUS_SOCKET_CLOSED)); 91 | 92 | if amqp_os_socket_close(self.sockfd) > 0 then 93 | Exit(Int(AMQP_STATUS_SOCKET_ERROR)); 94 | 95 | self.sockfd := -1; 96 | Result := Int(AMQP_STATUS_OK); 97 | end; 98 | 99 | 100 | function amqp_tcp_socket_open( base: Pointer; const host : PAnsiChar; port : integer;const timeout: Ptimeval):integer; 101 | var 102 | Lself : Pamqp_tcp_socket; 103 | err : integer; 104 | begin 105 | Lself := Pamqp_tcp_socket(base); 106 | if -1 <> Lself.sockfd then 107 | Exit(Int(AMQP_STATUS_SOCKET_INUSE)); 108 | 109 | Lself.sockfd := amqp_open_socket_noblock(host, port, timeout); 110 | if 0 > Lself.sockfd then 111 | begin 112 | err := Lself.sockfd; 113 | Lself.sockfd := -1; 114 | Exit(err); 115 | end; 116 | Result := Int(AMQP_STATUS_OK); 117 | end; 118 | 119 | function amqp_tcp_socket_recv(base: Pointer; buf: Pointer; len : size_t; flags : integer):ssize_t; 120 | var 121 | self : Pamqp_tcp_socket; 122 | ret : ssize_t; 123 | Level: int; 124 | s: string; 125 | 126 | label start; 127 | begin 128 | Inc(gLevel); 129 | Level := gLevel; 130 | {$IFDEF _DEBUG_} 131 | DebugOut(Level, 'step into amqp.tcp_socket::amqp_tcp_socket_recv!'); 132 | {$ENDIF} 133 | self := Pamqp_tcp_socket(base); 134 | if -1 = self.sockfd then 135 | Exit(Int(AMQP_STATUS_SOCKET_CLOSED)); 136 | 137 | start: 138 | {$IFDEF _WIN32} 139 | 140 | ret := recv(self.sockfd, Pbyte(buf)^, Int(len), flags); 141 | {$ELSE} 142 | ret = recv(self.sockfd, buf, len, flags); 143 | {$ENDIF} 144 | if 0 > ret then 145 | begin 146 | self.internal_error := amqp_os_socket_error(); 147 | {$IFDEF _DEBUG_} 148 | s := Format('step over amqp.tcp_socket::recv, ret=%d os_socket_error=%d', [ret, self.internal_error] ); 149 | DebugOut(Level, s); 150 | {$ENDIF} 151 | case self.internal_error of 152 | WSAEINTR: goto start; 153 | {$IFDEF _WIN32} 154 | WSAEWOULDBLOCK, 155 | {$ELSE} 156 | EWOULDBLOCK: 157 | {$ENDIF} 158 | {$IF EAGAIN <> 10035}//EWOULDBLOCK} 159 | EAGAIN: 160 | {$IFEND} 161 | ret := Int(AMQP_PRIVATE_STATUS_SOCKET_NEEDREAD); 162 | else 163 | ret := Int(AMQP_STATUS_SOCKET_ERROR); 164 | end; 165 | end 166 | else 167 | if (0 = ret) then 168 | ret := Int(AMQP_STATUS_CONNECTION_CLOSED); 169 | 170 | Result := ret; 171 | 172 | end; 173 | 174 | function amqp_tcp_socket_send(base: Pointer;const buf: Pointer; len : size_t; flags : integer):ssize_t; 175 | var 176 | Lself : Pamqp_tcp_socket; 177 | res : ssize_t; 178 | flagz, one, zero : integer; 179 | LBuffer : Puint8_t; 180 | LArray: array of AnsiChar; 181 | label start; 182 | begin 183 | {$POINTERMATH ON} 184 | Lself := Pamqp_tcp_socket(base); 185 | flagz := 0; 186 | //sockfd=-1 表示socket 已经closed 187 | if -1 = Lself.sockfd then 188 | Exit(Int(AMQP_STATUS_SOCKET_CLOSED)); 189 | 190 | {$IFDEF MSG_NOSIGNAL} 191 | flagz := flagz or MSG_NOSIGNAL; 192 | {$ENDIF} 193 | {$IF defined(MSG_MORE)} 194 | if flags and AMQP_SF_MORE then begin 195 | flagz := flagz or MSG_MORE; 196 | end; 197 | { Cygwin defines TCP_NOPUSH, but trying to use it will return not 198 | * implemented. Disable it here. } 199 | {$ELSEIF defined(TCP_NOPUSH) and not defined(__CYGWIN__)} 200 | if ( (flags and Int(AMQP_SF_MORE))>0 ) and 201 | (0> (self.state and Int(AMQP_SF_MORE) )) then 202 | begin 203 | one := 1; 204 | res := setsockopt(self.sockfd, IPPROTO_TCP, TCP_NOPUSH, &one, sizeof(one)); 205 | if 0 <> res then 206 | begin 207 | self.internal_error := res; 208 | Exit(AMQP_STATUS_SOCKET_ERROR); 209 | end; 210 | self.state := self.state or AMQP_SF_MORE; 211 | end 212 | else 213 | if ( 0= (flags and AMQP_SF_MORE) ) and ((self.state and AMQP_SF_MORE)>0) then 214 | begin 215 | zero := 0; 216 | res := setsockopt(self.sockfd, IPPROTO_TCP, TCP_NOPUSH, &zero, sizeof(&zero)); 217 | if 0 <> res then 218 | begin 219 | self.internal_error := res; 220 | res := AMQP_STATUS_SOCKET_ERROR; 221 | end 222 | else 223 | begin 224 | self.state &= ~AMQP_SF_MORE; 225 | end; 226 | end; 227 | {$IFEND} 228 | 229 | start: 230 | {$IFDEF _WIN32} 231 | //LBuffer := Puint8_t(buf); 232 | {SetLength(LArray, len); 233 | for var I := 0 to Len - 1 do 234 | Larray[I] := AnsiChar(LBuffer[I]); } 235 | {$IFNDEF FPC} 236 | res := send(Lself.sockfd, buf^, Int(len), flagz); 237 | {$ELSE} 238 | res := send(Lself.sockfd, buf^, len, flagz); 239 | {$ENDIF} 240 | {$ELSE} 241 | res := send(Lself.sockfd, buf, len, flagz); 242 | {$ENDIF} 243 | if res < 0 then 244 | begin 245 | Lself.internal_error := amqp_os_socket_error(); 246 | case Lself.internal_error of 247 | WSAEINTR: goto start; 248 | {$IFDEF _WIN32} 249 | WSAEWOULDBLOCK, 250 | {$ELSE } 251 | EWOULDBLOCK: 252 | {$ENDIF} 253 | {$if EAGAIN <> 10035}//EWOULDBLOCK} 254 | EAGAIN: 255 | {$IFEND} 256 | res := int(AMQP_PRIVATE_STATUS_SOCKET_NEEDWRITE); 257 | 258 | else 259 | res := Int(AMQP_STATUS_SOCKET_ERROR); 260 | end; 261 | end 262 | else 263 | Lself.internal_error := 0; 264 | 265 | Result := res; 266 | {$POINTERMATH ON} 267 | end; 268 | 269 | 270 | function amqp_tcp_socket_new( state : Pamqp_connection_state):Pamqp_socket; 271 | var 272 | Lself : Pamqp_tcp_socket; 273 | begin 274 | Lself := calloc(1, sizeof(Tamqp_tcp_socket)); 275 | if not Assigned(Lself) then 276 | Exit(nil); 277 | 278 | Lself.klass := @amqp_tcp_socket_class; 279 | Lself.sockfd := -1; 280 | //amqp_set_socket(state, Pamqp_socket(Lself)); 281 | state.socket := Pamqp_socket(Lself); 282 | Result := Pamqp_socket(Lself); 283 | end; 284 | 285 | initialization 286 | 287 | end. 288 | -------------------------------------------------------------------------------- /amqp.time.pas: -------------------------------------------------------------------------------- 1 | unit amqp.time; 2 | 3 | {$IFDEF FPC} 4 | {$MODE Delphi} 5 | {$ENDIF} 6 | 7 | interface 8 | {$INCLUDE config.inc} 9 | uses {$IFNDEF FPC} 10 | {$IFDEF _WIN32} 11 | Net.Winsock2, 12 | {$ELSE} 13 | Net.SocketAPI, 14 | {$ENDIF} 15 | 16 | Winapi.Windows, 17 | {$ELSE} 18 | Windows, winsock2, //WS2tcpip, 19 | {$ENDIF} AMQP.Types; 20 | 21 | 22 | function amqp_time_from_now(var Atime : Tamqp_time;const Atimeout: Ptimeval):integer; 23 | function amqp_time_s_from_now(var Atime : Tamqp_time; Aseconds : integer):integer; 24 | 25 | function amqp_time_ms_until( Atime : Tamqp_time):integer; 26 | function amqp_time_tv_until( Atime : Tamqp_time; Ain: Ptimeval; Aout: PPtimeval):integer; 27 | function amqp_time_has_past( Atime : Tamqp_time):integer; 28 | function amqp_time_first( l, r : Tamqp_time):Tamqp_time; 29 | 30 | 31 | const 32 | //要指定 uint64_t,否则会引发计算错误 33 | AMQP_MS_PER_S: uint32_t =1000; 34 | AMQP_US_PER_MS: uint32_t =1000; 35 | AMQP_NS_PER_S: uint64_t =1000*1000*1000; //每秒=多少纳秒 36 | AMQP_NS_PER_MS: uint64_t =1000*1000; //每毫秒=多少纳秒 37 | AMQP_NS_PER_US: uint32_t =1000; //每微秒=多少纳秒 38 | 39 | var 40 | NS_PER_COUNT: double ; 41 | 42 | implementation 43 | 44 | function amqp_get_monotonic_timestamp:uint64; 45 | var 46 | perf_count, 47 | perf_frequency : Int64;//LARGE_INTEGER; 48 | begin 49 | //static double NS_PER_COUNT = 0; 50 | if 0 = NS_PER_COUNT then 51 | begin 52 | if not QueryPerformanceFrequency(perf_frequency) then 53 | Exit(0); 54 | 55 | //NS_PER_COUNT := double(AMQP_NS_PER_S / perf_frequency); 56 | NS_PER_COUNT := (AMQP_NS_PER_S / perf_frequency); 57 | end; 58 | if not QueryPerformanceCounter(perf_count) then 59 | Exit(0); 60 | 61 | Result := uint64_t(Round(perf_count * NS_PER_COUNT)); 62 | end; 63 | 64 | function amqp_time_from_now(var Atime : Tamqp_time;const Atimeout: Ptimeval):integer; 65 | var 66 | now_ns, 67 | delta_ns : Uint64; 68 | LValue: int; 69 | Lns: Int64; 70 | begin 71 | //assert(nil <> Atime); 72 | if nil = Atimeout then 73 | begin 74 | Atime := Tamqp_time.infinite; 75 | LValue := Integer(AMQP_STATUS_OK); 76 | Exit(LValue); 77 | end; 78 | if (Atimeout.tv_sec < 0) or 79 | (Atimeout.tv_usec < 0) then 80 | begin 81 | LValue := Integer(AMQP_STATUS_INVALID_PARAMETER); 82 | Exit(LValue); 83 | end; 84 | 85 | Lns := Atimeout.tv_sec * AMQP_NS_PER_S; 86 | delta_ns := Lns + 87 | Atimeout.tv_usec * AMQP_NS_PER_US; 88 | now_ns := amqp_get_monotonic_timestamp(); 89 | 90 | if 0 = now_ns then 91 | begin 92 | Exit(Integer(AMQP_STATUS_TIMER_FAILURE)); 93 | end; 94 | 95 | Atime.time_point_ns := now_ns + delta_ns; 96 | 97 | if (now_ns > Atime.time_point_ns) or 98 | (delta_ns > Atime.time_point_ns) then 99 | begin 100 | Exit(Integer(AMQP_STATUS_INVALID_PARAMETER)); 101 | end; 102 | Result := Integer(AMQP_STATUS_OK); 103 | end; 104 | 105 | 106 | function amqp_time_s_from_now(var Atime : Tamqp_time; Aseconds : integer):integer; 107 | var 108 | now_ns, 109 | delta_ns : uint64; 110 | begin 111 | //assert(nil <> Atime); 112 | if 0 >= Aseconds then 113 | begin 114 | Atime := Tamqp_time.infinite; 115 | Exit(Integer(AMQP_STATUS_OK)); 116 | end; 117 | now_ns := amqp_get_monotonic_timestamp(); 118 | if 0 = now_ns then 119 | begin 120 | Exit(Integer(AMQP_STATUS_TIMER_FAILURE)); 121 | end; 122 | delta_ns := uint64_t(Aseconds * AMQP_NS_PER_S); 123 | Atime.time_point_ns := now_ns + delta_ns; 124 | if (now_ns > Atime.time_point_ns) or 125 | (delta_ns > Atime.time_point_ns) then 126 | begin 127 | Exit(Integer(AMQP_STATUS_INVALID_PARAMETER)); 128 | end; 129 | Result := Integer(AMQP_STATUS_OK); 130 | end; 131 | 132 | 133 | 134 | 135 | 136 | function amqp_time_ms_until( Atime : Tamqp_time):integer; 137 | var 138 | now_ns, 139 | delta_ns : uint64; 140 | left_ms : integer; 141 | begin 142 | if UINT64_MAX = Atime.time_point_ns then 143 | begin 144 | Exit(-1); 145 | end; 146 | if 0 = Atime.time_point_ns then 147 | begin 148 | Exit(0); 149 | end; 150 | now_ns := amqp_get_monotonic_timestamp(); 151 | if 0 = now_ns then 152 | begin 153 | Exit(Integer(AMQP_STATUS_TIMER_FAILURE)); 154 | end; 155 | if now_ns >= Atime.time_point_ns then 156 | begin 157 | Exit(0); 158 | end; 159 | delta_ns := Atime.time_point_ns - now_ns; 160 | left_ms := delta_ns div AMQP_NS_PER_MS; 161 | Result := left_ms; 162 | end; 163 | 164 | 165 | function amqp_time_tv_until( Atime : Tamqp_time; Ain: Ptimeval; Aout: PPtimeval):integer; 166 | var 167 | now_ns, 168 | delta_ns : uint64; 169 | begin 170 | assert(Ain <> nil); 171 | if UINT64_MAX = Atime.time_point_ns then 172 | begin 173 | Aout^ := nil; 174 | Exit(Integer(AMQP_STATUS_OK)); 175 | end; 176 | if 0 = Atime.time_point_ns then 177 | begin 178 | Ain.tv_sec := 0; 179 | Ain.tv_usec := 0; 180 | Aout^ := Ain; 181 | Exit(Integer(AMQP_STATUS_OK)); 182 | end; 183 | now_ns := amqp_get_monotonic_timestamp(); 184 | if 0 = now_ns then 185 | begin 186 | Exit(Integer(AMQP_STATUS_TIMER_FAILURE)); 187 | end; 188 | if now_ns >= Atime.time_point_ns then 189 | begin 190 | Ain.tv_sec := 0; 191 | Ain.tv_usec := 0; 192 | Aout^ := Ain; 193 | Exit(Integer(AMQP_STATUS_OK)); 194 | end; 195 | delta_ns := Atime.time_point_ns - now_ns; 196 | Ain.tv_sec := delta_ns div AMQP_NS_PER_S; 197 | Ain.tv_usec :=(delta_ns mod AMQP_NS_PER_S) div AMQP_NS_PER_US; 198 | Aout^ := Ain; 199 | Result := Integer(AMQP_STATUS_OK); 200 | end; 201 | 202 | 203 | function amqp_time_has_past( Atime : Tamqp_time):integer; 204 | var 205 | now_ns : uint64; 206 | begin 207 | if UINT64_MAX = Atime.time_point_ns then 208 | begin 209 | Exit(Integer(AMQP_STATUS_OK)); 210 | end; 211 | now_ns := amqp_get_monotonic_timestamp(); 212 | if 0 = now_ns then 213 | begin 214 | Exit(Integer(AMQP_STATUS_TIMER_FAILURE)); 215 | end; 216 | if now_ns > Atime.time_point_ns then 217 | begin 218 | Exit(Integer(AMQP_STATUS_TIMEOUT)); 219 | end; 220 | Result := Integer(AMQP_STATUS_OK); 221 | end; 222 | 223 | 224 | function amqp_time_first( l, r : Tamqp_time):Tamqp_time; 225 | begin 226 | if l.time_point_ns < r.time_point_ns then 227 | Exit(l); 228 | 229 | Result := r; 230 | end; 231 | 232 | 233 | 234 | 235 | initialization 236 | NS_PER_COUNT := 0; 237 | 238 | end. 239 | -------------------------------------------------------------------------------- /amqp_tcp_socket.pas: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonadorje/rabbitmq-delphi/e4931fc10be22d84d0bafe83e3349403dbeb3b9b/amqp_tcp_socket.pas -------------------------------------------------------------------------------- /config.inc: -------------------------------------------------------------------------------- 1 | {$DEFINE _WIN32} 2 | //{$DEFINE CrossSocket} 3 | {$define HAVE_SELECT} 4 | {$define _DEBUG_} 5 | 6 | --------------------------------------------------------------------------------