├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build.bat ├── build.sh ├── cf ├── Catalogs │ ├── БрокерыКафка.xml │ ├── БрокерыКафка │ │ └── Forms │ │ │ ├── ФормаСписка.xml │ │ │ ├── ФормаСписка │ │ │ └── Ext │ │ │ │ └── Form.xml │ │ │ ├── ФормаЭлемента.xml │ │ │ └── ФормаЭлемента │ │ │ └── Ext │ │ │ ├── Form.xml │ │ │ └── Form │ │ │ └── Module.bsl │ ├── НастройкиКафки.xml │ └── НастройкиКафки │ │ ├── Commands │ │ └── ОткрытьЛоги │ │ │ └── Ext │ │ │ └── CommandModule.bsl │ │ ├── Ext │ │ ├── ManagerModule.bsl │ │ └── ObjectModule.bsl │ │ └── Forms │ │ ├── ФормаЛоги.xml │ │ ├── ФормаЛоги │ │ └── Ext │ │ │ ├── Form.xml │ │ │ └── Form │ │ │ └── Module.bsl │ │ ├── ФормаСписка.xml │ │ ├── ФормаСписка │ │ └── Ext │ │ │ └── Form.xml │ │ ├── ФормаЭлемента.xml │ │ └── ФормаЭлемента │ │ └── Ext │ │ ├── Form.xml │ │ └── Form │ │ └── Module.bsl ├── CommonModules │ ├── ОбщегоНазначения.xml │ └── ОбщегоНазначения │ │ └── Ext │ │ └── Module.bsl ├── CommonPictures │ ├── Кафка.xml │ └── Кафка │ │ └── Ext │ │ ├── Picture.xml │ │ └── Picture │ │ └── Picture.png ├── ConfigDumpInfo.xml ├── Configuration.xml ├── DataProcessors │ ├── КафкаКоннектор.xml │ └── КафкаКоннектор │ │ ├── Ext │ │ └── ObjectModule.bsl │ │ ├── Forms │ │ ├── Форма.xml │ │ └── Форма │ │ │ └── Ext │ │ │ ├── Form.xml │ │ │ └── Form │ │ │ └── Module.bsl │ │ └── Templates │ │ ├── RdKafka1C.xml │ │ └── RdKafka1C │ │ └── Ext │ │ └── Template.bin ├── Ext │ ├── ClientApplicationInterface.xml │ └── HomePageWorkArea.xml ├── Languages │ └── Русский.xml └── Subsystems │ └── Кафка.xml ├── doc ├── build.md ├── cmake.md ├── how-to-use.md ├── kafka.md ├── program-interface.md ├── res │ ├── structure.plantuml │ └── structure.png └── vcpkg.md ├── docker-compose.yml ├── generate.bat ├── include ├── AddInDefBase.h ├── ComponentBase.h ├── IMemoryManager.h ├── com.h ├── dllmain.cpp ├── md5.cpp ├── md5.h ├── resource.h ├── stdafx.cpp ├── stdafx.h ├── targetver.h └── types.h ├── kafka-broker └── dockerfile ├── kafka-ui └── dockerfile ├── package ├── INFO.XML ├── MANIFEST.XML └── RdKafka1C.zip ├── src ├── AddInNative.cpp ├── AddInNative.h ├── ConfigBuilder.cpp ├── ConfigBuilder.h ├── DeliveryReport.cpp ├── DeliveryReport.h ├── ErrorHandler.cpp ├── ErrorHandler.h ├── Event.cpp ├── Event.h ├── Loger.cpp ├── Loger.h ├── RdKafka1C.cpp ├── RdKafka1C.h ├── Rebalance.cpp ├── Rebalance.h ├── strings.cpp ├── strings.h └── utils.h ├── test ├── RdKafka1CTest.cpp ├── RdKafka1CTest.h └── main.cpp ├── vcpkg-configuration.json ├── vcpkg-install.bat ├── vcpkg-install.sh └── vcpkg.json /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /.cache 3 | /build 4 | /logs 5 | /vcpkg_installed 6 | 7 | *.so 8 | *.dll 9 | *.cf 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.30) 2 | set(CMAKE_CXX_STANDARD 20) 3 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 4 | set(CMAKE_LEGACY_CYGWIN_WIN32 0) 5 | set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) 6 | set(CMAKE_SUPPRESS_REGENERATION true) 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}) 8 | 9 | if(WIN32) 10 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 11 | set(VCPKG_TARGET_TRIPLET "x64-windows-static-md") 12 | elseif() 13 | set(VCPKG_TARGET_TRIPLET "x64-linux") 14 | endif() 15 | 16 | # DLL 17 | project(RdKafka1C) 18 | 19 | find_package(Boost 1.88 CONFIG REQUIRED COMPONENTS filesystem iostreams program_options regex system json) 20 | find_package(RdKafka CONFIG REQUIRED) 21 | 22 | add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) 23 | add_definitions("-DLIBRDKAFKA_STATICLIB") 24 | 25 | add_library(RdKafka1C SHARED 26 | include/dllmain.cpp 27 | include/stdafx.cpp 28 | include/md5.cpp 29 | src/RdKafka1C.cpp 30 | src/AddInNative.cpp 31 | src/ErrorHandler.cpp 32 | src/Loger.cpp 33 | src/ConfigBuilder.cpp 34 | src/DeliveryReport.cpp 35 | src/Event.cpp 36 | src/Rebalance.cpp 37 | src/strings.cpp) 38 | 39 | if(WIN32) 40 | if(NOT MSVC) 41 | message(FATAL_ERROR "Must be compiled with MSVC on Windows") 42 | endif() 43 | 44 | target_include_directories(RdKafka1C PRIVATE include 45 | ${Boost_INCLUDE_DIRS} 46 | ${CMAKE_CURRENT_SOURCE_DIR}/include 47 | ${RdKafka_INCLUDE_DIRS}) 48 | 49 | target_link_libraries(RdKafka1C 50 | ${Boost_LIBRARIES} 51 | RdKafka::rdkafka 52 | RdKafka::rdkafka++ 53 | ) 54 | 55 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 56 | 57 | target_compile_definitions(RdKafka1C PRIVATE 58 | _WINDOWS 59 | _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) 60 | 61 | else() 62 | target_include_directories(RdKafka1C PRIVATE include 63 | ${Boost_INCLUDE_DIRS} 64 | ${CMAKE_CURRENT_SOURCE_DIR}/include 65 | ${RdKafka_INCLUDE_DIRS}) 66 | 67 | target_link_libraries(RdKafka1C 68 | ${Boost_LIBRARIES} 69 | RdKafka::rdkafka 70 | RdKafka::rdkafka++ 71 | ) 72 | endif() 73 | 74 | # Testing 75 | project(testing) 76 | find_package(GTest CONFIG REQUIRED) 77 | enable_testing() 78 | 79 | add_executable(testing 80 | test/main.cpp 81 | test/RdKafka1CTest.cpp 82 | src/RdKafka1C.cpp 83 | src/ErrorHandler.cpp 84 | src/Loger.cpp 85 | src/ConfigBuilder.cpp 86 | src/DeliveryReport.cpp 87 | src/Event.cpp 88 | src/Rebalance.cpp) 89 | 90 | target_include_directories(testing PRIVATE 91 | ${CMAKE_CURRENT_SOURCE_DIR}/src 92 | ${CMAKE_CURRENT_SOURCE_DIR}/include) 93 | 94 | target_link_libraries(testing PRIVATE 95 | RdKafka1C 96 | GTest::gtest 97 | GTest::gtest_main 98 | GTest::gmock 99 | GTest::gmock_main) 100 | -------------------------------------------------------------------------------- /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 | # Внешняя компонента Rdkafka-1C 2 | 3 | Версия 1.3.1 4 | 5 | Rdkafka-1c - это внешняя компонента разработанная на языке C++ для обмена приложений на языке 1С с брокером сообщений Kafka. Компонента использует производительную многопоточную библиотеку [librdkafka](https://github.com/confluentinc/librdkafka) и разработана в соответствии с рекомендациями фирмы 1С по разработке [внешних компонент](https://its.1c.ru/db/metod8dev/content/3221/hdoc). 6 | 7 | ![Структура компоненты](doc/res/structure.png) 8 | 9 | ## Документация 10 | 11 | - [Сборка внешней компоненты](./doc/build.md) 12 | - [Менеджер пакетов vcpkg](./doc/vcpkg.md) 13 | - [Настройка cmake](./doc/cmake.md) 14 | - [Тестовый Apache Kafka и веб интерфейс](./doc/kafka.md) 15 | 16 | - [Использование](./doc/how-to-use.md) 17 | - [Программный интерфейс компоненты (справочник методов)](./doc/program-interface.md) 18 | 19 | ## Контрибьюторам 20 | 21 | Разработка ведется по [Gitflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow), любой вклад в проект приветствуется. Чтобы задать вопрос или для своих предложений по развитию вы можете открывать [issue](https://github.com/sv-sand/rdkafka-1c/issues). Если вы можете сделать pull request и решить [issue](https://github.com/sv-sand/rdkafka-1c/issues) - это будет в двойне круто. 22 | 23 | ## Ссылки 24 | 25 | - [Технология создания внешних компонент](https://its.1c.ru/db/metod8dev/content/3221/hdoc) 26 | - [librdkafka](https://github.com/confluentinc/librdkafka) 27 | - [googletest](https://github.com/google/googletest) 28 | - [vcpkg](https://github.com/microsoft/vcpkg) 29 | - [cmake](https://cmake.org) 30 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @set BUILD_DIR=".\build" 2 | 3 | del %BUILD_DIR% /Q /S 4 | 5 | cmake -S . -B %BUILD_DIR% --toolchain %VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake 6 | cmake --build %BUILD_DIR% --config "Release" --target RdKafka1C 7 | 8 | @pause -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | BUILD_DIR="./build" 2 | 3 | rm -rf $BUILD_DIR 4 | 5 | cmake -B $BUILD_DIR -S . --toolchain $VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake 6 | cmake --build $BUILD_DIR --config "Release" --target RdKafka1C 7 | -------------------------------------------------------------------------------- /cf/Catalogs/БрокерыКафка/Forms/ФормаСписка.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | ФормаСписка 6 | 7 | 8 | ru 9 | Форма списка 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 |
21 |
-------------------------------------------------------------------------------- /cf/Catalogs/БрокерыКафка/Forms/ФормаСписка/Ext/Form.xml: -------------------------------------------------------------------------------- 1 |  2 |
3 | 4 | 5 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | <v8:item> 22 | <v8:lang>ru</v8:lang> 23 | <v8:content>Группа пользовательских настроек</v8:content> 24 | </v8:item> 25 | 26 | false 27 | Vertical 28 | false 29 | 30 | 31 | 32 | List 33 | None 34 | true 35 | true 36 | ExpandTopLevel 37 | true 38 | Список 39 | Список.DefaultPicture 40 | false 41 | 60 42 | 43 | Custom 44 | 0001-01-01T00:00:00 45 | 0001-01-01T00:00:00 46 | 47 | Items 48 | false 49 | 50 | true 51 | false 52 | Auto 53 | СписокКомпоновщикНастроекПользовательскиеНастройки 54 | true 55 | 56 | 57 | false 58 | 59 | 60 | 61 | 62 | Список 63 | SearchStringRepresentation 64 | 65 | 66 | 67 | 68 | 69 | 70 | Список 71 | ViewStatusRepresentation 72 | 73 | 74 | 75 | 76 | 77 | 78 | Список 79 | SearchControl 80 | 81 | 82 | 83 | 84 | 85 | 86 | Список.Ref 87 | 88 | false 89 | 90 | 91 | 92 | 93 | 94 | Список.Code 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | Список.Description 103 | true 104 | 105 | 106 | 107 | 108 | Список.СписокБрокеров 109 | 110 | 111 | 112 | 113 | Список.ПротоколБезопасности 114 | 115 | 116 | 117 | 118 | Список.Комментарий 119 | 120 | 121 | 122 | 123 |
124 |
125 | 126 | 127 | 128 | cfg:DynamicList 129 | 130 | true 131 | 132 | false 133 | true 134 | Catalog.БрокерыКафка 135 | 136 | 137 | Normal 138 | dfcece9d-5077-440b-b6b3-45a5cb4538eb 139 | 140 | 141 | Normal 142 | 88619765-ccb3-46c6-ac52-38e9c992ebd4 143 | 144 | 145 | Normal 146 | b75fecce-942b-4aed-abc9-e6a02e460fb3 147 | 148 | Normal 149 | 911b6018-f537-43e8-a417-da56b22f9aec 150 | 151 | 152 | 153 | 154 |
-------------------------------------------------------------------------------- /cf/Catalogs/БрокерыКафка/Forms/ФормаЭлемента.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | ФормаЭлемента 6 | 7 | 8 | ru 9 | Форма элемента 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 |
21 |
-------------------------------------------------------------------------------- /cf/Catalogs/БрокерыКафка/Forms/ФормаЭлемента/Ext/Form.xml: -------------------------------------------------------------------------------- 1 |  2 |
3 | LockOwnerWindow 4 | Items 5 | 6 | 7 | ПриСозданииНаСервере 8 | 9 | 10 | 11 | 12 | <v8:item> 13 | <v8:lang>ru</v8:lang> 14 | <v8:content>Группа код наименование</v8:content> 15 | </v8:item> 16 | 17 | 18 | 19 | ru 20 | Группа код наименование 21 | 22 | 23 | None 24 | false 25 | 26 | 27 | 28 | Объект.Description 29 | EnterOnInput 30 | true 31 | 32 | 33 | 34 | 35 | Объект.Code 36 | 37 | false 38 | 39 | EnterOnInput 40 | true 41 | 42 | 43 | 44 | 45 | 46 | 47 | Объект.СписокБрокеров 48 | true 49 | 50 | 51 | 52 | 53 | Объект.ПротоколБезопасности 54 | EnterOnInput 55 | true 56 | true 57 | false 58 | 59 | 60 | 61 | 0 62 | 63 | 64 | plaintext 65 | 66 | 67 | 68 | 69 | 0 70 | 71 | 72 | ssl 73 | 74 | 75 | 76 | 77 | 0 78 | 79 | 80 | sasl_plaintext 81 | 82 | 83 | 84 | 85 | 0 86 | 87 | 88 | sasl_ssl 89 | 90 | 91 | 92 | 93 | 94 | 95 | ПротоколБезопасностиПриИзменении 96 | 97 | 98 | 99 | 100 | <v8:item> 101 | <v8:lang>ru</v8:lang> 102 | <v8:content>SASL</v8:content> 103 | </v8:item> 104 | 105 | 106 | 107 | ru 108 | Группа SASL 109 | 110 | 111 | 112 | 113 | 114 | Объект.МеханизмSASL 115 | 116 | <v8:item> 117 | <v8:lang>ru</v8:lang> 118 | <v8:content>Механизм</v8:content> 119 | </v8:item> 120 | 121 | EnterOnInput 122 | true 123 | true 124 | false 125 | 126 | 127 | 128 | 0 129 | 130 | 131 | GSSAPI 132 | 133 | 134 | 135 | 136 | 0 137 | 138 | 139 | PLAIN 140 | 141 | 142 | 143 | 144 | 0 145 | 146 | 147 | SCRAM-SHA-256 148 | 149 | 150 | 151 | 152 | 0 153 | 154 | 155 | SCRAM-SHA-512 156 | 157 | 158 | 159 | 160 | 0 161 | 162 | 163 | OAUTHBEARER 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | <v8:item> 173 | <v8:lang>ru</v8:lang> 174 | <v8:content>Группа авторизация SASL</v8:content> 175 | </v8:item> 176 | 177 | 178 | 179 | ru 180 | Группа авторизация SASL 181 | 182 | 183 | Vertical 184 | None 185 | false 186 | 187 | 188 | 189 | Объект.ИмяПользователяSASL 190 | 191 | <v8:item> 192 | <v8:lang>ru</v8:lang> 193 | <v8:content>Имя пользователя</v8:content> 194 | </v8:item> 195 | 196 | EnterOnInput 197 | true 198 | 199 | 200 | 201 | 202 | Объект.ПарольSASL 203 | 204 | <v8:item> 205 | <v8:lang>ru</v8:lang> 206 | <v8:content>Пароль</v8:content> 207 | </v8:item> 208 | 209 | EnterOnInput 210 | true 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | <v8:item> 221 | <v8:lang>ru</v8:lang> 222 | <v8:content>SSL</v8:content> 223 | </v8:item> 224 | 225 | 226 | 227 | ru 228 | Группа SSL 229 | 230 | 231 | 232 | 233 | 234 | Объект.СертификатSSL 235 | 236 | <v8:item> 237 | <v8:lang>ru</v8:lang> 238 | <v8:content>Сертификат</v8:content> 239 | </v8:item> 240 | 241 | 60 242 | true 243 | true 244 | 245 | 246 | 247 | 248 | 249 | 250 | Объект.Комментарий 251 | 60 252 | 2 253 | false 254 | 2 255 | true 256 | true 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | cfg:CatalogObject.БрокерыКафка 265 | 266 | true 267 | true 268 | 269 | 270 | -------------------------------------------------------------------------------- /cf/Catalogs/БрокерыКафка/Forms/ФормаЭлемента/Ext/Form/Module.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Область ОбработчикиСобытийФормы 3 | 4 | &НаСервере 5 | Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) 6 | 7 | ОбновитьЭлементыФормы(); 8 | 9 | КонецПроцедуры 10 | 11 | #КонецОбласти 12 | 13 | #Область ОбрботчикиСобытийЭлементовФормы 14 | 15 | &НаКлиенте 16 | Процедура ПротоколБезопасностиПриИзменении(Элемент) 17 | ОбновитьЭлементыФормы(); 18 | КонецПроцедуры 19 | 20 | #КонецОбласти 21 | 22 | #Область СлужебныеПроцедурыИФункции 23 | 24 | &НаСервере 25 | Процедура ОбновитьЭлементыФормы() 26 | 27 | Если Объект.ПротоколБезопасности = "plaintext" Тогда 28 | Элементы.ГруппаSASL.Видимость = Ложь; 29 | Элементы.ГруппаSSL.Видимость = Ложь; 30 | 31 | ИначеЕсли Объект.ПротоколБезопасности = "ssl" Тогда 32 | Элементы.ГруппаSASL.Видимость = Ложь; 33 | Элементы.ГруппаSSL.Видимость = Истина; 34 | 35 | ИначеЕсли Объект.ПротоколБезопасности = "sasl_plaintext" Тогда 36 | Элементы.ГруппаSASL.Видимость = Истина; 37 | Элементы.ГруппаSSL.Видимость = Ложь; 38 | 39 | ИначеЕсли Объект.ПротоколБезопасности = "sasl_ssl" Тогда 40 | Элементы.ГруппаSASL.Видимость = Истина; 41 | Элементы.ГруппаSSL.Видимость = Истина; 42 | 43 | Иначе 44 | Элементы.ГруппаSASL.Видимость = Ложь; 45 | Элементы.ГруппаSSL.Видимость = Ложь; 46 | 47 | КонецЕсли; 48 | 49 | КонецПроцедуры 50 | 51 | #КонецОбласти 52 | -------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Commands/ОткрытьЛоги/Ext/CommandModule.bsl: -------------------------------------------------------------------------------- 1 |  2 | &НаКлиенте 3 | Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды) 4 | 5 | ПараметрыФОрмы = Новый Структура("Настройки", ПараметрКоманды); 6 | ОткрытьФорму("Справочник.НастройкиКафки.Форма.ФормаЛоги", ПараметрыФормы, ПараметрыВыполненияКоманды.Источник, 7 | ПараметрыВыполненияКоманды.Уникальность, ПараметрыВыполненияКоманды.Окно, ПараметрыВыполненияКоманды.НавигационнаяСсылка); 8 | 9 | КонецПроцедуры 10 | -------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Ext/ManagerModule.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Если Сервер ИЛИ ТолстыйКлиентУправляемоеПриложение Тогда 3 | 4 | #Область ПрограммныйИнтерфейс 5 | 6 | // Возвращает настройку Кафки найденную по Идентификатору 7 | // 8 | // Параметры: 9 | // Идентификатор - Строка - Идентификатор настройки 10 | // 11 | // Возвращаемое значение: 12 | // СправочникСсылка.НастройкиКафки - Найденная настройка 13 | // 14 | Функция НайтиПоИдентификатору(Идентификатор) Экспорт 15 | 16 | Настройка = НайтиПоРеквизиту("Идентификатор", Идентификатор); 17 | Если НЕ ЗначениеЗаполнено(Настройка) Тогда 18 | ВызватьИсключение СтрШаблон("Не удалось найти настройку Кафки по идентификатору '%1'", Идентификатор); 19 | КонецЕсли; 20 | 21 | Возврат Настройка; 22 | 23 | КонецФункции 24 | 25 | // Возвращает каталог логов для настройки Кафки 26 | // 27 | // Параметры: 28 | // Настройка - СправочникСсылка.НастройкиКафки - Настройка 29 | // 30 | // Возвращаемое значение: 31 | // Строка - Каталог логов 32 | // 33 | Функция КаталогЛогов(Настройка) Экспорт 34 | 35 | Разделитель = ПолучитьРазделительПутиСервера(); 36 | 37 | Возврат КаталогВременныхФайлов() + "rdkafka-1c" + Разделитель + Настройка.Идентификатор + Разделитель; 38 | 39 | КонецФункции 40 | 41 | #КонецОбласти 42 | 43 | #КонецЕсли 44 | -------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Ext/ObjectModule.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Область ОбработчикиСобытий 3 | 4 | Процедура ПриЗаписи(Отказ) 5 | 6 | ПроверитьУникальностьИдентификатора(Отказ); 7 | 8 | КонецПроцедуры 9 | 10 | #КонецОбласти 11 | 12 | #Область СлужебныеПроцедурыИФункции 13 | 14 | Процедура ПроверитьУникальностьИдентификатора(Отказ) 15 | 16 | Запрос = Новый Запрос; 17 | Запрос.Текст = 18 | "ВЫБРАТЬ 19 | | НастройкиКафки.Ссылка КАК Ссылка 20 | |ИЗ 21 | | Справочник.НастройкиКафки КАК НастройкиКафки 22 | |ГДЕ 23 | | НастройкиКафки.Идентификатор = &Идентификатор 24 | | И НастройкиКафки.Ссылка <> &Ссылка"; 25 | 26 | Запрос.УстановитьПараметр("Идентификатор", Идентификатор); 27 | Запрос.УстановитьПараметр("Ссылка", Ссылка); 28 | 29 | Выборка = Запрос.Выполнить().Выбрать(); 30 | 31 | Если Выборка.Следующий() Тогда 32 | ТекстСообщения = СтрШаблон("Уже существет настройка Кафки %1 с идентификатором %2", 33 | Выборка.Ссылка, Идентификатор); 34 | ОбщегоНазначения.СообщитьПользователю(ТекстСообщения, Выборка.Ссылка, , Отказ); 35 | КонецЕсли; 36 | 37 | КонецПроцедуры 38 | 39 | #КонецОбласти 40 | -------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаЛоги.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | ФормаЛоги 6 | 7 | 8 | ru 9 | Форма логи 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 |
21 |
-------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаЛоги/Ext/Form/Module.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Область ОбработчикиСобытийФормы 3 | 4 | &НаСервере 5 | Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) 6 | 7 | Параметры.Свойство("Настройки", Настройки); 8 | 9 | Заголовок = СтрШаблон("Логи настройки Кафки: %1", Настройки); 10 | Каталог = Справочники.НастройкиКафки.КаталогЛогов(Настройки); 11 | 12 | ОбновитьФайлыНаСервере(); 13 | 14 | КонецПроцедуры 15 | 16 | #КонецОбласти 17 | 18 | #Область ОбработчикиСобытийЭлементовФормы 19 | 20 | &НаКлиенте 21 | Процедура ФайлыПриАктивизацииСтроки(Элемент) 22 | 23 | ПрочитатьЛоги(); 24 | 25 | КонецПроцедуры 26 | 27 | #КонецОбласти 28 | 29 | #Область ОбработчикиКоманд 30 | 31 | &НаКлиенте 32 | Процедура ФайлыПередУдалением(Элемент, Отказ) 33 | 34 | УдалитьФайлыНаСервере(Элементы.Файлы.ВыделенныеСтроки); 35 | ПрочитатьЛоги(); 36 | 37 | КонецПроцедуры 38 | 39 | &НаКлиенте 40 | Процедура ОбновитьФайлы(Команда) 41 | ОбновитьФайлыНаСервере(); 42 | КонецПроцедуры 43 | 44 | &НаСервере 45 | Процедура ОбновитьФайлыНаСервере() 46 | 47 | Файлы.Очистить(); 48 | 49 | НайденныеФайлы = НайтиФайлы(Каталог, "*.log"); 50 | Для каждого Файл Из НайденныеФайлы Цикл 51 | НоваяСтрока = Файлы.Добавить(); 52 | ЗаполнитьЗначенияСвойств(НоваяСтрока, Файл); 53 | 54 | Размер = Файл.Размер(); 55 | НоваяСтрока.Размер = Размер; 56 | 57 | Если Размер <= 1000 Тогда 58 | НоваяСтрока.РазмерПредставление = Формат(Размер, "ЧДЦ=0; ЧС=0; ЧФ='Ч'"); 59 | НоваяСтрока.Предупреждать = Ложь; 60 | ИначеЕсли Размер <= 1000000 Тогда 61 | НоваяСтрока.РазмерПредставление = Формат(Размер, "ЧДЦ=0; ЧС=3; ЧФ='Ч Кб'"); 62 | НоваяСтрока.Предупреждать = Ложь; 63 | ИначеЕсли Размер <= 1000000000 Тогда 64 | НоваяСтрока.РазмерПредставление = Формат(Размер, "ЧДЦ=0; ЧС=6; ЧФ='Ч Мб'"); 65 | НоваяСтрока.Предупреждать = Истина; 66 | Иначе 67 | НоваяСтрока.РазмерПредставление = Формат(Размер, "ЧДЦ=0; ЧС=9; ЧФ='Ч Гб'"); 68 | НоваяСтрока.Предупреждать = Истина; 69 | КонецЕсли; 70 | КонецЦикла; 71 | 72 | Файлы.Сортировать("Имя Убыв"); 73 | 74 | КонецПроцедуры 75 | 76 | #КонецОбласти 77 | 78 | #Область СлужебныеПроцедурыИФункции 79 | 80 | &НаКлиенте 81 | Процедура ПрочитатьЛоги() 82 | 83 | Логи.Очистить(); 84 | Если Элементы.Файлы.ТекущиеДанные = Неопределено Тогда 85 | Возврат; 86 | КонецЕсли; 87 | 88 | ВыбраннаяСтрока = Элементы.Файлы.ТекущиеДанные; 89 | ЛогФайл = Каталог + ВыбраннаяСтрока.Имя; 90 | Если НЕ ЗначениеЗаполнено(ЛогФайл) Тогда 91 | Возврат; 92 | КонецЕсли; 93 | 94 | Если ВыбраннаяСтрока.Предупреждать Тогда 95 | ДополнительныеПараметры = Новый Структура("ЛогФайл", ЛогФайл); 96 | Оповещение = Новый ОписаниеОповещения("ПрочитатьЛогиЗавершение", ЭтотОбъект, ДополнительныеПараметры); 97 | ТекстСообщения = СтрШаблон("Чтение файла %1 размером %2 может занять время. Прочитать файл?", 98 | ВыбраннаяСтрока.Имя, ВыбраннаяСтрока.РазмерПредставление); 99 | ПоказатьВопрос(Оповещение, ТекстСообщения, РежимДиалогаВопрос.ДаНет, , , "Внимание!"); 100 | Иначе 101 | ПрочитатьЛогиНаСервере(ЛогФайл); 102 | КонецЕсли; 103 | 104 | КонецПроцедуры 105 | 106 | &НаКлиенте 107 | Процедура ПрочитатьЛогиЗавершение(РезультатВопроса, ДополнительныеПараметры) Экспорт 108 | 109 | Если РезультатВопроса <> КодВозвратаДиалога.Да Тогда 110 | Возврат; 111 | КонецЕсли; 112 | 113 | ПрочитатьЛогиНаСервере(ДополнительныеПараметры.ЛогФайл); 114 | 115 | КонецПроцедуры 116 | 117 | &НаСервере 118 | Процедура ПрочитатьЛогиНаСервере(ЛогФайл) 119 | 120 | Файл = Новый Файл(ЛогФайл); 121 | 122 | Если НЕ Файл.Существует() Тогда 123 | Возврат; 124 | КонецЕсли; 125 | 126 | Логи.Прочитать(ЛогФайл); 127 | 128 | КонецПроцедуры 129 | 130 | &НаСервере 131 | Процедура УдалитьФайлыНаСервере(Знач ИдентификаторыСтрок) 132 | 133 | Для каждого Идентификатор Из ИдентификаторыСтрок Цикл 134 | Строка = Файлы.НайтиПоИдентификатору(Идентификатор); 135 | УдалитьФайлы(Строка.ПолноеИмя); 136 | КонецЦикла; 137 | 138 | КонецПроцедуры 139 | 140 | #КонецОбласти 141 | -------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаСписка.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | ФормаСписка 6 | 7 | 8 | ru 9 | Форма списка 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 |
21 |
-------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаСписка/Ext/Form.xml: -------------------------------------------------------------------------------- 1 |  2 |
3 | 4 | 5 | 11 | 16 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | <v8:item> 34 | <v8:lang>ru</v8:lang> 35 | <v8:content>Группа пользовательских настроек</v8:content> 36 | </v8:item> 37 | 38 | false 39 | Vertical 40 | false 41 | 42 | 43 | 44 | None 45 | true 46 | true 47 | ExpandTopLevel 48 | true 49 | true 50 | Список 51 | Список.DefaultPicture 52 | false 53 | 60 54 | 55 | Custom 56 | 0001-01-01T00:00:00 57 | 0001-01-01T00:00:00 58 | 59 | Items 60 | false 61 | 62 | true 63 | false 64 | Auto 65 | СписокКомпоновщикНастроекПользовательскиеНастройки 66 | true 67 | 68 | 69 | false 70 | 71 | 72 | 73 | 74 | Список 75 | SearchStringRepresentation 76 | 77 | 78 | 79 | 80 | 81 | 82 | Список 83 | ViewStatusRepresentation 84 | 85 | 86 | 87 | 88 | 89 | 90 | Список 91 | SearchControl 92 | 93 | 94 | 95 | 96 | 97 | 98 | Список.Ref 99 | 100 | false 101 | 102 | 103 | 104 | 105 | 106 | Список.Code 107 | 108 | false 109 | 110 | 111 | 112 | 113 | 114 | Список.Активна 115 | Auto 116 | 117 | 118 | 119 | 120 | Список.Description 121 | true 122 | 123 | 124 | 125 | 126 | Список.Идентификатор 127 | 128 | 129 | 130 | 131 | Список.Отправка 132 | Auto 133 | 134 | 135 | 136 | 137 | Список.Получение 138 | Auto 139 | 140 | 141 | 142 | 143 | Список.Брокер 144 | 145 | 146 | 147 | 148 | Список.Топик 149 | 150 | 151 | 152 | 153 | Список.ГруппаКонсюмера 154 | 155 | 156 | 157 | 158 | Список.Комментарий 159 | 160 | 161 | 162 | 163 |
164 |
165 | 166 | 167 | 168 | cfg:DynamicList 169 | 170 | true 171 | 172 | false 173 | true 174 | Catalog.НастройкиКафки 175 | 176 | 177 | Normal 178 | dfcece9d-5077-440b-b6b3-45a5cb4538eb 179 | 180 | 181 | Normal 182 | 88619765-ccb3-46c6-ac52-38e9c992ebd4 183 | 184 | 185 | Normal 186 | b75fecce-942b-4aed-abc9-e6a02e460fb3 187 | 188 | Normal 189 | 911b6018-f537-43e8-a417-da56b22f9aec 190 | 191 | 192 | 193 | 194 |
-------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаЭлемента.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | ФормаЭлемента 6 | 7 | 8 | ru 9 | Форма элемента 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 |
21 |
-------------------------------------------------------------------------------- /cf/Catalogs/НастройкиКафки/Forms/ФормаЭлемента/Ext/Form/Module.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Область ОбработчикиСобытийФОрмы 3 | 4 | &НаСервере 5 | Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) 6 | 7 | Если НЕ ЗначениеЗаполнено(Объект.Ссылка) Тогда 8 | Объект.УровеньЛогирования = "none"; 9 | КонецЕсли; 10 | 11 | ОбновитьЭлементыФормы(); 12 | 13 | КонецПроцедуры 14 | 15 | #КонецОбласти 16 | 17 | #Область ОбработчикиСобытийЭлементовШапкиФормы 18 | 19 | &НаКлиенте 20 | Процедура ОтправкаПриИзменении(Элемент) 21 | ОбновитьЭлементыФормы(); 22 | КонецПроцедуры 23 | 24 | &НаКлиенте 25 | Процедура ПолучениеПриИзменении(Элемент) 26 | ОбновитьЭлементыФормы(); 27 | КонецПроцедуры 28 | 29 | #КонецОбласти 30 | 31 | #Область СлужебныеПроцедурыИФункции 32 | 33 | &НаСервере 34 | Процедура ОбновитьЭлементыФормы() 35 | 36 | Элементы.ГруппаКонсюмера.Видимость = Объект.Получение; 37 | 38 | КонецПроцедуры 39 | 40 | #КонецОбласти -------------------------------------------------------------------------------- /cf/CommonModules/ОбщегоНазначения.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | ОбщегоНазначения 6 | 7 | 8 | ru 9 | Общего назначения 10 | 11 | 12 | 13 | false 14 | false 15 | true 16 | true 17 | false 18 | false 19 | false 20 | DontUse 21 | 22 | 23 | -------------------------------------------------------------------------------- /cf/CommonModules/ОбщегоНазначения/Ext/Module.bsl: -------------------------------------------------------------------------------- 1 | // Модуль для совместимости с БСП 2 | 3 | #Область ПрограммныйИнтерфейс 4 | 5 | // Показать сообщение пользователю 6 | // 7 | // Параметры: 8 | // ТекстСообщения - Строка - Текст сообщения 9 | // КлючДанных - ЛюбаяСсылка - Ключ данных сообщения 10 | // Поле - Строка - Поле формы к которому необходимо привязать сообщение 11 | // ПутьКДанным - Строка - Пусть к данным формы к которым надо привязать сообщение 12 | // Отказ - Булево - Флаг отказа, если указан, будет установлен в Итсина 13 | // 14 | Процедура СообщитьПользователю(Знач ТекстСообщения, Знач КлючДанных = Неопределено, Знач Поле = "", 15 | Знач ПутьКДанным = "", Отказ = Ложь) Экспорт 16 | 17 | Сообщение = Новый СообщениеПользователю; 18 | Сообщение.Текст = ТекстСообщения; 19 | Сообщение.КлючДанных = КлючДанных; 20 | Сообщение.Поле = Поле; 21 | Сообщение.ПутьКДанным = ПутьКДанным; 22 | Сообщение.Сообщить(); 23 | 24 | Отказ = Истина; 25 | 26 | КонецПроцедуры 27 | 28 | #КонецОбласти -------------------------------------------------------------------------------- /cf/CommonPictures/Кафка.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Кафка 6 | 7 | 8 | ru 9 | Кафка 10 | 11 | 12 | 13 | false 14 | false 15 | 16 | 17 | -------------------------------------------------------------------------------- /cf/CommonPictures/Кафка/Ext/Picture.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Picture.png 5 | false 6 | 7 | -------------------------------------------------------------------------------- /cf/CommonPictures/Кафка/Ext/Picture/Picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sv-sand/rdkafka-1c/cc05dfab6470d9639c85cf687d815f4712d6ca9b/cf/CommonPictures/Кафка/Ext/Picture/Picture.png -------------------------------------------------------------------------------- /cf/ConfigDumpInfo.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /cf/Configuration.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 9cd510cd-abfc-11d4-9434-004095e12fc7 7 | b0b7ca2f-305d-4577-87fb-a1a9db0b069f 8 | 9 | 10 | 9fcd25a0-4822-11d4-9414-008048da11f9 11 | 3988dfdb-b8bf-42cd-b63a-8736010d1e00 12 | 13 | 14 | e3687481-0a87-462c-a166-9f34594f9bba 15 | e0799882-e0c1-4ef5-b372-18bba25f20dd 16 | 17 | 18 | 9de14907-ec23-4a07-96f0-85521cb6b53b 19 | 9ab2a8cd-16c8-4e00-8cec-73f04eb56324 20 | 21 | 22 | 51f2d5d8-ea4d-4064-8892-82951750031e 23 | 34bda657-91b1-4670-85ef-9476c8abb720 24 | 25 | 26 | e68182ea-4237-4383-967f-90c1e3370bc7 27 | e6004127-3c62-4cd5-8312-468f35276694 28 | 29 | 30 | fb282519-d103-4dd3-bc12-cb271d631dfc 31 | bbe6548d-e5d5-440c-b27e-65b398cdcaf2 32 | 33 | 34 | 35 | ТестКомпонентыRdKafka1C 36 | 37 | 38 | ru 39 | Тест компоненты RdKafka1C 40 | 41 | 42 | 43 | 44 | Version8_3_26 45 | ManagedApplication 46 | 47 | PlatformApplication 48 | 49 | Russian 50 | 51 | sv-sand 52 | 1.3.1 53 | 54 | false 55 | false 56 | false 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | Biometrics 79 | true 80 | 81 | 82 | Location 83 | false 84 | 85 | 86 | BackgroundLocation 87 | false 88 | 89 | 90 | BluetoothPrinters 91 | false 92 | 93 | 94 | WiFiPrinters 95 | false 96 | 97 | 98 | Contacts 99 | false 100 | 101 | 102 | Calendars 103 | false 104 | 105 | 106 | PushNotifications 107 | false 108 | 109 | 110 | LocalNotifications 111 | false 112 | 113 | 114 | InAppPurchases 115 | false 116 | 117 | 118 | PersonalComputerFileExchange 119 | false 120 | 121 | 122 | Ads 123 | false 124 | 125 | 126 | NumberDialing 127 | false 128 | 129 | 130 | CallProcessing 131 | false 132 | 133 | 134 | CallLog 135 | false 136 | 137 | 138 | AutoSendSMS 139 | false 140 | 141 | 142 | ReceiveSMS 143 | false 144 | 145 | 146 | SMSLog 147 | false 148 | 149 | 150 | Camera 151 | false 152 | 153 | 154 | Microphone 155 | false 156 | 157 | 158 | MusicLibrary 159 | false 160 | 161 | 162 | PictureAndVideoLibraries 163 | false 164 | 165 | 166 | AudioPlaybackAndVibration 167 | false 168 | 169 | 170 | BackgroundAudioPlaybackAndVibration 171 | false 172 | 173 | 174 | InstallPackages 175 | false 176 | 177 | 178 | OSBackup 179 | true 180 | 181 | 182 | ApplicationUsageStatistics 183 | false 184 | 185 | 186 | BarcodeScanning 187 | false 188 | 189 | 190 | BackgroundAudioRecording 191 | false 192 | 193 | 194 | AllFilesAccess 195 | false 196 | 197 | 198 | Videoconferences 199 | false 200 | 201 | 202 | NFC 203 | false 204 | 205 | 206 | DocumentScanning 207 | false 208 | 209 | 210 | SpeechToText 211 | false 212 | 213 | 214 | Geofences 215 | false 216 | 217 | 218 | IncomingShareRequests 219 | false 220 | 221 | 222 | AllIncomingShareRequestsTypesProcessing 223 | false 224 | 225 | 226 | TextToSpeech 227 | false 228 | 229 | 230 | 231 | 232 | 233 | Normal 234 | 235 | 236 | Language.Русский 237 | 238 | 239 | 240 | 241 | ru 242 | sv-sand 243 | 244 | 245 | 246 | 247 | ru 248 | https://github.com/sv-sand 249 | 250 | 251 | 252 | Managed 253 | NotAutoFree 254 | Use 255 | Use 256 | Taxi 257 | DontUse 258 | Version8_3_25 259 | 260 | 261 | 262 | Русский 263 | Кафка 264 | Кафка 265 | ОбщегоНазначения 266 | НастройкиКафки 267 | БрокерыКафка 268 | КафкаКоннектор 269 | 270 | 271 | -------------------------------------------------------------------------------- /cf/DataProcessors/КафкаКоннектор.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 3f663c04-0b22-4379-8f44-748b52ce6e4c 7 | 850f3ac7-de56-4745-9afc-917fb5b6295b 8 | 9 | 10 | 7425bde0-ab94-42c1-91bf-6ac6088daaa6 11 | 7a59b462-00ec-419e-9e47-1798396e4b38 12 | 13 | 14 | 15 | КафкаКоннектор 16 | 17 | 18 | ru 19 | Кафка коннектор 20 | 21 | 22 | 23 | true 24 | DataProcessor.КафкаКоннектор.Form.Форма 25 | 26 | false 27 | 28 | 29 | 30 | 31 | 32 | 33 | ВерсияКомпоненты 34 | 35 | 36 | ru 37 | Версия компоненты 38 | 39 | 40 | 41 | 42 | xs:string 43 | 44 | 10 45 | Variable 46 | 47 | 48 | false 49 | 50 | 51 | 52 | false 53 | 54 | false 55 | false 56 | 57 | 58 | DontCheck 59 | Items 60 | 61 | 62 | Auto 63 | Auto 64 | 65 | 66 | Auto 67 | 68 | 69 | 70 | 71 | ВерсияRdKafka 72 | 73 | 74 | ru 75 | Версия RdKafka 76 | 77 | 78 | 79 | 80 | xs:string 81 | 82 | 20 83 | Variable 84 | 85 | 86 | false 87 | 88 | 89 | 90 | false 91 | 92 | false 93 | false 94 | 95 | 96 | DontCheck 97 | Items 98 | 99 | 100 | Auto 101 | Auto 102 | 103 | 104 | Auto 105 | 106 | 107 | 108 | 109 | Локаль 110 | 111 | 112 | ru 113 | Локаль 114 | 115 | 116 | 117 | 118 | xs:string 119 | 120 | 10 121 | Variable 122 | 123 | 124 | false 125 | 126 | 127 | 128 | false 129 | 130 | false 131 | false 132 | 133 | 134 | DontCheck 135 | Items 136 | 137 | 138 | Auto 139 | Auto 140 | 141 | 142 | Auto 143 | 144 | 145 |
Форма
146 | 147 |
148 |
149 |
-------------------------------------------------------------------------------- /cf/DataProcessors/КафкаКоннектор/Forms/Форма.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 |
4 | 5 | Форма 6 | 7 | 8 | ru 9 | Форма 10 | 11 | 12 | 13 | Managed 14 | false 15 | 16 | PlatformApplication 17 | MobilePlatformApplication 18 | 19 | 20 | 21 |
22 |
-------------------------------------------------------------------------------- /cf/DataProcessors/КафкаКоннектор/Forms/Форма/Ext/Form/Module.bsl: -------------------------------------------------------------------------------- 1 |  2 | #Область ОбработчикиСобытийФормы 3 | 4 | &НаСервере 5 | Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) 6 | 7 | ПартицияСообщенияПолучениеАвто = Истина; 8 | ОбновитьЭлементы(); 9 | 10 | КонецПроцедуры 11 | 12 | &НаКлиенте 13 | Процедура ПриОткрытии(Отказ) 14 | 15 | ОбновитьЭлементы(); 16 | 17 | КонецПроцедуры 18 | 19 | #КонецОбласти 20 | 21 | #Область ОбработчикиСобытийЭлементовФормы 22 | 23 | &НаКлиенте 24 | Процедура ПартицияСообщенияПолучениеАвтоПриИзменении(Элемент) 25 | 26 | УстановитьПартициюПолучение(); 27 | ОбновитьЭлементы(); 28 | 29 | КонецПроцедуры 30 | 31 | &НаКлиенте 32 | Процедура ПартицияСообщенияОтправкаАвтоПриИзменении(Элемент) 33 | ОбновитьЭлементы(); 34 | КонецПроцедуры 35 | 36 | &НаКлиенте 37 | Процедура ПартицияПолучениеПриИзменении(Элемент) 38 | УстановитьПартициюПолучение(); 39 | КонецПроцедуры 40 | 41 | #КонецОбласти 42 | 43 | #Область ОбработчикиКомандФормы 44 | 45 | &НаКлиенте 46 | Процедура СоздатьКоннектор(Команда) 47 | СоздатьКоннекторНаСервере(); 48 | КонецПроцедуры 49 | 50 | &НаСервере 51 | Процедура СоздатьКоннекторНаСервере() 52 | 53 | Если НЕ ЗначениеЗаполнено(НастройкиКафки) Тогда 54 | Возврат; 55 | КонецЕсли; 56 | 57 | Если ЗначениеЗаполнено(АдресКоннектора) 58 | И ВосстановитьКоннектор() <> Неопределено 59 | Тогда 60 | ВызватьИсключение "Коннектор уже создан"; 61 | КонецЕсли; 62 | 63 | Коннектор = Обработки.КафкаКоннектор.Создать(); 64 | Коннектор.Инициализировать(НастройкиКафки.Идентификатор); 65 | 66 | Объект.ВерсияКомпоненты = Коннектор.ВерсияКомпоненты; 67 | Объект.ВерсияRdKafka = Коннектор.ВерсияRdKafka; 68 | Объект.Локаль = Коннектор.Локаль; 69 | 70 | СохранитьКоннектор(Коннектор); 71 | 72 | КонецПроцедуры 73 | 74 | &НаКлиенте 75 | Процедура ОстановитьКоннектор(Команда) 76 | ОстановитьКоннекторНаСервере(); 77 | КонецПроцедуры 78 | 79 | &НаСервере 80 | Процедура ОстановитьКоннекторНаСервере() 81 | 82 | Коннектор = ВосстановитьКоннектор(); 83 | Коннектор.Остановить(); 84 | Коннектор = Неопределено; 85 | 86 | АдресКоннектора = ""; 87 | 88 | КонецПроцедуры 89 | 90 | #Область Продюсер 91 | 92 | &НаКлиенте 93 | Процедура ОтправитьСообщения(Команда) 94 | ОтправитьСообщенияНаСервере(); 95 | КонецПроцедуры 96 | 97 | &НаСервере 98 | Процедура ОтправитьСообщенияНаСервере() 99 | 100 | Коннектор = ВосстановитьКоннектор(); 101 | 102 | ДобавлятьНомерСообщения = КоличествоСообщенийКОтправке > 1 И Лев(СокрЛП(ТекстСообщенияКОтправке), 1) <> "{"; 103 | 104 | МассивСообщений = Новый Массив; 105 | Для НомерСообщения = 1 По КоличествоСообщенийКОтправке Цикл 106 | Текст = ТекстСообщенияКОтправке; 107 | Если ДобавлятьНомерСообщения Тогда 108 | Текст = Текст + " " + НомерСообщения; 109 | КонецЕсли; 110 | 111 | Если ПартицияСообщенияОтправкаАвто Тогда 112 | Сообщение = Коннектор.НовоеСообщение(Текст, КлючСообщения, ЗаголовкиСообщения); 113 | Иначе 114 | Сообщение = Коннектор.НовоеСообщение(Текст, КлючСообщения, ЗаголовкиСообщения, ПартицияСообщенияОтправка); 115 | КонецЕсли; 116 | 117 | МассивСообщений.Добавить(Сообщение); 118 | КонецЦикла; 119 | 120 | ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); 121 | Коннектор.ОтправитьСообщения(МассивСообщений); 122 | ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах(); 123 | 124 | ТекстСообщения = СтрШаблон("Отправлено %1 сообщений за %2 секунд", 125 | КоличествоСообщенийКОтправке, 126 | (ВремяОкончания - ВремяНачала) / 1000); 127 | ОбщегоНазначения.СообщитьПользователю(ТекстСообщения); 128 | 129 | СохранитьКоннектор(Коннектор); 130 | 131 | КонецПроцедуры 132 | 133 | &НаКлиенте 134 | Процедура ОчередьСообщенийПродюсера(Команда) 135 | ОчередьСообщенийПродюсераНаСервере(); 136 | КонецПроцедуры 137 | 138 | &НаСервере 139 | Процедура ОчередьСообщенийПродюсераНаСервере() 140 | 141 | Коннектор = ВосстановитьКоннектор(); 142 | ОбщегоНазначения.СообщитьПользователю("Очередь сообщений продюсера: " + Коннектор.ОчередьСообщенийПродюсера()); 143 | СохранитьКоннектор(Коннектор); 144 | 145 | КонецПроцедуры 146 | 147 | #КонецОбласти 148 | 149 | #Область Консюмер 150 | 151 | &НаКлиенте 152 | Процедура ПрочитатьСообщения(Команда) 153 | 154 | Если ЧитатьМетаданныеСообщений Тогда 155 | ПрочитатьСообщениеСМетаданнымиНаСервере(); 156 | Иначе 157 | ПрочитатьСообщениеНаСервере(); 158 | КонецЕсли; 159 | 160 | КонецПроцедуры 161 | 162 | &НаСервере 163 | Процедура ПрочитатьСообщениеСМетаданнымиНаСервере() 164 | 165 | Коннектор = ВосстановитьКоннектор(); 166 | 167 | // Сначала вычитываем все сообщения для замера времени 168 | ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); 169 | МассивСообщений = Коннектор.ПрочитатьСообщения(КоличествоСообщенийКЧтению); 170 | ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах(); 171 | 172 | ТекстСообщения = СтрШаблон("Загружено %1 сообщений за %2 секунд", 173 | МассивСообщений.Количество(), 174 | (ВремяОкончания - ВремяНачала) / 1000); 175 | ОбщегоНазначения.СообщитьПользователю(ТекстСообщения); 176 | 177 | // Теперь выводим сообщения, если количество больше 100 - это явно нагрузочный тест, нет смысла выводить их 178 | Если МассивСообщений.Количество() <= 100 Тогда 179 | Для каждого Сообщение Из МассивСообщений Цикл 180 | ЗаписьJSON = Новый ЗаписьJSON; 181 | ЗаписьJSON.УстановитьСтроку(); 182 | ЗаписатьJSON(ЗаписьJSON, Сообщение); 183 | ТекстСообщения = "Сообщение: " + ЗаписьJSON.Закрыть(); 184 | 185 | ОбщегоНазначения.СообщитьПользователю(ТекстСообщения);; 186 | КонецЦикла; 187 | КонецЕсли; 188 | 189 | СохранитьКоннектор(Коннектор); 190 | 191 | КонецПроцедуры 192 | 193 | &НаСервере 194 | Процедура ПрочитатьСообщениеНаСервере() 195 | 196 | Коннектор = ВосстановитьКоннектор(); 197 | 198 | // Сначала вычитываем все сообщения для замера времени 199 | ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах(); 200 | МассивСообщений = Новый Массив(); 201 | Пока МассивСообщений.Количество() < КоличествоСообщенийКЧтению 202 | И Коннектор.ПрочитатьСледующееСообщение() Цикл 203 | Сообщение = Коннектор.ПрочитатьСообщение(); 204 | МассивСообщений.Добавить(Сообщение); 205 | КонецЦикла; 206 | ВремяОкончания = ТекущаяУниверсальнаяДатаВМиллисекундах(); 207 | 208 | ТекстСообщения = СтрШаблон("Загружено %1 сообщений за %2 секунд", 209 | МассивСообщений.Количество(), 210 | (ВремяОкончания - ВремяНачала) / 1000); 211 | ОбщегоНазначения.СообщитьПользователю(ТекстСообщения); 212 | 213 | // Теперь выводим сообщения, если количество больше 100 - это явно нагрузочный тест, нет смысла выводить их 214 | Если МассивСообщений.Количество() <= 100 Тогда 215 | Для каждого Сообщение Из МассивСообщений Цикл 216 | ОбщегоНазначения.СообщитьПользователю(Сообщение); 217 | КонецЦикла; 218 | КонецЕсли; 219 | 220 | СохранитьКоннектор(Коннектор); 221 | 222 | КонецПроцедуры 223 | 224 | &НаКлиенте 225 | Процедура ЗафиксироватьОффсет(Команда) 226 | ЗафиксироватьОффсетНаСервере(); 227 | КонецПроцедуры 228 | 229 | &НаСервере 230 | Процедура ЗафиксироватьОффсетНаСервере() 231 | 232 | Коннектор = ВосстановитьКоннектор(); 233 | Коннектор.ЗафиксироватьОффсет(); 234 | СохранитьКоннектор(Коннектор); 235 | 236 | КонецПроцедуры 237 | 238 | &НаКлиенте 239 | Процедура Подписки(Команда) 240 | ПодпискиНаСервере(); 241 | КонецПроцедуры 242 | 243 | &НаСервере 244 | Процедура ПодпискиНаСервере() 245 | 246 | Коннектор = ВосстановитьКоннектор(); 247 | ОбщегоНазначения.СообщитьПользователю(Коннектор.Подписки()); 248 | СохранитьКоннектор(Коннектор); 249 | 250 | КонецПроцедуры 251 | 252 | &НаКлиенте 253 | Процедура Подписаться(Команда) 254 | ПодписатьсяНаСервере(); 255 | КонецПроцедуры 256 | 257 | &НаСервере 258 | Процедура ПодписатьсяНаСервере() 259 | 260 | Коннектор = ВосстановитьКоннектор(); 261 | Коннектор.Подписаться(); 262 | СохранитьКоннектор(Коннектор); 263 | 264 | КонецПроцедуры 265 | 266 | &НаКлиенте 267 | Процедура ПолучитьОффсет(Команда) 268 | ПолучитьОффсетНаСервере(); 269 | КонецПроцедуры 270 | 271 | &НаСервере 272 | Процедура ПолучитьОффсетНаСервере() 273 | 274 | Коннектор = ВосстановитьКоннектор(); 275 | Оффсет = Коннектор.ПолучитьОффсет(ПартицияСообщенияОтправка); 276 | СохранитьКоннектор(Коннектор); 277 | 278 | КонецПроцедуры 279 | 280 | &НаКлиенте 281 | Процедура ИзменитьОффсет(Команда) 282 | ИзменитьОффсетНаСервере(); 283 | КонецПроцедуры 284 | 285 | &НаСервере 286 | Процедура ИзменитьОффсетНаСервере() 287 | 288 | Коннектор = ВосстановитьКоннектор(); 289 | Коннектор.ИзменитьОффсет(ПартицияСообщенияОтправка, Оффсет); 290 | СохранитьКоннектор(Коннектор); 291 | 292 | КонецПроцедуры 293 | 294 | &НаКлиенте 295 | Процедура ОчередьСообщенийКонсюмера(Команда) 296 | ОчередьСообщенийКонсюмераНаСервере(); 297 | КонецПроцедуры 298 | 299 | &НаСервере 300 | Процедура ОчередьСообщенийКонсюмераНаСервере() 301 | 302 | Коннектор = ВосстановитьКоннектор(); 303 | ОбщегоНазначения.СообщитьПользователю("Очередь сообщений консюмера: " + Коннектор.ОчередьСообщенийКонсюмера()); 304 | СохранитьКоннектор(Коннектор); 305 | 306 | КонецПроцедуры 307 | 308 | #КонецОбласти 309 | 310 | #КонецОбласти 311 | 312 | #Область СлужебныеПроцедурыИФункции 313 | 314 | &НаСервере 315 | Процедура ОбновитьЭлементы() 316 | 317 | Элементы.ПартицияСообщенияОтправка.Доступность = НЕ ПартицияСообщенияОтправкаАвто; 318 | Элементы.ПартицияСообщенияПолучение.Доступность = НЕ ПартицияСообщенияПолучениеАвто; 319 | 320 | КонецПроцедуры 321 | 322 | &НаСервере 323 | Процедура СохранитьКоннектор(Коннектор) 324 | 325 | Структура = Новый Структура("Коннектор", Коннектор); 326 | АдресКоннектора = ПоместитьВоВременноеХранилище(Структура, УникальныйИдентификатор); 327 | 328 | КонецПроцедуры 329 | 330 | &НаСервере 331 | Функция ВосстановитьКоннектор() 332 | 333 | Если НЕ ЗначениеЗаполнено(АдресКоннектора) Тогда 334 | ВызватьИсключение "Коннектор не был создан"; 335 | КонецЕсли; 336 | 337 | Структура = ПолучитьИзВременногоХранилища(АдресКоннектора); 338 | 339 | Если Структура = Неопределено Тогда 340 | ВызватьИсключение "Не удалось получить коннектор из временного хранилища"; 341 | КонецЕсли; 342 | 343 | Возврат Структура.Коннектор; 344 | 345 | КонецФункции 346 | 347 | &НаСервере 348 | Процедура УстановитьПартициюПолучение() 349 | 350 | Коннектор = ВосстановитьКоннектор(); 351 | 352 | Если ПартицияСообщенияПолучениеАвто Тогда 353 | Коннектор.УстановитьПартицию(Неопределено); 354 | Иначе 355 | Коннектор.УстановитьПартицию(ПартицияСообщенияПолучение); 356 | КонецЕсли; 357 | 358 | СохранитьКоннектор(Коннектор); 359 | 360 | КонецПроцедуры 361 | 362 | #КонецОбласти 363 | -------------------------------------------------------------------------------- /cf/DataProcessors/КафкаКоннектор/Templates/RdKafka1C.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 16 | -------------------------------------------------------------------------------- /cf/DataProcessors/КафкаКоннектор/Templates/RdKafka1C/Ext/Template.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sv-sand/rdkafka-1c/cc05dfab6470d9639c85cf687d815f4712d6ca9b/cf/DataProcessors/КафкаКоннектор/Templates/RdKafka1C/Ext/Template.bin -------------------------------------------------------------------------------- /cf/Ext/ClientApplicationInterface.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | b553047f-c9aa-4157-978d-448ecad24248 6 | 7 | 8 | 9 | 10 | cbab57f2-a0f3-4f0a-89ea-4cb19570ab75 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /cf/Ext/HomePageWorkArea.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | TwoColumnsEqualWidth 4 | 5 | 6 |
DataProcessor.КафкаКоннектор.Form.Форма
7 | 10 8 | 9 | true 10 | 11 |
12 |
13 | 14 |
-------------------------------------------------------------------------------- /cf/Languages/Русский.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Русский 6 | 7 | 8 | ru 9 | Русский 10 | 11 | 12 | 13 | ru 14 | 15 | 16 | -------------------------------------------------------------------------------- /cf/Subsystems/Кафка.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Кафка 6 | 7 | 8 | ru 9 | Кафка 10 | 11 | 12 | 13 | true 14 | true 15 | false 16 | 17 | 18 | CommonPicture.Кафка 19 | true 20 | 21 | 22 | Catalog.НастройкиКафки 23 | DataProcessor.КафкаКоннектор 24 | Catalog.БрокерыКафка 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /doc/build.md: -------------------------------------------------------------------------------- 1 | # Сборка внешней комопненты RdKafka1C 2 | 3 | ## Требуемое программное обеспечение 4 | 5 | - [Платформа 1С Предприятие](https://1c.ru) 6 | - [MS Visual Studio C++](https://visualstudio.microsoft.com/) - для Windows 7 | - Компилятор g++ - для Linux 8 | - [MS VSCode](https://code.visualstudio.com/) 9 | - [CMake](https://github.com/Kitware/CMake/releases) 10 | - [vcpkg](https://github.com/microsoft/vcpkg) 11 | - [Docker](https://www.docker.com) 12 | 13 | ## Сборка 14 | 15 | Чтобы собрать проект необходимо: 16 | 17 | 1. Установить требуемое программное обеспечение 18 | 2. Выполнить первоначальную [настройку cmake](./doc/cmake.md) 19 | 3. Выполнить первоначальную [настройку vcpkg](./doc/vcpkg.md) 20 | 4. Запустить скрипт сборки `/build.bat` или `/build.sh` для Linux 21 | 5. Собрать [тестовый инстанс Apache Kafka](./doc/kafka.md) 22 | 23 | [*] Компилятор g++ в Linux можно установить командой: 24 | ```sh 25 | sudo apt install g++ 26 | ``` 27 | 28 | Результатом сборки будет динамическая библиотека для Windows `/build/Release/RdKafka1C.dll` или для Linux `/build/Release/libRdKafka1C.so` скомпилированная в режиме Relese, которую можно подключить к 1С, но нельзя отлаживать. Для отладки тредуется собрать библиотеку с параметром `--config "Release"` через IDE или скрипт cmake. 29 | 30 | ## Разработка 31 | 32 | Для разработки на Windows и Linux использовался [MS VSCode](https://code.visualstudio.com/) для отладки на Windows из 1С [MS Visual Studio C++](https://visualstudio.microsoft.com/). 33 | 34 | ## Тесты 35 | 36 | Компонента покрыта интеграционными тестами на основе библиотеки [GTest](https://github.com/google/googletest). Тесты проверяют корректность выполнения обмена и обработку ошибкок с тестовым инстансом Kafka. 37 | 38 | ```plantuml 39 | @startuml 40 | 41 | package "RdKafka1C.dll" { 42 | rectangle AddInNative #line:gray;text:gray 43 | rectangle RdKafka1C [ 44 | RdKafka1C 45 | Loger 46 | Config 47 | ... 48 | ] 49 | rectangle LibRdKafka as "librdkafka" 50 | } 51 | 52 | note top of RdKafka1C 53 | Основная 54 | логика 55 | компоененты 56 | end note 57 | 58 | note top of LibRdKafka 59 | Библиотека 60 | confluentinc/librdkafka 61 | end note 62 | 63 | rectangle Tests as "Тестовой приложение\ntesting.exe" 64 | rectangle Kafka as "Kafka" 65 | 66 | AddInNative ~ RdKafka1C 67 | Tests <-up-> RdKafka1C 68 | RdKafka1C <-> LibRdKafka 69 | LibRdKafka <-> Kafka 70 | 71 | @enduml 72 | ``` 73 | 74 | ## Известные проблемы 75 | 76 | ### Ошибка "No such file or directory" 77 | 78 | При сборке на Ubuntu Server может появиться ошибка `uuid/uuid.h: No such file or directory`. Необходимо установить пакет uuid. 79 | 80 | ```sh 81 | sudo apt install uuid-dev 82 | ``` 83 | 84 | ### Ошибка "CMake was unable to find a build program corresponding to "Unix Makefiles" 85 | 86 | При сборке на Ubuntu Server может появиться ошибка: 87 | 88 | CMake Error: CMake was unable to find a build program corresponding to "Unix Makefiles". CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool. 89 | -- Configuring incomplete, errors occurred! 90 | 91 | Необходимо установить утилиту make: 92 | 93 | ```sh 94 | sudo apt install make 95 | ``` 96 | 97 | ### Ошибка "No targets specified and no makefile found" 98 | 99 | При сборке на Ubuntu Server может появиться данная ошибка. Необходимо установить генератор makefiles для UNIX. 100 | 101 | ```sh 102 | sudo apt install make 103 | ``` 104 | -------------------------------------------------------------------------------- /doc/cmake.md: -------------------------------------------------------------------------------- 1 | # Система сборки cmake 2 | 3 | Для сборки компоненты использоваталь кросплатформенная система сборки [cmake](https://cmake.org). 4 | 5 | Порядок установки: 6 | 7 | 1. Проверить необходимую версию cmake в файле CMakeLisk.txt. Внимание: не нужно устанавливать более новую версию. 8 | 2. [Скачать билд](https://github.com/Kitware/CMake/releases) необходимой версии под свою операционную систему. 9 | 3. Распаковать в рабочий каталог. 10 | 4. Добавляем в переменную `PATH` каталог cmake: `D:\tools\cmake\bin` 11 | 5. Проверяем в командной строке доступ: `cmake --version` 12 | 13 | Также для Linux потребуется установить: 14 | 15 | 1. Компилятор c++, например g++ 16 | 17 | ```sh 18 | sudo apt install g++ 19 | ``` 20 | 2. Генератор makefiles для UNIX 21 | 22 | ```sh 23 | sudo apt install make 24 | ``` -------------------------------------------------------------------------------- /doc/how-to-use.md: -------------------------------------------------------------------------------- 1 | # Использование внешней компоненты 2 | 3 | В каталоге /cf размещена конфигурация с обработкой `КафкаКоннектор.epf`, которая: 4 | - Упрощает работу с компонентой через паттерн Коннектор 5 | - Определяет программный интерфейс компоненты 6 | - Форма обработки демонстрирует возможностей внешней компоненты 7 | 8 | ## Отправка сообщения 9 | 10 | ```bsl 11 | Коннектор = Обработки.КафкаКоннектор.Создать(); 12 | Коннектор.Инициализировать("идентификатор-настройки-кафки"); 13 | 14 | МассивСообщений = Новый Массив; 15 | Сообщение = Коннектор.НовоеСообщение("Текст сообщения", "Ключ сообщения", "Заголовок1: Значение"); 16 | МассивСообщений.Добавить(Сообщение); 17 | 18 | Коннектор.ОтправитьСообщения(МассивСообщений); 19 | Коннектор.Остановить(); 20 | ``` 21 | 22 | ## Чтение сообщения с метаданными 23 | 24 | ```bsl 25 | Коннектор = Обработки.КафкаКоннектор.Создать(); 26 | Коннектор.Инициализировать("идентификатор-настройки-кафки"); 27 | Сообщение = Коннектор.ПрочитатьСообщение(); 28 | Ключ = Коннектор.ПрочитатьКлючСообщения(); 29 | Заголовки = Коннектор.ПрочитатьЗаголовкиСообщения(); 30 | МетаданныеСообщения = Коннектор.ПрочитатьМетаданныеСообщения(); 31 | Коннектор.Остановить(); 32 | ``` 33 | 34 | ## Известные проблемы 35 | 36 | ### Иеролифы вместо русского текста в сообщениях 37 | 38 | > Рассмотрим пример для Linux, на Windows принцип такой же. 39 | 40 | Проверьте наличие русской локали ru_RU и ru_RU.UTF-8: 41 | 42 | ```sh 43 | locale -a 44 | ``` 45 | 46 | Если нет локали, её нужно добавить: 47 | 48 | ```sh 49 | sudo locale-gen ru_RU 50 | sudo locale-gen ru_RU.UTF-8 51 | sudo update-locale 52 | ``` 53 | 54 | Удалить лишние локали, если хотите вернуть все обратно: 55 | 56 | 1. Открыть файл `sudo nano /etc/locale.gen` 57 | 2. Закомментировать лишние локали 58 | 3. Сгенерировать локали `sudo locale-gen` 59 | 4. Обновить локали `sudo update-locale` 60 | -------------------------------------------------------------------------------- /doc/kafka.md: -------------------------------------------------------------------------------- 1 | # Тестовый Apache Kafka и веб интерфейс 2 | 3 | ## Установка контейнеров 4 | 5 | Необходимо выполнить команды в каталоге проекта: 6 | 7 | 1. Сборка образов Docker: 8 | 9 | ```sh 10 | docker-compose build 11 | ``` 12 | 13 | 2. Запуск контейнеров 14 | 15 | Также выполняет сброку контейнеров (можно не выполнять п.1) 16 | 17 | ```sh 18 | docker-compose up -d 19 | ``` 20 | 21 | Для остановки или повторного запуска контейнеров модно воспользоваться комадной строкой или UI Docker 22 | 23 | ## Настройка веб интерфейса 24 | 25 | В качестве UI Kafka выбран [provectuslabs/kafka-ui](https://github.com/provectus/kafka-ui) 26 | 27 | Веб интерфейс открывается в браузере, на странице [http://localhost:8082/](http://localhost:8082/). При первом входе Kefka UI предложит ввести настройки кластера, вводим: 28 | 29 | > Cluster name: kafka-broker 30 | > 31 | > Bootstrap Servers: kafka-broker 32 | > 33 | > Port: 9093 34 | 35 | Тестовый топик добавится при запуске тестов. 36 | -------------------------------------------------------------------------------- /doc/program-interface.md: -------------------------------------------------------------------------------- 1 | # Программный интерфейс 2 | 3 | ## Свойства компоненты 4 | 5 | | Имя на русском языке | Имя на английском языке | Чтение | Установка | Описание | 6 | | ----------------------------- | -------------------------------- | ------ | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 7 | | ВерсияКомпоненты | ComponentVersion | + | | Содержит текущую версию компоненты | 8 | | ВерсияRdKafka | RdKafkaVersion | + | | Содержит версию библиотеки libRdKafka которую использует | 9 | | Локаль | Locale | + | + | Системная локаль на машине, где запущена компонента, должна соответствовать отправляемым данным. Внимание! Если локаль en_EN, а вы пытаетесь отправить русский текст, он будет уходить в виде иероглифов. | 10 | | ЛогФайл | LogFile | + | | Имя файла в который пишутся логи. | 11 | | УровеньЛогирования | LogLevel | + | + | Текущий уровень логирования. | 12 | | ТаймаутОпераций | OperationTimeout | + | + | Время в миллисекундах выделенное для выполнения операций, если операция выполняется дольше, библиотека RdKafka прерывает её. | 13 | | Отказ | Error | + | | Флаг отказа. Сбрасывается при начале каждой операции, чтобы после выполнения операции можно было посмотреть её ошибки. Если ошибка произошла, будет заполнено свойство ОписаниеОшибки (ErrorDescription). | 14 | | ОписаниеОшибки | ErrorDescription | + | | Описание ошибки, если флаг Error был взведен. 15 | 16 | ## Методы компоненты 17 | 18 | | Имя на русском языке | Имя на английском языке | Описание | 19 | | --------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | 20 | | НачатьЛогирование | StartLogging | Запускает логирование операций компоненты и библиотеки libRrKafka. | 21 | | ОстановитьЛогирование | StopLogging | Останавливает логирование компоненты и библиотеки libRdKafka. | 22 | | УстановитьПараметр | SetConfigProperty | Устанавливает свойство конфигурации. | 23 | | ИнициализироватьПродюсера | InitProducer | Инициализирует продюсера. | 24 | | НачатьОтправку | StartProduce | Подготавливает новый массив сообщений к отправке. На данном этапе происходит очистка коллекции статусов сообщений отправленных в предыдущий раз. | 25 | | Отправить | Produce | Добавляет сообщение в асинхронную очередь отправки. | 26 | | Слить | Flush | Отправляет сообщения, которые еще не отправлены в Кафку и ожидает отчетов об отправке, таже заполняет коллекцию статусов сообщений. | 27 | | ОстановитьПродюсера | StopProducer | Останавливает продюсера. | 28 | | ОчередьСообщенийПродюсера | ProducerQueueLen | Возвращает длину очереди продюсера, в которой могут быть сообщения к отправке и технические сообщения. | 29 | | КоличествоНеДоставленныхСообщений | CountUndeliveredMessages | Возвращает количество не доставленных сообщений с момента вызова метода НачатьОтправку (StartProduce). | 30 | | СтатусСообщения | MessageStatus | Возвращает статус сообщения по идентификатору. | 31 | | ИнициализироватьКонсюмера | InitConsumer | Инициализирует консюмера. | 32 | | Прочитать | Consume | Читает сообщение из Кафки в компоненту. | 33 | | ДанныеСообщения | MessageData | Возвращает данные сообщения. | 34 | | МетаданныеСообщения | MessageMetadata | Возвращает метаданные сообщения. | 35 | | ОстановитьКонсюмера | StopConsumer | Останавливает консюмера. | 36 | | УстановитьПартицию | AssignPartition | Устанавливает партицию из которой будут читаться сообщения. | 37 | | ЗафиксироватьОффсет | CommitOffset | Фиксирует оффсет у сообщений, которые были прочитаны с момента инициализации консюмера или последней фиксации. | 38 | | ИзменитьОффсет | ChangeOffset | Изменяет оффсет у произвольного топика и партиции. Позволяет смещать оффсет назад и вперед. | 39 | | ПолучитьОффсет | CommittedOffset | Возвращает последний зафиксированный оффсет. | 40 | | ОчередьСообщенийКонсюмера | ConsumerQueueLen | Возвращает длину очереди консюмера, в которой могут быть сообщения фиксации оффсета, подписки на топик и технические сообщения. | 41 | | Подписаться | Subscribe | Подписывает консюмера на топик. | 42 | | Отписаться | Unsubscribe | Отписывает консюмера от всех топиков. | 43 | | Подписки | Subscription | Возвращает список топиков на которые подписан консюмер, разделеннх точкой-запятой. 44 | -------------------------------------------------------------------------------- /doc/res/structure.plantuml: -------------------------------------------------------------------------------- 1 | 2 | @startuml 3 | title Структура компоненты 4 | 5 | rectangle 1CPlatform as "Платформа 1С" 6 | 7 | package "RdKafka1C.dll" { 8 | rectangle AddInNative 9 | rectangle RdKafka1C [ 10 | RdKafka1C 11 | Loger 12 | Config 13 | ... 14 | ] 15 | rectangle LibRdKafka as "librdkafka" 16 | } 17 | 18 | note bottom of AddInNative 19 | Интерфейс 20 | компоненты 21 | end note 22 | 23 | note bottom of RdKafka1C 24 | Основная 25 | логика 26 | компоененты 27 | end note 28 | 29 | note bottom of LibRdKafka 30 | Библиотека 31 | confluentinc/librdkafka 32 | end note 33 | 34 | rectangle Kafka as "Kafka" 35 | 36 | 1CPlatform <-> AddInNative 37 | AddInNative <-> RdKafka1C 38 | RdKafka1C <-> LibRdKafka 39 | LibRdKafka <-> Kafka 40 | 41 | @enduml 42 | -------------------------------------------------------------------------------- /doc/res/structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sv-sand/rdkafka-1c/cc05dfab6470d9639c85cf687d815f4712d6ca9b/doc/res/structure.png -------------------------------------------------------------------------------- /doc/vcpkg.md: -------------------------------------------------------------------------------- 1 | # Менеджер пакетов vcpkg 2 | 3 | Для сборки компоненты понадобятся дополнительные библиотеки, которые можно загрузить и использовать через менеджер пакетов С++ vcpkg. Вы можете [скачать](https://github.com/microsoft/vcpkg) его самостоятельно в свой каталог. 4 | 5 | ## Установка 6 | 7 | 1. Клонируем репозиторий 8 | 9 | ```sh 10 | git clone https://github.com/microsoft/vcpkg.git 11 | ``` 12 | 13 | 2. Запускаем настройку среды 14 | 15 | ```sh 16 | bootstrap-vcpkg.bat 17 | ``` 18 | 19 | 3. Добавляем переменную окружения: 20 | 21 | ```sh 22 | VCPKG_ROOT=D:\tools\vcpkg 23 | ``` 24 | 25 | 4. Добавляем в переменную PATH каталог vcpkg: 26 | 27 | ```sh 28 | D:\tools\vcpkg 29 | ``` 30 | 31 | 5. Интегрируем в MS Visual Studio (для windows): 32 | 33 | ```sh 34 | vcpkg integrate install 35 | ``` 36 | 37 | ## Установка зависимостей: 38 | 39 | Для установки зависимостей нужно запустить скрипт `vcpkg-install`. Зависимости будут установлены в каталог `vcpkg_installed`. 40 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | services: 3 | 4 | kafka-broker: 5 | container_name: kafka-broker 6 | build: kafka-broker 7 | hostname: kafka-broker 8 | ports: 9 | - 9092:9092 10 | 11 | environment: 12 | KAFKA_NODE_ID: 1 13 | KAFKA_LISTENERS: 'CONTROLLER://:29093,PLAINTEXT_HOST://:9092,PLAINTEXT://:19092' 14 | KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT_HOST://localhost:9092,PLAINTEXT://kafka-broker:19092' 15 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT' 16 | KAFKA_PROCESS_ROLES: 'broker,controller' 17 | KAFKA_CONTROLLER_QUORUM_VOTERS: '1@kafka-broker:29093' 18 | KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT' 19 | KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER' 20 | CLUSTER_ID: '4L6g3nShT-eMCtK--X86sw' 21 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 22 | KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 23 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 24 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 25 | KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs' 26 | 27 | kafka-ui: 28 | container_name: kafka-ui 29 | build: kafka-ui 30 | hostname: kafka-ui 31 | ports: 32 | - 8082:8080 33 | 34 | environment: 35 | DYNAMIC_CONFIG_ENABLED: true 36 | 37 | depends_on: 38 | - kafka-broker 39 | -------------------------------------------------------------------------------- /generate.bat: -------------------------------------------------------------------------------- 1 | @set BUILD_DIR="./build" 2 | 3 | cmake -S . -B %BUILD_DIR% "-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake" 4 | 5 | @pause -------------------------------------------------------------------------------- /include/AddInDefBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Warning!!! 3 | * DO NOT ALTER THIS FILE! 4 | */ 5 | 6 | #ifndef __ADAPTER_DEF_H__ 7 | #define __ADAPTER_DEF_H__ 8 | #include "types.h" 9 | 10 | struct IInterface 11 | { 12 | }; 13 | 14 | 15 | enum Interfaces 16 | { 17 | eIMsgBox = 0, 18 | eIPlatformInfo, 19 | #if defined(__ANDROID__) 20 | eIAndroidComponentHelper, 21 | #endif 22 | eIAttachedInfo, 23 | }; 24 | 25 | //////////////////////////////////////////////////////////////////////////////// 26 | /** 27 | * This class serves as representation of a platform for external 28 | * components External components use it to communicate with a platform. 29 | * 30 | */ 31 | /// Base interface for object components. 32 | class IAddInDefBase 33 | { 34 | public: 35 | virtual ~IAddInDefBase() {} 36 | /// Adds the error message 37 | /** 38 | * @param wcode - error code 39 | * @param source - source of error 40 | * @param descr - description of error 41 | * @param scode - error code (HRESULT) 42 | * @return the result of 43 | */ 44 | virtual bool ADDIN_API AddError(unsigned short wcode, const WCHAR_T* source, 45 | const WCHAR_T* descr, long scode) = 0; 46 | 47 | /// Reads a property value 48 | /** 49 | * @param wszPropName -property name 50 | * @param pVal - value being returned 51 | * @param pErrCode - error code (if any error occured) 52 | * @param errDescriptor - error description (if any error occured) 53 | * @return the result of read. 54 | */ 55 | virtual bool ADDIN_API Read(WCHAR_T* wszPropName, 56 | tVariant* pVal, 57 | long *pErrCode, 58 | WCHAR_T** errDescriptor) = 0; 59 | /// Writes a property value 60 | /** 61 | * @param wszPropName - property name 62 | * @param pVar - new property value 63 | * @return the result of write. 64 | */ 65 | virtual bool ADDIN_API Write(WCHAR_T* wszPropName, 66 | tVariant *pVar) = 0; 67 | 68 | ///Registers profile components 69 | /** 70 | * @param wszProfileName - profile name 71 | * @return the result of 72 | */ 73 | virtual bool ADDIN_API RegisterProfileAs(WCHAR_T* wszProfileName) = 0; 74 | 75 | /// Changes the depth of event buffer 76 | /** 77 | * @param lDepth - new depth of event buffer 78 | * @return the result of 79 | */ 80 | virtual bool ADDIN_API SetEventBufferDepth(long lDepth) = 0; 81 | /// Returns the depth of event buffer 82 | /** 83 | * @return the depth of event buffer 84 | */ 85 | virtual long ADDIN_API GetEventBufferDepth() = 0; 86 | /// Registers external event 87 | /** 88 | * @param wszSource - source of event 89 | * @param wszMessage - event message 90 | * @param wszData - message parameters 91 | * @return the result of 92 | */ 93 | virtual bool ADDIN_API ExternalEvent(WCHAR_T* wszSource, 94 | WCHAR_T* wszMessage, 95 | WCHAR_T* wszData) = 0; 96 | /// Clears event buffer 97 | /** 98 | */ 99 | virtual void ADDIN_API CleanEventBuffer() = 0; 100 | 101 | /// Sets status line contents 102 | /** 103 | * @param wszStatusLine - new status line contents 104 | * @return the result of 105 | */ 106 | virtual bool ADDIN_API SetStatusLine(WCHAR_T* wszStatusLine) = 0; 107 | /// Resets the status line contents 108 | /** 109 | * @return the result of 110 | */ 111 | virtual void ADDIN_API ResetStatusLine() = 0; 112 | }; 113 | 114 | class IAddInDefBaseEx : 115 | public IAddInDefBase 116 | { 117 | public: 118 | virtual ~IAddInDefBaseEx() {} 119 | 120 | virtual IInterface* ADDIN_API GetInterface(Interfaces iface) = 0; 121 | }; 122 | 123 | struct IMsgBox : 124 | public IInterface 125 | { 126 | virtual bool ADDIN_API Confirm(const WCHAR_T* queryText, tVariant* retVal) = 0; 127 | 128 | virtual bool ADDIN_API Alert(const WCHAR_T* text) = 0; 129 | }; 130 | 131 | struct IPlatformInfo : 132 | public IInterface 133 | { 134 | enum AppType 135 | { 136 | eAppUnknown = -1, 137 | eAppThinClient = 0, 138 | eAppThickClient, 139 | eAppWebClient, 140 | eAppServer, 141 | eAppExtConn, 142 | eAppMobileClient, 143 | eAppMobileServer, 144 | }; 145 | 146 | struct AppInfo 147 | { 148 | const WCHAR_T* AppVersion; 149 | const WCHAR_T* UserAgentInformation; 150 | AppType Application; 151 | }; 152 | 153 | virtual const AppInfo* ADDIN_API GetPlatformInfo() = 0; 154 | }; 155 | struct IAttachedInfo : 156 | public IInterface 157 | { 158 | enum AttachedType 159 | { 160 | eAttachedIsolated = 0, 161 | eAttachedNotIsolated, 162 | }; 163 | virtual const AttachedType ADDIN_API GetAttachedInfo() = 0; 164 | }; 165 | #endif //__ADAPTER_DEF_H__ 166 | -------------------------------------------------------------------------------- /include/ComponentBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Warning!!! 3 | * DO NOT ALTER THIS FILE! 4 | */ 5 | 6 | 7 | #ifndef __COMPONENT_BASE_H__ 8 | #define __COMPONENT_BASE_H__ 9 | 10 | #include "types.h" 11 | //////////////////////////////////////////////////////////////////////////////// 12 | /** 13 | * The given interface is intended for initialization and 14 | * uninitialization of component and its adjustments 15 | */ 16 | /// Interface of component initialization. 17 | class IInitDoneBase 18 | { 19 | public: 20 | virtual ~IInitDoneBase() {} 21 | /// Initializes component 22 | /** 23 | * @param disp - 1C:Enterpise interface 24 | * @return the result of 25 | */ 26 | virtual bool ADDIN_API Init(void* disp) = 0; 27 | /// Sets the memory manager 28 | /* 29 | * @param mem - pointer to memory manager interface. 30 | * @return the result of 31 | */ 32 | virtual bool ADDIN_API setMemManager(void* mem) = 0; 33 | 34 | /// Returns component version 35 | /** 36 | * @return - component version (2000 - version 2) 37 | */ 38 | virtual long ADDIN_API GetInfo() = 0; 39 | 40 | /// Uninitializes component 41 | /** 42 | * Component here should release all consumed resources. 43 | */ 44 | virtual void ADDIN_API Done() = 0; 45 | 46 | }; 47 | /////////////////////////////////////////////////////////////////////////// 48 | /** 49 | * The given interface defines methods that are intented to be used by the Platform 50 | */ 51 | /// Interface describing extension of language. 52 | class ILanguageExtenderBase 53 | { 54 | public: 55 | virtual ~ILanguageExtenderBase(){} 56 | /// Registers language extension 57 | /** 58 | * @param wsExtensionName - extension name 59 | * @return the result of 60 | */ 61 | virtual bool ADDIN_API RegisterExtensionAs(WCHAR_T** wsExtensionName) = 0; 62 | 63 | /// Returns number of component properties 64 | /** 65 | * @return number of properties 66 | */ 67 | virtual long ADDIN_API GetNProps() = 0; 68 | 69 | /// Finds property by name 70 | /** 71 | * @param wsPropName - property name 72 | * @return property index or -1, if it is not found 73 | */ 74 | virtual long ADDIN_API FindProp(const WCHAR_T* wsPropName) = 0; 75 | 76 | /// Returns property name 77 | /** 78 | * @param lPropNum - property index (starting with 0) 79 | * @param lPropAlias - 0 - international alias, 80 | * 1 - russian alias. (International alias is required) 81 | * @return proeprty name or 0 if it is not found 82 | */ 83 | virtual const WCHAR_T* ADDIN_API GetPropName(long lPropNum, 84 | long lPropAlias) = 0; 85 | 86 | /// Returns property value 87 | /** 88 | * @param lPropNum - property index (starting with 0) 89 | * @param pvarPropVal - the pointer to a variable for property value 90 | * @return the result of 91 | */ 92 | virtual bool ADDIN_API GetPropVal(const long lPropNum, 93 | tVariant* pvarPropVal) = 0; 94 | 95 | /// Sets the property value 96 | /** 97 | * @param lPropNum - property index (starting with 0) 98 | * @param varPropVal - the pointer to a variable for property value 99 | * @return the result of 100 | */ 101 | virtual bool ADDIN_API SetPropVal(const long lPropNum, 102 | tVariant* varPropVal) = 0; 103 | 104 | /// Is property readable? 105 | /** 106 | * @param lPropNum - property index (starting with 0) 107 | * @return true if property is readable 108 | */ 109 | virtual bool ADDIN_API IsPropReadable(const long lPropNum) = 0; 110 | 111 | /// Is property writable? 112 | /** 113 | * @param lPropNum - property index (starting with 0) 114 | * @return true if property is writable 115 | */ 116 | virtual bool ADDIN_API IsPropWritable(const long lPropNum) = 0; 117 | 118 | /// Returns number of component methods 119 | /** 120 | * @return number of component methods 121 | */ 122 | virtual long ADDIN_API GetNMethods() = 0; 123 | 124 | /// Finds a method by name 125 | /** 126 | * @param wsMethodName - method name 127 | * @return - method index 128 | */ 129 | virtual long ADDIN_API FindMethod(const WCHAR_T* wsMethodName) = 0; 130 | 131 | /// Returns method name 132 | /** 133 | * @param lMethodNum - method index(starting with 0) 134 | * @param lMethodAlias - 0 - international alias, 135 | * 1 - russian alias. (International alias is required) 136 | * @return method name or 0 if method is not found 137 | */ 138 | virtual const WCHAR_T* ADDIN_API GetMethodName(const long lMethodNum, 139 | const long lMethodAlias) = 0; 140 | 141 | /// Returns number of method parameters 142 | /** 143 | * @param lMethodNum - method index (starting with 0) 144 | * @return number of parameters 145 | */ 146 | virtual long ADDIN_API GetNParams(const long lMethodNum) = 0; 147 | 148 | /// Returns default value of method parameter 149 | /** 150 | * @param lMethodNum - method index(starting with 0) 151 | * @param lParamNum - parameter index (starting with 0) 152 | * @param pvarParamDefValue - the pointer to a variable for default value 153 | * @return the result of 154 | */ 155 | virtual bool ADDIN_API GetParamDefValue(const long lMethodNum, 156 | const long lParamNum, 157 | tVariant *pvarParamDefValue) = 0; 158 | 159 | /// Does the method have a return value? 160 | /** 161 | * @param lMethodNum - method index (starting with 0) 162 | * @return true if the method has a return value 163 | */ 164 | virtual bool ADDIN_API HasRetVal(const long lMethodNum) = 0; 165 | 166 | /// Calls the method as a procedure 167 | /** 168 | * @param lMethodNum - method index (starting with 0) 169 | * @param paParams - the pointer to array of method parameters 170 | * @param lSizeArray - the size of array 171 | * @return the result of 172 | */ 173 | virtual bool ADDIN_API CallAsProc(const long lMethodNum, 174 | tVariant* paParams, 175 | const long lSizeArray) = 0; 176 | 177 | /// Calls the method as a function 178 | /** 179 | * @param lMethodNum - method index (starting with 0) 180 | * @param pvarRetValue - the pointer to returned value 181 | * @param paParams - the pointer to array of method parameters 182 | * @param lSizeArray - the size of array 183 | * @return the result of 184 | */ 185 | virtual bool ADDIN_API CallAsFunc(const long lMethodNum, 186 | tVariant* pvarRetValue, 187 | tVariant* paParams, 188 | const long lSizeArray) = 0; 189 | }; 190 | /////////////////////////////////////////////////////////////////////////// 191 | /** 192 | * This interface is used to change component locale 193 | */ 194 | /// Base interface for component localization. 195 | class LocaleBase 196 | { 197 | public: 198 | virtual ~LocaleBase(){} 199 | /// Changes component locale 200 | /** 201 | * @param loc - new locale (for Windows - rus_RUS, 202 | * for Linux - ru_RU, etc...) 203 | */ 204 | virtual void ADDIN_API SetLocale(const WCHAR_T* loc) = 0; 205 | }; 206 | 207 | /////////////////////////////////////////////////////////////////////// 208 | /// class UserLanguageBase- интерфейс изменения языка компоненты 209 | /** 210 | * Этот интерфейс предназначен для изменения локализации компоненты 211 | */ 212 | class UserLanguageBase 213 | { 214 | public: 215 | virtual ~UserLanguageBase() {} 216 | /// Изменение локали компоненты 217 | /** 218 | * @param const char16_t* lang - устанавливаемый язык (ru, etc...) 219 | */ 220 | virtual void ADDIN_API SetUserInterfaceLanguageCode(const WCHAR_T* lang) = 0; 221 | }; 222 | 223 | /////////////////////////////////////////////////////////////////////////// 224 | /** 225 | * The given interface is generalized, for its obligatory inheritance 226 | * in implementing components. 227 | */ 228 | /// Base interface describing object as a set of properties and methods. 229 | class IComponentBase : 230 | public IInitDoneBase, 231 | public ILanguageExtenderBase, 232 | public LocaleBase, 233 | public UserLanguageBase 234 | { 235 | public: 236 | virtual ~IComponentBase(){} 237 | }; 238 | 239 | enum AppCapabilities 240 | { 241 | eAppCapabilitiesInvalid = -1, 242 | eAppCapabilities1 = 1, 243 | eAppCapabilities2 = 2, 244 | eAppCapabilities3 = 3, 245 | eAppCapabilitiesLast = eAppCapabilities3, 246 | }; 247 | 248 | enum AttachType 249 | { 250 | eCanAttachNotIsolated = 1, 251 | eCanAttachIsolated, 252 | eCanAttachAny, 253 | }; 254 | 255 | /// Announcements of exported functions 256 | /** 257 | * These functions should be implemented that component can be loaded and created. 258 | */ 259 | extern "C" long GetClassObject(const WCHAR_T*, IComponentBase** pIntf); 260 | extern "C" long DestroyObject(IComponentBase** pIntf); 261 | extern "C" const WCHAR_T* GetClassNames(); 262 | extern "C" AppCapabilities SetPlatformCapabilities(const AppCapabilities capabilities); 263 | extern "C" AttachType GetAttachType(); 264 | 265 | typedef long (*GetClassObjectPtr)(const WCHAR_T* wsName, IComponentBase** pIntf); 266 | typedef long (*DestroyObjectPtr)(IComponentBase** pIntf); 267 | typedef const WCHAR_T* (*GetClassNamesPtr)(); 268 | typedef AppCapabilities (*SetPlatformCapabilitiesPtr)(const AppCapabilities capabilities); 269 | typedef AttachType (*GetAttachTypePtr)(); 270 | 271 | #endif //__COMPONENT_BASE_H__ 272 | -------------------------------------------------------------------------------- /include/IMemoryManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Warning!!! 3 | * DO NOT ALTER THIS FILE! 4 | */ 5 | 6 | 7 | #ifndef __IMEMORY_MANAGER_H__ 8 | #define __IMEMORY_MANAGER_H__ 9 | 10 | /////////////////////////////////////////////////////////////////////////////// 11 | /** 12 | * The given class allocates and releases memory for a component 13 | */ 14 | /// Interface representing memory manager. 15 | class IMemoryManager 16 | { 17 | public: 18 | virtual ~IMemoryManager() {} 19 | /// Allocates memory of specified size 20 | /** 21 | * @param pMemory - the double pointer to variable, that will hold newly 22 | * allocated block of memory of NULL if allocation fails. 23 | * @param ulCountByte - memory size 24 | * @return the result of 25 | */ 26 | virtual bool ADDIN_API AllocMemory (void** pMemory, unsigned long ulCountByte) = 0; 27 | /// Releases memory 28 | /** 29 | * @param pMemory - The double pointer to the memory block being released 30 | */ 31 | virtual void ADDIN_API FreeMemory (void** pMemory) = 0; 32 | }; 33 | 34 | #endif //__IMEMORY_MANAGER_H__ 35 | -------------------------------------------------------------------------------- /include/com.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __COM_H__ 3 | #define __COM_H__ 4 | 5 | #if defined(__linux__) || defined(__APPLE__) || defined(__ANDROID__) 6 | 7 | #ifdef __ANDROID__ 8 | 9 | typedef struct { 10 | unsigned int Data1; 11 | unsigned short Data2; 12 | unsigned short Data3; 13 | unsigned char Data4[ 8 ]; 14 | } uuid_t; 15 | 16 | #else 17 | #include 18 | #endif //__ANDROID__ 19 | 20 | #ifndef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ // iOS 21 | #include 22 | #endif //!__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ 23 | 24 | #pragma GCC system_header 25 | 26 | typedef long HRESULT; 27 | 28 | #ifdef __GNUC__ 29 | #define STDMETHODCALLTYPE __attribute__ ((__stdcall__)) 30 | #define DECLSPEC_NOTHROW __attribute__ ((nothrow)) 31 | #define STDMETHOD(method) virtual DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE method 32 | #else 33 | #define STDMETHODCALLTYPE 34 | #endif 35 | 36 | #define __stdcall STDMETHODCALLTYPE 37 | #define near 38 | #define far 39 | #define CONST const 40 | #define FAR far 41 | 42 | typedef unsigned long DWORD; 43 | #ifndef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ // iOS 44 | typedef int BOOL; 45 | #elif defined(__LP64__) 46 | typedef bool BOOL; 47 | #else 48 | typedef signed char BOOL; 49 | #endif //!__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ 50 | 51 | typedef void VOID; 52 | typedef short SHORT; 53 | typedef unsigned char BYTE; 54 | typedef unsigned short WORD; 55 | typedef float FLOAT; 56 | typedef FLOAT *PFLOAT; 57 | typedef BOOL near *PBOOL; 58 | typedef BOOL far *LPBOOL; 59 | typedef BYTE near *PBYTE; 60 | typedef BYTE far *LPBYTE; 61 | typedef int near *PINT; 62 | typedef int far *LPINT; 63 | typedef WORD near *PWORD; 64 | typedef WORD far *LPWORD; 65 | typedef long far *LPLONG; 66 | typedef DWORD near *PDWORD; 67 | typedef DWORD far *LPDWORD; 68 | typedef void far *LPVOID; 69 | typedef CONST void far *LPCVOID; 70 | typedef wchar_t *BSTR; 71 | typedef long SCODE; 72 | typedef int INT; 73 | typedef unsigned int UINT; 74 | typedef unsigned int *PUINT; 75 | typedef wchar_t WCHAR; 76 | typedef wchar_t OLECHAR; 77 | typedef wchar_t *LPOLESTR; 78 | typedef const wchar_t *LPCOLESTR; 79 | typedef DWORD LCID; 80 | typedef PDWORD PLCID; 81 | typedef long LONG; 82 | typedef unsigned long ULONG; 83 | typedef long long LONGLONG; 84 | typedef unsigned long long ULONGLONG; 85 | typedef LONG DISPID; 86 | typedef double DOUBLE; 87 | typedef double DATE; 88 | typedef short VARIANT_BOOL; 89 | typedef void *PVOID; 90 | typedef char CHAR; 91 | typedef CONST CHAR *LPCSTR; 92 | typedef unsigned short USHORT; 93 | typedef void *HMODULE; 94 | #define OLESTR(str) L##str 95 | 96 | typedef uuid_t GUID; 97 | typedef uuid_t IID; 98 | typedef uuid_t UUID; 99 | #define REFIID const IID & 100 | #define MAX_PATH 260 101 | 102 | #define IsEqualIID(x,y) uuid_compare((x),(y)) 103 | #ifdef __GNUC__ 104 | #define LoadLibraryA(x) dlopen((x), RTLD_LAZY) 105 | #define FreeLibrary(x) dlclose((x)) 106 | #define GetProcAddress(x, y) dlsym((x), (y)) 107 | #endif //__GNUC__ 108 | 109 | #define E_FAIL 0x80004005L 110 | #define S_OK 0L 111 | #define S_FALSE 1L 112 | #define E_NOINTERFACE 0x80004002L 113 | #define E_NOTIMPL 0x80004001L 114 | #define E_INVALIDARG 0x80070057L 115 | #define E_UNEXPECTED 0x8000FFFFL 116 | #define E_OUTOFMEMORY 0x8007000EL 117 | #define DISP_E_UNKNOWNNAME 0x80020006L 118 | #define DISPID_UNKNOWN ( -1 ) 119 | #define TRUE 1 120 | #define FALSE 0 121 | 122 | typedef long ITypeInfo; 123 | 124 | #if defined (__GNUC__) && !defined (NONAMELESSUNION) 125 | __extension__ /* no named members */ 126 | #endif 127 | union tCY { 128 | __extension__ struct 129 | { 130 | unsigned long Lo; 131 | long Hi; 132 | }; 133 | long long int64; 134 | }; 135 | typedef union tagCY CY; 136 | #define CLSIDFromString(x,y) uuid_parse((x),(unsigned char*)(y)) 137 | 138 | #endif //defined(__linux__) || defined(__APPLE__) 139 | 140 | #endif //__COM_H__ 141 | -------------------------------------------------------------------------------- /include/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | #if !defined(__linux__) && !defined(__APPLE__) 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | #endif //__linux__ 20 | -------------------------------------------------------------------------------- /include/md5.h: -------------------------------------------------------------------------------- 1 | /* MD5 2 | converted to C++ class by Frank Thilo (thilo@unix-ag.org) 3 | for bzflag (http://www.bzflag.org) 4 | 5 | based on: 6 | 7 | md5.h and md5.c 8 | reference implementation of RFC 1321 9 | 10 | Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 11 | rights reserved. 12 | 13 | License to copy and use this software is granted provided that it 14 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 15 | Algorithm" in all material mentioning or referencing this software 16 | or this function. 17 | 18 | License is also granted to make and use derivative works provided 19 | that such works are identified as "derived from the RSA Data 20 | Security, Inc. MD5 Message-Digest Algorithm" in all material 21 | mentioning or referencing the derived work. 22 | 23 | RSA Data Security, Inc. makes no representations concerning either 24 | the merchantability of this software or the suitability of this 25 | software for any particular purpose. It is provided "as is" 26 | without express or implied warranty of any kind. 27 | 28 | These notices must be retained in any copies of any part of this 29 | documentation and/or software. 30 | 31 | */ 32 | 33 | #ifndef BZF_MD5_H 34 | #define BZF_MD5_H 35 | 36 | #include 37 | #include 38 | 39 | 40 | // a small class for calculating MD5 hashes of strings or byte arrays 41 | // it is not meant to be fast or secure 42 | // 43 | // usage: 1) feed it blocks of uchars with update() 44 | // 2) finalize() 45 | // 3) get hexdigest() string 46 | // or 47 | // MD5(std::string).hexdigest() 48 | // 49 | // assumes that char is 8 bit and int is 32 bit 50 | class MD5 51 | { 52 | public: 53 | typedef unsigned int size_type; // must be 32bit 54 | 55 | MD5(); 56 | MD5(const std::string& text); 57 | void update(const unsigned char *buf, size_type length); 58 | void update(const char *buf, size_type length); 59 | MD5& finalize(); 60 | std::string hexdigest() const; 61 | friend std::ostream& operator<<(std::ostream&, MD5 md5); 62 | 63 | private: 64 | void init(); 65 | typedef unsigned char uint1; // 8bit 66 | typedef unsigned int uint4; // 32bit 67 | enum {blocksize = 64}; // VC6 won't eat a const static int here 68 | 69 | void transform(const uint1 block[blocksize]); 70 | static void decode(uint4 output[], const uint1 input[], size_type len); 71 | static void encode(uint1 output[], const uint4 input[], size_type len); 72 | 73 | bool finalized; 74 | uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk 75 | uint4 count[2]; // 64bit counter for number of bits (lo, hi) 76 | uint4 state[4]; // digest so far 77 | uint1 digest[16]; // the result 78 | 79 | // low level logic operations 80 | static inline uint4 F(uint4 x, uint4 y, uint4 z); 81 | static inline uint4 G(uint4 x, uint4 y, uint4 z); 82 | static inline uint4 H(uint4 x, uint4 y, uint4 z); 83 | static inline uint4 I(uint4 x, uint4 y, uint4 z); 84 | static inline uint4 rotate_left(uint4 x, int n); 85 | static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 86 | static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 87 | static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 88 | static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac); 89 | }; 90 | 91 | std::string md5(const std::string str); 92 | 93 | #endif -------------------------------------------------------------------------------- /include/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by AddIn.rc 4 | // 5 | #define IDS_PROJNAME 100 6 | #define IDR_ADDIN 101 7 | #define IDS_TERM_MSGBOX 101 8 | #define IDR_ADDINCOM 102 9 | #define IDS_PROPPAGE_CAPTION 103 10 | #define IDS_MESSAGE_SOURCE 105 11 | #define IDS_TERM_ENABLED 106 12 | #define IDS_TERM_ENABLE 107 13 | #define IDS_TERM_DISABLE 108 14 | #define IDS_TERM_SHOWSTATUS 109 15 | #define IDS_TERM_STARTTIMER 110 16 | #define IDS_ERROR_SOURCE 111 17 | #define IDS_ERROR_DESCRIPTION 112 18 | #define IDS_TERM_STOPTIMER 113 19 | #define IDS_TERM_TIMERPRESENT 114 20 | #define IDS_TERM_OPENFORM 115 21 | #define IDS_ERROR_OPENFORMERROR 116 22 | #define IDS_TERM_LANGCODE 117 23 | 24 | // Next default values for new objects 25 | // 26 | #ifdef APSTUDIO_INVOKED 27 | #ifndef APSTUDIO_READONLY_SYMBOLS 28 | #define _APS_NEXT_RESOURCE_VALUE 201 29 | #define _APS_NEXT_COMMAND_VALUE 32768 30 | #define _APS_NEXT_CONTROL_VALUE 201 31 | #define _APS_NEXT_SYMED_VALUE 103 32 | #endif 33 | #endif 34 | -------------------------------------------------------------------------------- /include/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // AddInNative.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /include/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | #ifndef __STDAFX_H__ 6 | #define __STDAFX_H__ 7 | 8 | #ifdef _WINDOWS 9 | #define NOMINMAX 10 | #include 11 | #endif //_WINDOWS 12 | 13 | #if defined(__linux__) || defined(__APPLE__) 14 | #define LINUX_OR_MACOS 15 | #endif 16 | 17 | #endif //__STDAFX_H__ 18 | -------------------------------------------------------------------------------- /include/targetver.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | // The following macros define the minimum required platform. The minimum required platform 5 | // is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run 6 | // your application. The macros work by enabling all features available on platform versions up to and 7 | // including the version specified. 8 | 9 | // Modify the following defines if you have to target a platform prior to the ones specified below. 10 | // Refer to MSDN for the latest info on corresponding values for different platforms. 11 | #ifndef WINVER // Specifies that the minimum required platform is Windows Vista. 12 | #define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. 13 | #endif 14 | 15 | #ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. 16 | #define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. 17 | #endif 18 | 19 | #ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. 20 | #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. 21 | #endif 22 | 23 | #ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. 24 | #define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. 25 | #endif 26 | 27 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __CON_TYPES_H__ 3 | #define __CON_TYPES_H__ 4 | 5 | #if defined(_WINDOWS) || defined(WINAPI_FAMILY) 6 | #define NOMINMAX 7 | #include 8 | #endif 9 | 10 | #if defined(WINAPI_FAMILY) 11 | #include 12 | #endif 13 | 14 | #if __GNUC__ >=3 15 | #pragma GCC system_header 16 | #endif 17 | 18 | #include "com.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define EXTERN_C extern "C" 25 | 26 | #ifdef __GNUC__ 27 | #define _ANONYMOUS_UNION __extension__ 28 | #define _ANONYMOUS_STRUCT __extension__ 29 | #else 30 | #define _ANONYMOUS_UNION 31 | #define _ANONYMOUS_STRUCT 32 | #endif //__GNUC__ 33 | 34 | #ifdef NONAMELESSUNION 35 | #define __VARIANT_NAME_1 u 36 | #define __VARIANT_NAME_2 iface 37 | #define __VARIANT_NAME_3 str 38 | #define __VARIANT_NAME_4 wstr 39 | #else 40 | #define __VARIANT_NAME_1 41 | #define __VARIANT_NAME_2 42 | #define __VARIANT_NAME_3 43 | #define __VARIANT_NAME_4 44 | #endif //NONAMELESSUNION 45 | 46 | #define RESULT_FROM_ERRNO(x) ((long)(x) <= 0 ? ((long)(x)) \ 47 | : ((long) (((x) & 0x0000FFFF) | (BASE_ERRNO << 16) | 0x80000000))) 48 | 49 | #define ADDIN_E_NONE 1000 50 | #define ADDIN_E_ORDINARY 1001 51 | #define ADDIN_E_ATTENTION 1002 52 | #define ADDIN_E_IMPORTANT 1003 53 | #define ADDIN_E_VERY_IMPORTANT 1004 54 | #define ADDIN_E_INFO 1005 55 | #define ADDIN_E_FAIL 1006 56 | #define ADDIN_E_MSGBOX_ATTENTION 1007 57 | #define ADDIN_E_MSGBOX_INFO 1008 58 | #define ADDIN_E_MSGBOX_FAIL 1009 59 | 60 | #ifndef ADDIN_API 61 | #ifdef _WINDOWS 62 | #define ADDIN_API __stdcall 63 | #else 64 | //#define ADDIN_API __attribute__ ((__stdcall__)) 65 | #define ADDIN_API 66 | #endif //_WINDOWS 67 | #endif //ADDIN_API 68 | 69 | #include 70 | 71 | #ifdef _WINDOWS 72 | #define WCHAR_T char16_t 73 | #else 74 | #define WCHAR_T char16_t 75 | #endif //_WINDOWS 76 | typedef unsigned short TYPEVAR; 77 | enum ENUMVAR 78 | { 79 | VTYPE_EMPTY = 0, 80 | VTYPE_NULL, 81 | VTYPE_I2, //int16_t 82 | VTYPE_I4, //int32_t 83 | VTYPE_R4, //float 84 | VTYPE_R8, //double 85 | VTYPE_DATE, //DATE (double) 86 | VTYPE_TM, //struct tm 87 | VTYPE_PSTR, //struct str string 88 | VTYPE_INTERFACE, //struct iface 89 | VTYPE_ERROR, //int32_t errCode 90 | VTYPE_BOOL, //bool 91 | VTYPE_VARIANT, //struct _tVariant * 92 | VTYPE_I1, //int8_t 93 | VTYPE_UI1, //uint8_t 94 | VTYPE_UI2, //uint16_t 95 | VTYPE_UI4, //uint32_t 96 | VTYPE_I8, //int64_t 97 | VTYPE_UI8, //uint64_t 98 | VTYPE_INT, //int Depends on architecture 99 | VTYPE_UINT, //unsigned int Depends on architecture 100 | VTYPE_HRESULT, //long hRes 101 | VTYPE_PWSTR, //struct wstr 102 | VTYPE_BLOB, //means in struct str binary data contain 103 | VTYPE_CLSID, //UUID 104 | VTYPE_STR_BLOB = 0xfff, 105 | VTYPE_VECTOR = 0x1000, 106 | VTYPE_ARRAY = 0x2000, 107 | VTYPE_BYREF = 0x4000, //Only with struct _tVariant * 108 | VTYPE_RESERVED = 0x8000, 109 | VTYPE_ILLEGAL = 0xffff, 110 | VTYPE_ILLEGALMASKED = 0xfff, 111 | VTYPE_TYPEMASK = 0xfff 112 | } ; 113 | #if defined (__GNUC__) && !defined (NONAMELESSUNION) 114 | __extension__ /* no named members */ 115 | #endif 116 | struct _tVariant 117 | { 118 | _ANONYMOUS_UNION union 119 | { 120 | int8_t i8Val; 121 | int16_t shortVal; 122 | int32_t lVal; 123 | int intVal; 124 | unsigned int uintVal; 125 | int64_t llVal; 126 | uint8_t ui8Val; 127 | uint16_t ushortVal; 128 | uint32_t ulVal; 129 | uint64_t ullVal; 130 | int32_t errCode; 131 | long hRes; 132 | float fltVal; 133 | double dblVal; 134 | bool bVal; 135 | char chVal; 136 | wchar_t wchVal; 137 | DATE date; 138 | IID IDVal; 139 | struct _tVariant *pvarVal; 140 | struct tm tmVal; 141 | _ANONYMOUS_STRUCT struct 142 | { 143 | void* pInterfaceVal; 144 | IID InterfaceID; 145 | } __VARIANT_NAME_2/*iface*/; 146 | _ANONYMOUS_STRUCT struct 147 | { 148 | char* pstrVal; 149 | uint32_t strLen; //count of bytes 150 | } __VARIANT_NAME_3/*str*/; 151 | _ANONYMOUS_STRUCT struct 152 | { 153 | WCHAR_T* pwstrVal; 154 | uint32_t wstrLen; //count of symbol 155 | } __VARIANT_NAME_4/*wstr*/; 156 | } __VARIANT_NAME_1; 157 | uint32_t cbElements; //Dimension for an one-dimensional array in pvarVal 158 | TYPEVAR vt; 159 | }; 160 | typedef struct _tVariant tVariant; 161 | typedef tVariant tVariantArg; 162 | 163 | 164 | #if defined(NONAMELESSUNION) 165 | #define TV_JOIN(X, Y) ((X)->u.Y) 166 | #else 167 | #define TV_JOIN(X, Y) ((X)->Y) 168 | #endif 169 | 170 | #define TV_VT(X) ((X)->vt) 171 | #define TV_ISBYREF(X) (TV_VT(X)&VT_BYREF) 172 | #define TV_ISARRAY(X) (TV_VT(X)&VT_ARRAY) 173 | #define TV_ISVECTOR(X) (TV_VT(X)&VT_VECTOR) 174 | #define TV_NONE(X) TV_I2(X) 175 | 176 | #define TV_UI1(X) TV_JOIN(X, ui8Val) 177 | #define TV_I2(X) TV_JOIN(X, shortVal) 178 | #define TV_I4(X) TV_JOIN(X, lVal) 179 | #define TV_I8(X) TV_JOIN(X, llVal) 180 | #define TV_R4(X) TV_JOIN(X, fltVal) 181 | #define TV_R8(X) TV_JOIN(X, dblVal) 182 | #define TV_I1(X) TV_JOIN(X, i8Val) 183 | #define TV_UI2(X) TV_JOIN(X, ushortVal) 184 | #define TV_UI4(X) TV_JOIN(X, ulVal) 185 | #define TV_UI8(X) TV_JOIN(X, ullVal) 186 | #define TV_INT(X) TV_JOIN(X, intVal) 187 | #define TV_UINT(X) TV_JOIN(X, uintVal) 188 | 189 | #ifdef _WIN64 190 | #define TV_INT_PTR(X) TV_JOIN(X, llVal) 191 | #define TV_UINT_PTR(X) TV_JOIN(X, ullVal) 192 | #else 193 | #define TV_INT_PTR(X) TV_JOIN(X, lVal) 194 | #define TV_UINT_PTR(X) TV_JOIN(X, ulVal) 195 | #endif 196 | 197 | 198 | #define TV_DATE(X) TV_JOIN(X, date) 199 | #define TV_STR(X) TV_JOIN(X, pstrVal) 200 | #define TV_WSTR(X) TV_JOIN(X, pwstrVal) 201 | #define TV_BOOL(X) TV_JOIN(X, bVal) 202 | #define TV_UNKNOWN(X) TV_JOIN(X, pInterfaceVal) 203 | #define TV_VARIANTREF(X) TV_JOIN(X, pvarVal) 204 | 205 | void tVarInit(tVariant* tvar); 206 | 207 | inline 208 | void tVarInit(tVariant* tvar) 209 | { 210 | assert(tvar != NULL); 211 | memset(tvar, 0, sizeof(tVariant)); 212 | TV_VT(tvar) = VTYPE_EMPTY; 213 | } 214 | //----------------------------------------------------------------------------// 215 | // static setter functions... 216 | 217 | #define DATA_SET_BEGIN(data_) \ 218 | tVarInit(data_); 219 | 220 | #define DATA_SET_END(data_, type_) \ 221 | TV_VT(data_) = type_; 222 | 223 | 224 | #define DATA_SET(data_, type_, member_, value_) \ 225 | DATA_SET_BEGIN(data_) \ 226 | TV_JOIN(data_, member_) = value_; \ 227 | DATA_SET_END(data_, type_) 228 | 229 | #define DATA_SET_WITH_CAST(data_, type_, member_, cast_, value_) \ 230 | DATA_SET_BEGIN(data_) \ 231 | TV_JOIN(data_, member_) = cast_ value_; \ 232 | DATA_SET_END(data_, type_) 233 | 234 | #endif //__CON_TYPES_H__ 235 | -------------------------------------------------------------------------------- /kafka-broker/dockerfile: -------------------------------------------------------------------------------- 1 | FROM apache/kafka:latest 2 | -------------------------------------------------------------------------------- /kafka-ui/dockerfile: -------------------------------------------------------------------------------- 1 | FROM provectuslabs/kafka-ui:latest 2 | -------------------------------------------------------------------------------- /package/INFO.XML: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /package/MANIFEST.XML: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /package/RdKafka1C.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sv-sand/rdkafka-1c/cc05dfab6470d9639c85cf687d815f4712d6ca9b/package/RdKafka1C.zip -------------------------------------------------------------------------------- /src/AddInNative.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "stdafx.h" 8 | #include "ComponentBase.h" 9 | #include "AddInDefBase.h" 10 | #include "IMemoryManager.h" 11 | #include "Loger.h" 12 | #include "ErrorHandler.h" 13 | #include "RdKafka1C.h" 14 | #include "strings.h" 15 | #include "utils.h" 16 | 17 | #if defined( __linux__ ) 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #endif 27 | 28 | /////////////////////////////////////////////////////////////////////////////// 29 | // class CAddInNative 30 | class CAddInNative : public IComponentBase { 31 | 32 | public: 33 | enum Props { 34 | ePropComponentVersion = 0, 35 | ePropRdKafkaVersion, 36 | ePropLocale, 37 | ePropLogFile, 38 | ePropLogLevel, 39 | ePropOperationTimeout, 40 | ePropError, 41 | ePropErrorDescription, 42 | ePropLast // Always last 43 | }; 44 | 45 | enum Methods { 46 | // Logging 47 | eMethStartLogging = 0, 48 | eMethStopLogging, 49 | eMethSetConfigProperty, 50 | 51 | // Producer 52 | eMethInitProducer, 53 | eMethStartProduce, 54 | eMethProduce, 55 | eMethFlush, 56 | eMethStopProducer, 57 | eMethProducerQueueLen, 58 | eMethCountUndeliveredMessages, 59 | eMethMessageStatus, 60 | 61 | // Consumer 62 | eMethInitConsumer, 63 | eMethConsume, 64 | eMethMessageData, 65 | eMethMessageKey, 66 | eMethMessageHeaders, 67 | eMethMessageMetadata, 68 | eMethStopConsumer, 69 | eMethAssignPartition, 70 | eMethCommitOffset, 71 | eMethChangeOffset, 72 | eMethCommittedOffset, 73 | eMethConsumerQueueLen, 74 | 75 | // Subscriptions 76 | eMethSubscribe, 77 | eMethUnsubscribe, 78 | eMethSubscription, 79 | 80 | eMethLast // Always last 81 | }; 82 | 83 | 84 | CAddInNative(void); 85 | virtual ~CAddInNative(); 86 | 87 | // IInitDoneBase 88 | virtual bool ADDIN_API Init(void*) override; 89 | virtual bool ADDIN_API setMemManager(void* mem) override; 90 | virtual long ADDIN_API GetInfo() override; 91 | virtual void ADDIN_API Done() override; 92 | 93 | // ILanguageExtenderBase 94 | virtual bool ADDIN_API RegisterExtensionAs(WCHAR_T**) override; 95 | 96 | virtual long ADDIN_API GetNProps() override; 97 | virtual long ADDIN_API FindProp(const WCHAR_T* wsPropName) override; 98 | virtual const WCHAR_T* ADDIN_API GetPropName(long lPropNum, long lPropAlias) override; 99 | virtual bool ADDIN_API GetPropVal(const long lPropNum, tVariant* pvarPropVal) override; 100 | virtual bool ADDIN_API SetPropVal(const long lPropNum, tVariant* varPropVal) override; 101 | virtual bool ADDIN_API IsPropReadable(const long lPropNum) override; 102 | virtual bool ADDIN_API IsPropWritable(const long lPropNum) override; 103 | 104 | virtual long ADDIN_API GetNMethods() override; 105 | virtual long ADDIN_API FindMethod(const WCHAR_T* wsMethodName) override; 106 | virtual const WCHAR_T* ADDIN_API GetMethodName(const long lMethodNum, const long lMethodAlias) override; 107 | virtual long ADDIN_API GetNParams(const long lMethodNum) override; 108 | virtual bool ADDIN_API GetParamDefValue(const long lMethodNum, const long lParamNum, tVariant *pvarParamDefValue) override; 109 | virtual bool ADDIN_API HasRetVal(const long lMethodNum) override; 110 | virtual bool ADDIN_API CallAsProc(const long lMethodNum, tVariant* paParams, const long lSizeArray) override; 111 | virtual bool ADDIN_API CallAsFunc(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray) override; 112 | 113 | // LocaleBase 114 | virtual void ADDIN_API SetLocale(const WCHAR_T* loc) override; 115 | 116 | // UserLanguageBase 117 | virtual void ADDIN_API SetUserInterfaceLanguageCode(const WCHAR_T* lang) override; 118 | 119 | private: 120 | 121 | const wchar_t* EXTENSION_NAME = L"RdKafka1C"; 122 | const wchar_t* COMPONENT_VERSION = L"1.3.0"; 123 | 124 | std::string currentLocale; 125 | IAddInDefBase* m_iConnect; 126 | IMemoryManager* m_iMemory; 127 | Loger* loger; 128 | ErrorHandler* error; 129 | RdKafka1C* rdk1c; 130 | 131 | bool SetLocale(tVariant* varPropVal); 132 | bool SetLocale(std::string LocaleName); 133 | 134 | // Logging 135 | bool StartLogging(tVariant* paParams, const long lSizeArray); 136 | bool StopLogging(tVariant* paParams, const long lSizeArray); 137 | bool SetLogLevel(tVariant* varPropVal); 138 | std::string GetLogLevel(); 139 | std::string GetLogFile(); 140 | Loger::Levels StringToLogLevel(std::string String); 141 | 142 | // General action 143 | bool SetConfigProperty(tVariant* paParams, const long lSizeArray); 144 | 145 | // Producer 146 | bool InitProducer(tVariant* paParams, const long lSizeArray); 147 | bool StopProducer(tVariant* paParams, const long lSizeArray); 148 | bool StartProduce(tVariant* paParams, const long lSizeArray); 149 | bool Produce(tVariant* paParams, const long lSizeArray); 150 | bool Flush(tVariant* paParams, const long lSizeArray); 151 | bool ProducerQueueLen(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 152 | bool CountUndeliveredMessages(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 153 | bool MessageStatus(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 154 | 155 | // Consumer 156 | bool InitConsumer(tVariant* paParams, const long lSizeArray); 157 | bool StopConsumer(tVariant* paParams, const long lSizeArray); 158 | bool Consume(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 159 | bool MessageData(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 160 | bool MessageKey(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 161 | bool MessageHeaders(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 162 | bool MessageMetadata(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 163 | bool ConsumerQueueLen(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 164 | bool AssignPartition(tVariant* paParams, const long lSizeArray); 165 | bool CommittedOffset(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 166 | bool CommitOffset(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 167 | bool ChangeOffset(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 168 | 169 | // Subscription 170 | bool Subscription(tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray); 171 | bool Subscribe(tVariant* paParams, const long lSizeArray); 172 | bool Unsubscribe(tVariant* paParams, const long lSizeArray); 173 | 174 | // Variant conversion 175 | int ToInt(tVariant* Source); 176 | int ToInt(tVariant* Source, int defaultValue); 177 | int64_t ToLongInt(tVariant* Source); 178 | std::string ToString(tVariant* Source); 179 | std::string ToString(tVariant* Source, std::string defaultValue); 180 | std::string ToBinaryString(tVariant* Source); 181 | 182 | void SetVariant(tVariant* Dest, std::string Source); 183 | void SetVariant(tVariant* Dest, const wchar_t* Source); 184 | void SetVariant(tVariant* Dest, const char* Source); 185 | void SetVariant(tVariant* Dest, int Source); 186 | void SetVariant(tVariant* Dest, int64_t Source); 187 | void SetVariant(tVariant* Dest, bool Source); 188 | void SetVariantBlob(tVariant* Dest, std::string Source); 189 | void ToShortWchar(WCHAR_T** Dest, const wchar_t* Source); 190 | void ToShortWchar(WCHAR_T** Dest, const char* Source); 191 | 192 | // Other 193 | long findName(const wchar_t* names[], const wchar_t* name, const uint32_t size) const; 194 | }; 195 | -------------------------------------------------------------------------------- /src/ConfigBuilder.cpp: -------------------------------------------------------------------------------- 1 | #include "ConfigBuilder.h" 2 | 3 | std::string CoverPaswords(std::string name, std::string value); 4 | 5 | ConfigBuilder::ConfigBuilder(Loger* Loger, ErrorHandler* Error) { 6 | loger = Loger; 7 | error = Error; 8 | 9 | rebalance = new Rebalance(loger); 10 | event = new Event(loger); 11 | deliveryReport = new DeliveryReport(loger); 12 | 13 | loger->Info("Create config"); 14 | conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL); 15 | } 16 | 17 | ConfigBuilder::~ConfigBuilder() { 18 | delete_pointer(conf); 19 | delete_pointer(rebalance); 20 | delete_pointer(event); 21 | delete_pointer(deliveryReport); 22 | } 23 | 24 | bool ConfigBuilder::BuildProducerConfig() { 25 | loger->Info("Build config"); 26 | 27 | loger->Debug("Set common props"); 28 | if (loger->level == Loger::Levels::DEBUG) 29 | if (!SetProperty("debug", "all")) 30 | return false; 31 | 32 | if (!SetProperty("client.id", "rdkafka-1c")) 33 | return false; 34 | 35 | loger->Debug("Set user props"); 36 | for (const auto& [key, value] : properties) 37 | if (!SetProperty(key, value)) 38 | return false; 39 | 40 | loger->Debug("Set callbacks"); 41 | if (!SetEventCb()) 42 | return false; 43 | 44 | if (!SetDeliveryReportCb()) 45 | return false; 46 | 47 | if (loger->level == Loger::Levels::DEBUG) 48 | LogConfigDump(); 49 | 50 | loger->Debug("Clear config properties after build"); 51 | properties.clear(); 52 | 53 | return true; 54 | } 55 | 56 | bool ConfigBuilder::BuildConsumerConfig() { 57 | loger->Info("Build config"); 58 | 59 | loger->Debug("Set common props"); 60 | if (loger->level == Loger::Levels::DEBUG) 61 | if (!SetProperty("debug", "all")) 62 | return false; 63 | 64 | if (!SetProperty("client.id", "rdkafka-1c")) 65 | return false; 66 | 67 | loger->Debug("Set user props"); 68 | for (const auto& [key, value] : properties) 69 | if (!SetProperty(key, value)) 70 | return false; 71 | 72 | loger->Debug("Set callbacks"); 73 | if (!SetEventCb()) 74 | return false; 75 | 76 | if (!SetRebalanceCb()) 77 | return false; 78 | 79 | if (loger->level == Loger::Levels::DEBUG) 80 | LogConfigDump(); 81 | 82 | loger->Debug("Clear config properties after build"); 83 | properties.clear(); 84 | 85 | return true; 86 | } 87 | 88 | RdKafka::Conf* ConfigBuilder::GetConf() { 89 | return conf; 90 | } 91 | 92 | void ConfigBuilder::AddProperty(std::string Name, std::string Value) { 93 | properties[Name] = Value; 94 | } 95 | 96 | DeliveryReport* ConfigBuilder::GetDeliveryReport() { 97 | return deliveryReport; 98 | } 99 | 100 | ///////////////////////////////////////////////////////////////////////////// 101 | // Support methods 102 | 103 | std::string CoverPaswords(std::string name, std::string value) { 104 | if (name == "sasl.password") 105 | return "***"; 106 | return value; 107 | } 108 | 109 | void ConfigBuilder::LogConfigDump() { 110 | std::list* dump = conf->dump(); 111 | std::stringstream stream; 112 | 113 | stream << "Config dump:"; 114 | 115 | for (auto it = dump->begin(); it != dump->end();) { 116 | std::string name = std::string(*it); 117 | it++; 118 | std::string value = std::string(*it); 119 | it++; 120 | 121 | if (name == "sasl.password") 122 | value = "***"; 123 | 124 | stream << std::endl << name << " = " << CoverPaswords(name, value); 125 | } 126 | loger->Debug(stream.str()); 127 | } 128 | 129 | bool ConfigBuilder::SetProperty(std::string Name, std::string Value) { 130 | loger->Debug("Set config property '" + Name + "' in value '" + CoverPaswords(Name, Value) + "'"); 131 | 132 | std::string errorDescription; 133 | RdKafka::Conf::ConfResult result = conf->set(Name, Value, errorDescription); 134 | if (result != RdKafka::Conf::CONF_OK) { 135 | loger->Error("Failed to set config property: " + errorDescription); 136 | return false; 137 | } 138 | 139 | return true; 140 | } 141 | 142 | bool ConfigBuilder::SetEventCb() { 143 | if (!event) 144 | return true; 145 | 146 | loger->Debug("Set config property 'event_cb'"); 147 | 148 | std::string errorDescription; 149 | RdKafka::Conf::ConfResult result = conf->set("event_cb", event, errorDescription); 150 | if (result != RdKafka::Conf::CONF_OK) { 151 | loger->Error("Failed to set config property 'event_cb': " + errorDescription); 152 | return false; 153 | } 154 | 155 | return true; 156 | } 157 | 158 | bool ConfigBuilder::SetDeliveryReportCb() { 159 | if (!deliveryReport) 160 | return true; 161 | 162 | loger->Debug("Set config property 'dr_cb'"); 163 | 164 | std::string errorDescription; 165 | RdKafka::Conf::ConfResult result = conf->set("dr_cb", deliveryReport, errorDescription); 166 | if (result != RdKafka::Conf::CONF_OK) { 167 | loger->Error("Failed to set config property 'dr_cb': " + errorDescription); 168 | return false; 169 | } 170 | 171 | return true; 172 | } 173 | 174 | bool ConfigBuilder::SetRebalanceCb() { 175 | if (!rebalance) 176 | return true; 177 | 178 | loger->Debug("Set config property 'rebalance_cb'"); 179 | 180 | std::string errorDescription; 181 | RdKafka::Conf::ConfResult result = conf->set("rebalance_cb", rebalance, errorDescription); 182 | if (result != RdKafka::Conf::CONF_OK) { 183 | loger->Error("Failed to set config property 'rebalance_cb': " + errorDescription); 184 | return false; 185 | } 186 | 187 | return true; 188 | } 189 | -------------------------------------------------------------------------------- /src/ConfigBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Loger.h" 6 | #include "ErrorHandler.h" 7 | #include "DeliveryReport.h" 8 | #include "Rebalance.h" 9 | #include "Event.h" 10 | #include "utils.h" 11 | 12 | class ConfigBuilder { 13 | 14 | public: 15 | ConfigBuilder(Loger* Loger, ErrorHandler* Error); 16 | ~ConfigBuilder(); 17 | 18 | void AddProperty(std::string Name, std::string Value); 19 | bool BuildProducerConfig(); 20 | bool BuildConsumerConfig(); 21 | RdKafka::Conf* GetConf(); 22 | 23 | DeliveryReport* GetDeliveryReport(); 24 | 25 | private: 26 | Loger* loger; 27 | ErrorHandler* error; 28 | RdKafka::Conf* conf; 29 | Rebalance* rebalance; 30 | Event* event; 31 | DeliveryReport* deliveryReport; 32 | 33 | std::map properties; 34 | 35 | void LogConfigDump(); 36 | bool SetProperty(std::string Name, std::string Value); 37 | bool SetEventCb(); 38 | bool SetDeliveryReportCb(); 39 | bool SetRebalanceCb(); 40 | }; -------------------------------------------------------------------------------- /src/DeliveryReport.cpp: -------------------------------------------------------------------------------- 1 | #include "DeliveryReport.h" 2 | 3 | DeliveryReport::DeliveryReport(Loger* Loger) { 4 | loger = Loger; 5 | } 6 | 7 | void DeliveryReport::dr_cb(RdKafka::Message& Message) { 8 | LogMessageStatus(Message); 9 | 10 | std::string messageId = ExtractMessageId(Message); 11 | SetStatus(messageId, Message.status()); 12 | } 13 | 14 | void DeliveryReport::LogMessageStatus(RdKafka::Message& Message) { 15 | std::stringstream stream; 16 | 17 | stream << "Message delivery report: " 18 | << "broker: " << Message.broker_id() << ", " 19 | << "topic: " << Message.topic_name() << ", " 20 | << "offset: " << Message.offset() << ", " 21 | << "partition: " << Message.partition() << ", "; 22 | 23 | switch (Message.status()) { 24 | case RdKafka::Message::MSG_STATUS_NOT_PERSISTED: 25 | stream << "status: NOT_PERSISTED, Details: " << Message.errstr(); 26 | break; 27 | case RdKafka::Message::MSG_STATUS_POSSIBLY_PERSISTED: 28 | stream << "status: POSSIBLY_PERSISTED, Details: " << Message.errstr(); 29 | break; 30 | case RdKafka::Message::MSG_STATUS_PERSISTED: 31 | stream << "status: PERSISTED"; 32 | break; 33 | default: 34 | stream << "status: UNKNOWN, Details: " << Message.errstr(); 35 | break; 36 | } 37 | 38 | loger->Debug(stream.str()); 39 | } 40 | 41 | std::string DeliveryReport::ExtractMessageId(RdKafka::Message& Message) { 42 | loger->Debug("Extract message status"); 43 | 44 | if (!Message.msg_opaque()) 45 | return ""; 46 | 47 | std::string* opaque = (std::string*)Message.msg_opaque(); 48 | return *opaque; 49 | } 50 | 51 | void DeliveryReport::ClearStatuses() { 52 | loger->Debug("Clear message statuses"); 53 | statuses.clear(); 54 | } 55 | 56 | const std::string* DeliveryReport::AddEmptyStatus(std::string MessageId) { 57 | loger->Debug("Add message status"); 58 | 59 | if (MessageId.empty()) 60 | return nullptr; 61 | 62 | statuses[MessageId] = RdKafka::Message::Status::MSG_STATUS_NOT_PERSISTED; 63 | 64 | return &statuses.find(MessageId)->first; 65 | } 66 | 67 | void DeliveryReport::SetStatus(std::string MessageId, RdKafka::Message::Status Status) { 68 | loger->Debug("Set message status"); 69 | 70 | if (MessageId.empty()) 71 | return; 72 | 73 | statuses[MessageId] = Status; 74 | } 75 | 76 | RdKafka::Message::Status DeliveryReport::GetStatus(std::string MessageId) { 77 | RdKafka::Message::Status status; 78 | 79 | try { 80 | status = statuses.at(MessageId); 81 | } 82 | catch (const std::out_of_range& e) { 83 | return RdKafka::Message::MSG_STATUS_NOT_PERSISTED; 84 | } 85 | 86 | return status; 87 | } 88 | 89 | int DeliveryReport::CountUndelivered() 90 | { 91 | int count = 0; 92 | 93 | for (const auto& [key, value] : statuses) 94 | if (value != RdKafka::Message::MSG_STATUS_PERSISTED) 95 | count++; 96 | 97 | return count; 98 | } -------------------------------------------------------------------------------- /src/DeliveryReport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "Loger.h" 7 | 8 | class DeliveryReport : public RdKafka::DeliveryReportCb { 9 | 10 | public: 11 | DeliveryReport(Loger* Loger); 12 | 13 | void dr_cb(RdKafka::Message& Message); 14 | 15 | void ClearStatuses(); 16 | const std::string* AddEmptyStatus(std::string MessageId); 17 | RdKafka::Message::Status GetStatus(std::string MessageId); 18 | int CountUndelivered(); 19 | 20 | private: 21 | Loger* loger; 22 | std::map statuses; 23 | 24 | void LogMessageStatus(RdKafka::Message& Message); 25 | std::string ExtractMessageId(RdKafka::Message& Message); 26 | void SetStatus(std::string MessageId, RdKafka::Message::Status Status); 27 | }; -------------------------------------------------------------------------------- /src/ErrorHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "ErrorHandler.h" 2 | 3 | ErrorHandler::ErrorHandler(Loger* Loger) { 4 | loger = Loger; 5 | } 6 | 7 | bool ErrorHandler::Error() { 8 | return error; 9 | } 10 | 11 | std::string ErrorHandler::ErrorDescription() { 12 | return errorDescription; 13 | } 14 | 15 | void ErrorHandler::Set(std::string ErrorDescription) { 16 | error = true; 17 | errorDescription = ErrorDescription; 18 | 19 | if (loger) 20 | loger->Error(errorDescription); 21 | } 22 | 23 | void ErrorHandler::Clear() { 24 | error = false; 25 | errorDescription = ""; 26 | } 27 | -------------------------------------------------------------------------------- /src/ErrorHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Loger.h" 5 | 6 | class ErrorHandler { 7 | 8 | public: 9 | ErrorHandler(Loger* Loger); 10 | 11 | bool Error(); 12 | std::string ErrorDescription(); 13 | void Set(std::string ErrorDescription); 14 | void Clear(); 15 | 16 | private: 17 | Loger* loger; 18 | bool error; 19 | std::string errorDescription; 20 | }; -------------------------------------------------------------------------------- /src/Event.cpp: -------------------------------------------------------------------------------- 1 | #include "Event.h" 2 | 3 | Event::Event(Loger* Loger) { 4 | loger = Loger; 5 | } 6 | 7 | void Event::event_cb(RdKafka::Event& event) { 8 | std::stringstream stream; 9 | 10 | switch (event.type()) { 11 | case RdKafka::Event::EVENT_ERROR: 12 | stream << "[KAFKA] "; 13 | 14 | if (event.fatal()) 15 | stream << "FATAL "; 16 | 17 | stream << "ERROR: " << RdKafka::err2str(event.err()) << ": " << event.str(); 18 | loger->Error(stream.str()); 19 | break; 20 | 21 | case RdKafka::Event::EVENT_STATS: 22 | stream << "[KAFKA] STATS: " << event.str(); 23 | loger->Debug(stream.str()); 24 | break; 25 | 26 | case RdKafka::Event::EVENT_LOG: 27 | stream << "[KAFKA] LOG-" << event.severity() << "-" << event.fac() << ": " << event.str(); 28 | loger->Debug(stream.str()); 29 | break; 30 | 31 | default: 32 | stream << "[KAFKA] EVENT " << event.type() << ": " << RdKafka::err2str(event.err()) << ": " << event.str(); 33 | loger->Info(stream.str()); 34 | break; 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/Event.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Loger.h" 6 | 7 | class Event : public RdKafka::EventCb { 8 | 9 | public: 10 | Event(Loger* Loger); 11 | void event_cb(RdKafka::Event& event); 12 | 13 | private: 14 | Loger* loger; 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /src/Loger.cpp: -------------------------------------------------------------------------------- 1 | #include "Loger.h" 2 | 3 | Loger::Loger() { 4 | } 5 | 6 | Loger::~Loger() { 7 | Info("Stop logging"); 8 | } 9 | 10 | bool Loger::Init(std::string FileName) { 11 | std::string ErrorDescription = ""; 12 | return Init(FileName, ErrorDescription); 13 | } 14 | 15 | bool Loger::Init(std::string FileName, std::string &ErrorDescription) { 16 | fileName = FileName; 17 | 18 | if (!StartNewFile(fileName)) { 19 | ErrorDescription = "Failed to open file " + fileName; 20 | return false; 21 | } 22 | 23 | return true; 24 | } 25 | 26 | void Loger::Debug(std::string Message) { 27 | if (level > Levels::DEBUG || level == Levels::NONE || fileName.empty()) 28 | return; 29 | 30 | std::stringstream stream; 31 | stream << Strings::TimeStamp() << " [DEBUG] " << Message; 32 | 33 | WriteFile(fileName, stream.str()); 34 | } 35 | 36 | void Loger::Info(std::string Message) { 37 | if (level > Levels::INFO || level == Levels::NONE || fileName.empty()) 38 | return; 39 | 40 | std::stringstream stream; 41 | stream << Strings::TimeStamp() << " [INFO] " << Message; 42 | 43 | WriteFile(fileName, stream.str()); 44 | } 45 | 46 | void Loger::Warn(std::string Message) 47 | { 48 | if (level > Levels::WARN || level == Levels::NONE || fileName.empty()) 49 | return; 50 | 51 | std::stringstream stream; 52 | stream << Strings::TimeStamp() << " [WARNING] " << Message; 53 | 54 | WriteFile(fileName, stream.str()); 55 | } 56 | 57 | void Loger::Error(std::string Message) { 58 | if (level > Levels::ERRORS || level == Levels::NONE || fileName.empty()) 59 | return; 60 | 61 | std::stringstream stream; 62 | stream << Strings::TimeStamp() << " [ERROR] " << Message; 63 | 64 | WriteFile(fileName, stream.str()); 65 | } 66 | 67 | std::string Loger::GetLogFile() { 68 | return fileName; 69 | } 70 | 71 | ///////////////////////////////////////////////////////////////////////////// 72 | // File operations 73 | 74 | bool Loger::StartNewFile(std::string FileName) { 75 | bool result; 76 | std::ofstream file(FileName, std::ios::out | std::ios::trunc |std::ios::binary); 77 | 78 | result = file.is_open(); 79 | if (result) 80 | file 81 | << "####--####---#--#--####--###--#--#--####----------#--####" << std::endl 82 | << "#--#--#--##--#-#---#--#--#----#-#---#--#---------##--#---" << std::endl 83 | << "####--#--##--##----####--###--##----####---###----#--#---" << std::endl 84 | << "#-#---#--##--#-#---#--#--#----#-#---#--#----------#--#---" << std::endl 85 | << "#-#---####---#--#--#--#--#----#--#--#--#----------#--####" << std::endl 86 | << std::endl; 87 | 88 | file.close(); 89 | 90 | return result; 91 | } 92 | 93 | void Loger::WriteFile(std::string FileName, std::string Message) { 94 | std::ofstream file(FileName, std::ios::app); 95 | 96 | if (file.is_open()) 97 | file << Message << std::endl; 98 | 99 | file.close(); 100 | } 101 | -------------------------------------------------------------------------------- /src/Loger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "strings.h" 8 | 9 | class Loger { 10 | 11 | public: 12 | enum class Levels { 13 | NONE = 0, 14 | DEBUG, 15 | INFO, 16 | WARN, 17 | ERRORS 18 | }; 19 | 20 | Levels level = Levels::NONE; 21 | 22 | Loger(); 23 | ~Loger(); 24 | 25 | bool Init(std::string FileName); 26 | bool Init(std::string FileName, std::string &ErrorDescription); 27 | 28 | void Debug(std::string Message); 29 | void Info(std::string Message); 30 | void Warn(std::string Message); 31 | void Error(std::string Message); 32 | 33 | std::string GetLogFile(); 34 | 35 | private: 36 | std::string fileName; 37 | 38 | bool StartNewFile(std::string FileName); 39 | void WriteFile(std::string FileName, std::string Message); 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /src/RdKafka1C.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef WIN32 4 | #pragma comment(lib, "bcrypt.lib") 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "Loger.h" 12 | #include "ErrorHandler.h" 13 | #include "ConfigBuilder.h" 14 | #include "strings.h" 15 | #include "utils.h" 16 | 17 | class RdKafka1C { 18 | public: 19 | 20 | int OperationTimeout = 1000; // ms 21 | 22 | RdKafka1C(Loger* Loger, ErrorHandler* Error); 23 | ~RdKafka1C(); 24 | 25 | std::string RdKafkaVersion(); 26 | 27 | // Set RdKafka config property https://github.com/confluentinc/librdkafka/blob/master/CONFIGURATION.md 28 | // Invoke this method before InitProducer(), InitConsumer() 29 | void SetConfigProperty(std::string Name, std::string Value); 30 | 31 | // Producer 32 | bool InitProducer(); 33 | bool StopProduser(); 34 | bool StartProduce(); 35 | bool Produce(std::string Topic, std::string Message, std::string Key, std::string Headers, int Partition, std::string MessageId); 36 | bool Flush(); 37 | int ProducerQueueLen(); 38 | int CountUndeliveredMessages(); 39 | std::string MessageStatus(std::string MessageId); 40 | 41 | // Consumer 42 | bool InitConsumer(); 43 | bool StopConsumer(); 44 | bool Consume(); 45 | std::string MessageData(); 46 | std::string MessageKey(); 47 | std::string MessageHeaders(); 48 | std::string MessageMetadata(); 49 | int64_t CommittedOffset(std::string Topic, int Partition); 50 | bool AssignPartition(std::string Topic, int Partition); 51 | bool CommitOffset(); 52 | bool ChangeOffset(std::string Topic, int Partition, int64_t Offset); 53 | int ConsumerQueueLen(); 54 | 55 | // Subscriptions 56 | std::string Subscription(); 57 | bool Subscribe(std::string Topic); 58 | bool Unsubscribe(); 59 | 60 | // Other 61 | std::string MessageStatusToString(RdKafka::Message::Status Status); 62 | 63 | private: 64 | 65 | Loger* loger; 66 | ErrorHandler* error; 67 | 68 | RdKafka::Producer* producer; 69 | RdKafka::KafkaConsumer* consumer; 70 | RdKafka::Message* message; 71 | ConfigBuilder* config; 72 | 73 | bool SetHeaders(RdKafka::Headers* Headers, std::string StringHeaders); 74 | }; 75 | 76 | -------------------------------------------------------------------------------- /src/Rebalance.cpp: -------------------------------------------------------------------------------- 1 | #include "Rebalance.h" 2 | 3 | /* 4 | * Rebalance. 5 | * The process of redistributing partitions among consumer instances in a group. Partition assignment strategy. 6 | * The algorithm used by Kafka to assign partitions to consumers in a group. 7 | */ 8 | 9 | Rebalance::Rebalance(Loger* Loger) { 10 | loger = Loger; 11 | } 12 | 13 | void Rebalance::LogConfig(const std::vector& partitions) { 14 | std::stringstream stream; 15 | stream << "Partition config: "; 16 | 17 | for (unsigned int i = 0; i < partitions.size(); i++) 18 | stream << partitions[i]->topic() << "[" << partitions[i]->partition() << "], "; 19 | 20 | loger->Debug(stream.str()); 21 | } 22 | 23 | void Rebalance::rebalance_cb(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions) { 24 | loger->Debug("Rebalance: " + RdKafka::err2str(err)); 25 | 26 | LogConfig(partitions); 27 | 28 | if (consumer->rebalance_protocol() == "COOPERATIVE") 29 | CooperativeRebalance(consumer, err, partitions); 30 | else 31 | EagerRebalance(consumer, err, partitions); 32 | } 33 | 34 | void Rebalance::CooperativeRebalance(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions) { 35 | RdKafka::Error* result = NULL; 36 | 37 | switch (err) { 38 | case RdKafka::ERR__ASSIGN_PARTITIONS: 39 | // Application may load offets from arbitrary external 40 | // storage here and update partitions 41 | result = consumer->incremental_assign(partitions); 42 | break; 43 | 44 | case RdKafka::ERR__REVOKE_PARTITIONS: 45 | // Application may commit offsets manually here 46 | // if auto.commit.enable=false 47 | result = consumer->incremental_unassign(partitions); 48 | break; 49 | 50 | default: 51 | result = consumer->incremental_unassign(partitions); 52 | } 53 | 54 | if (result) 55 | loger->Error("Incremental assign failed: " + result->str()); 56 | 57 | delete result; 58 | } 59 | 60 | void Rebalance::EagerRebalance(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions) { 61 | RdKafka::ErrorCode result = RdKafka::ERR_NO_ERROR; 62 | 63 | switch (err) { 64 | case RdKafka::ERR__ASSIGN_PARTITIONS: 65 | // Application may load offets from arbitrary external 66 | // storage here and update partitions 67 | result = consumer->assign(partitions); 68 | break; 69 | 70 | case RdKafka::ERR__REVOKE_PARTITIONS: 71 | // Application may commit offsets manually here 72 | // if auto.commit.enable=false 73 | result = consumer->unassign(); 74 | break; 75 | 76 | default: 77 | result = consumer->unassign(); 78 | } 79 | 80 | if (result) 81 | loger->Error("Assign failed: " + RdKafka::err2str(result)); 82 | } 83 | -------------------------------------------------------------------------------- /src/Rebalance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Loger.h" 6 | 7 | class Rebalance : public RdKafka::RebalanceCb { 8 | public: 9 | 10 | Rebalance(Loger* Loger); 11 | void rebalance_cb(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions); 12 | 13 | private: 14 | Loger* loger; 15 | 16 | void LogConfig(const std::vector& partitions); 17 | void CooperativeRebalance(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions); 18 | void EagerRebalance(RdKafka::KafkaConsumer* consumer, RdKafka::ErrorCode err, std::vector& partitions); 19 | }; 20 | -------------------------------------------------------------------------------- /src/strings.cpp: -------------------------------------------------------------------------------- 1 | #include "strings.h" 2 | 3 | uint32_t Strings::GetLength(const WCHAR_T* Source) { 4 | uint32_t length = 0; 5 | WCHAR_T* ptr = (WCHAR_T*)Source; 6 | 7 | while (*ptr++) 8 | ++length; 9 | 10 | return length; 11 | } 12 | 13 | uint32_t Strings::GetLength(const char* Source) { 14 | uint32_t length = 0; 15 | 16 | #ifdef WIN32 17 | length = _mbstrlen(Source); 18 | #else 19 | for (size_t size = 0; size < strlen(Source); length++) 20 | size += mblen(&Source[size], MB_CUR_MAX); 21 | #endif 22 | 23 | return length; 24 | } 25 | 26 | ///////////////////////////////////////////////////////////////////////////// 27 | // String conversion without memory allocation 28 | // You must allcate memory before for Dest before invoke this methods 29 | 30 | uint32_t Strings::ConvertToShortWchar(WCHAR_T** Dest, const wchar_t* Source) { 31 | uint32_t length = wcslen(Source); 32 | size_t size = sizeof(WCHAR_T) * (length + 1); 33 | WCHAR_T* tmpShort = *Dest; 34 | wchar_t* tmpWChar = (wchar_t*)Source; 35 | 36 | memset(*Dest, 0, size); 37 | 38 | for (size_t i = length; i; --i, ++tmpWChar, ++tmpShort) 39 | *tmpShort = (WCHAR_T)*tmpWChar; 40 | 41 | return length; 42 | } 43 | 44 | uint32_t Strings::ConvertToWchar(wchar_t** Dest, const WCHAR_T* Source) { 45 | uint32_t length = GetLength(Source); 46 | size_t size = sizeof(wchar_t) * (length + 1); 47 | wchar_t* tmpWChar = *Dest; 48 | WCHAR_T* tmpShort = (WCHAR_T*)Source; 49 | 50 | memset(*Dest, 0, size); 51 | 52 | for (size_t i = length; i; --i, ++tmpWChar, ++tmpShort) 53 | *tmpWChar = (wchar_t)*tmpShort; 54 | 55 | return length; 56 | } 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // String conversion with memory allocation 60 | // You must delete result array after invoke this methods (delete []) 61 | 62 | wchar_t* Strings::ToWchar(const char* Source) { 63 | // In multibyte string UTF-8 one symbol can occupy 1,2,4 bytes 64 | uint32_t length = GetLength(Source); 65 | wchar_t* dest = new wchar_t[length + 1]; 66 | 67 | size_t size = sizeof(wchar_t) * (length + 1); 68 | std::memset(dest, 0, size); 69 | std::mbstowcs(dest, Source, length); 70 | 71 | return dest; 72 | } 73 | 74 | wchar_t* Strings::ToWchar(const WCHAR_T* Source) { 75 | uint32_t length = GetLength(Source); 76 | wchar_t* dest = new wchar_t[length + 1]; 77 | 78 | ConvertToWchar(&dest, Source); 79 | 80 | return dest; 81 | } 82 | 83 | WCHAR_T* Strings::ToShortWchar(const char* Source) { 84 | // In multibyte string UTF-8 one symbol can occupy 1,2,4 bytes 85 | wchar_t* wcstr = ToWchar(Source); 86 | WCHAR_T* dest = ToShortWchar(wcstr); 87 | 88 | delete[] wcstr; 89 | 90 | return dest; 91 | } 92 | 93 | WCHAR_T* Strings::ToShortWchar(const wchar_t* Source) { 94 | uint32_t length = wcslen(Source); 95 | WCHAR_T* dest = new WCHAR_T[length + 1]; 96 | 97 | ConvertToShortWchar(&dest, Source); 98 | 99 | return dest; 100 | } 101 | 102 | char* Strings::ToChar(const wchar_t* Source) { 103 | uint32_t length = wcslen(Source); 104 | 105 | // In multibyte string UTF-8 one symbol can occupy 1,2,4 bytes 106 | int maxBytesPerSymbol = 4; 107 | size_t size = maxBytesPerSymbol * sizeof(char) * (length + 1); 108 | char* dest = new char[size]; 109 | 110 | std::memset(dest, 0, size); 111 | std::wcstombs(dest, Source, size); 112 | 113 | return dest; 114 | } 115 | 116 | ///////////////////////////////////////////////////////////////////////////// 117 | // Date & Time 118 | 119 | const std::string Strings::TimeStamp() { 120 | std::chrono::time_point now = std::chrono::high_resolution_clock::now(); 121 | tm current{}; 122 | 123 | #ifdef WIN32 124 | time_t time = std::time(NULL); 125 | localtime_s(¤t, &time); 126 | #else 127 | auto time = std::chrono::system_clock::to_time_t(now); 128 | current = *std::gmtime(&time); 129 | #endif 130 | 131 | auto duration = std::chrono::duration_cast (now.time_since_epoch()); 132 | auto nanosecond = duration.count() % 1000000000; 133 | 134 | std::ostringstream stream; 135 | stream << std::put_time(¤t, "%Y-%m-%d %T") << "." << nanosecond; 136 | 137 | return stream.str(); 138 | } 139 | 140 | std::string Strings::ToString(int64_t timestamp) { 141 | int milliseconds = timestamp % 1000; 142 | time_t seconds = (time_t)(timestamp / 1000); 143 | 144 | #ifdef WIN32 145 | tm time = *localtime(&seconds); 146 | #else 147 | tm time = *std::gmtime(&seconds); 148 | #endif 149 | 150 | std::ostringstream stream; 151 | stream << std::put_time(&time, "%Y-%m-%d %T") << "." << milliseconds; 152 | return stream.str(); 153 | } 154 | 155 | ///////////////////////////////////////////////////////////////////////////// 156 | // Other methods 157 | 158 | std::string Strings::NewUuid() { 159 | boost::uuids::uuid uuid = boost::uuids::random_generator()(); 160 | return boost::uuids::to_string(uuid); 161 | } 162 | 163 | std::multimap Strings::SplitString(std::string String, std::string PairSeporator, std::string KeyValueSeporator) { 164 | std::multimap map; 165 | 166 | std::vector pairs; 167 | boost::algorithm::split(pairs, String, boost::is_any_of(PairSeporator)); 168 | 169 | for (auto& pair : pairs) { 170 | std::vector keyValue; 171 | boost::algorithm::split(keyValue, pair, boost::is_any_of(KeyValueSeporator)); 172 | 173 | if (keyValue.size() == 2) { 174 | std::string key = keyValue[0]; 175 | std::string value = keyValue[1]; 176 | boost::algorithm::trim_all(key); 177 | boost::algorithm::trim_all(value); 178 | map.insert(std::pair(key, value)); 179 | } 180 | } 181 | 182 | return map; 183 | } 184 | -------------------------------------------------------------------------------- /src/strings.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "types.h" 16 | 17 | #ifdef __linux__ 18 | #include 19 | #include 20 | #endif //__linux__ 21 | 22 | namespace Strings { 23 | 24 | uint32_t GetLength(const WCHAR_T* Source); 25 | uint32_t GetLength(const char* Source); 26 | 27 | // String conversion without memory allocation 28 | // You must allcate memory before for Dest before invoke this methods 29 | uint32_t ConvertToShortWchar(WCHAR_T** Dest, const wchar_t* Source); 30 | uint32_t ConvertToWchar(wchar_t** Dest, const WCHAR_T* Source); 31 | 32 | // String conversion with memory allocation 33 | // You must delete result array after invoke this methods (delete []) 34 | wchar_t* ToWchar(const char* Source); 35 | wchar_t* ToWchar(const WCHAR_T* Source); 36 | WCHAR_T* ToShortWchar(const char* Source); 37 | WCHAR_T* ToShortWchar(const wchar_t* Source); 38 | char* ToChar(const wchar_t* source); 39 | 40 | // Date & Time 41 | const std::string TimeStamp(); 42 | std::string ToString(int64_t timestamp); 43 | 44 | // Other methods 45 | std::string NewUuid(); 46 | std::multimap SplitString(std::string String, std::string PairSeporator, std::string KeyValueSeporator); 47 | } -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define delete_pointer(ptr) { delete ptr; ptr = nullptr; } 4 | 5 | #define delete_array(ptr) { delete [] ptr; } 6 | -------------------------------------------------------------------------------- /test/RdKafka1CTest.cpp: -------------------------------------------------------------------------------- 1 | #include "RdKafka1CTest.h" 2 | 3 | std::string GetData(); 4 | 5 | ///////////////////////////////////////////////////////////////////////////// 6 | // Tests 7 | 8 | TEST_F(RdKafka1CTest, Constructor) 9 | { 10 | // Here method tests SetUp() & TearDown() 11 | } 12 | 13 | TEST_F(RdKafka1CTest, InitProducer) 14 | { 15 | InitProducer(); 16 | StopProducer(); 17 | } 18 | 19 | TEST_F(RdKafka1CTest, InitProducer_Twice) 20 | { 21 | InitProducer(); 22 | 23 | rdk1c->SetConfigProperty("bootstrap.servers", "some-broker"); 24 | 25 | bool initResult = rdk1c->InitProducer(); 26 | ASSERT_STREQ(error->ErrorDescription().c_str(), "Failed to create producer: producer has been initialized already"); 27 | ASSERT_FALSE(initResult); 28 | 29 | StopProducer(); 30 | } 31 | 32 | TEST_F(RdKafka1CTest, InitConsumer) 33 | { 34 | InitConsumer(); 35 | StopConsumer(); 36 | } 37 | 38 | TEST_F(RdKafka1CTest, InitConsumer_Twice) 39 | { 40 | InitConsumer(); 41 | 42 | rdk1c->SetConfigProperty("metadata.broker.list", "some-broker"); 43 | rdk1c->SetConfigProperty("group.id", "some-consumer-id"); 44 | 45 | bool initResult = rdk1c->InitConsumer(); 46 | ASSERT_STREQ(error->ErrorDescription().c_str(), "Failed to create consumer: consumer has been initialized already"); 47 | ASSERT_FALSE(initResult); 48 | 49 | StopConsumer(); 50 | } 51 | 52 | TEST_F(RdKafka1CTest, ProduceConsume) 53 | { 54 | ConsumeAll(); 55 | Produce(); 56 | Consume(); 57 | } 58 | 59 | TEST_F(RdKafka1CTest, ProduceConsumeWithKey) 60 | { 61 | SetKey("Key (ключ) 1"); 62 | ConsumeAll(); 63 | Produce(); 64 | SetKey(""); 65 | 66 | InitConsumer(); 67 | ConsumeMessage(); 68 | std::string key = GetKeyFromMessage(); 69 | StopConsumer(); 70 | 71 | ASSERT_STREQ(key.c_str(), "Key (ключ) 1"); 72 | } 73 | 74 | TEST_F(RdKafka1CTest, ProduceConsumeWithHeader) 75 | { 76 | SetHeaders("Header 1: значение 1; Header 2: значение 2; "); 77 | ConsumeAll(); 78 | Produce(); 79 | SetHeaders(""); 80 | 81 | InitConsumer(); 82 | ConsumeMessage(); 83 | std::string headers = GetHeadersFromMessage(); 84 | StopConsumer(); 85 | 86 | ASSERT_STREQ(headers.c_str(), "Header 1:значение 1;Header 2:значение 2"); 87 | } 88 | 89 | TEST_F(RdKafka1CTest, ConsumeFromEmptyTopic) 90 | { 91 | ConsumeAll(); 92 | InitConsumer(); 93 | 94 | bool consumeResult = rdk1c->Consume(); 95 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 96 | ASSERT_FALSE(consumeResult); 97 | 98 | std::string data = rdk1c->MessageData(); 99 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 100 | ASSERT_STREQ(data.substr(0, 17).c_str(), "Fetch from broker"); 101 | 102 | std::string metadata = rdk1c->MessageMetadata(); 103 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 104 | 105 | StopConsumer(); 106 | } 107 | 108 | TEST_F(RdKafka1CTest, StartLogging) 109 | { 110 | StartLogging(); 111 | } 112 | 113 | TEST_F(RdKafka1CTest, StartStopLogging) 114 | { 115 | StartLogging(); 116 | StopLogging(); 117 | } 118 | 119 | TEST_F(RdKafka1CTest, StartStopLoggingInWork) 120 | { 121 | StartLogging(); 122 | ConsumeAll(); 123 | StopLogging(); 124 | } 125 | 126 | TEST_F(RdKafka1CTest, SetProperty) 127 | { 128 | SetProperty("sasl.username", "test-user"); 129 | 130 | StartLogging(); 131 | InitProducer(); 132 | StopProducer(); 133 | } 134 | 135 | ///////////////////////////////////////////////////////////////////////////// 136 | // Test class members 137 | 138 | void RdKafka1CTest::SetUp() 139 | { 140 | 141 | #ifdef WIN32 142 | std::setlocale(LC_ALL, "ru-RU"); 143 | #else 144 | std::setlocale(LC_ALL, "ru_RU"); 145 | #endif 146 | 147 | loger = new Loger(); 148 | error = new ErrorHandler(loger); 149 | rdk1c = new RdKafka1C(loger, error); 150 | rdk1c->OperationTimeout = 10000; 151 | } 152 | 153 | void RdKafka1CTest::TearDown() 154 | { 155 | delete_pointer(rdk1c); 156 | delete_pointer(error); 157 | delete_pointer(loger); 158 | } 159 | 160 | void RdKafka1CTest::InitProducer() 161 | { 162 | rdk1c->SetConfigProperty("bootstrap.servers", BROKERS); 163 | bool initResult = rdk1c->InitProducer(); 164 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 165 | ASSERT_TRUE(initResult); 166 | } 167 | 168 | void RdKafka1CTest::Produce() 169 | { 170 | InitProducer(); 171 | GenerateNewData(); 172 | ProduceMessage(); 173 | StopProducer(); 174 | } 175 | 176 | void RdKafka1CTest::ProduceMessage() 177 | { 178 | bool sendResult = rdk1c->Produce(TOPIC, DATA, KEY, HEADERS, 0, ""); 179 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 180 | ASSERT_TRUE(sendResult); 181 | 182 | bool flushResult = rdk1c->Flush(); 183 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 184 | ASSERT_TRUE(flushResult); 185 | } 186 | 187 | void RdKafka1CTest::StopProducer() 188 | { 189 | bool stopResult = rdk1c->StopProduser(); 190 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 191 | ASSERT_TRUE(stopResult); 192 | } 193 | 194 | void RdKafka1CTest::InitConsumer() 195 | { 196 | SetProperty("auto.offset.reset", "smallest"); 197 | 198 | rdk1c->SetConfigProperty("metadata.broker.list", BROKERS); 199 | rdk1c->SetConfigProperty("group.id", CONSUMER_GROUP_ID); 200 | 201 | bool initResult = rdk1c->InitConsumer(); 202 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 203 | ASSERT_TRUE(initResult); 204 | 205 | bool subscribeResult = rdk1c->Subscribe(TOPIC); 206 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 207 | ASSERT_TRUE(subscribeResult); 208 | } 209 | 210 | void RdKafka1CTest::Consume() 211 | { 212 | InitConsumer(); 213 | ConsumeMessage(); 214 | StopConsumer(); 215 | } 216 | 217 | void RdKafka1CTest::ConsumeMessage() 218 | { 219 | bool consumeResult = rdk1c->Consume(); 220 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 221 | ASSERT_TRUE(consumeResult); 222 | 223 | std::string data = rdk1c->MessageData(); 224 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 225 | ASSERT_STREQ(DATA.c_str(), data.c_str()); 226 | } 227 | 228 | void RdKafka1CTest::ConsumeAll() 229 | { 230 | InitConsumer(); 231 | 232 | while (rdk1c->Consume()) 233 | { 234 | // Read all messages from topic 235 | } 236 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 237 | 238 | StopConsumer(); 239 | } 240 | 241 | void RdKafka1CTest::StopConsumer() 242 | { 243 | bool stopResult = rdk1c->StopConsumer(); 244 | ASSERT_STREQ(error->ErrorDescription().c_str(), ""); 245 | ASSERT_TRUE(stopResult); 246 | } 247 | 248 | void RdKafka1CTest::StartLogging() 249 | { 250 | loger->level = Loger::Levels::DEBUG; 251 | std::string errorDescription; 252 | bool result = loger->Init(LOG_FILE, errorDescription); 253 | 254 | ASSERT_STREQ(errorDescription.c_str(), ""); 255 | ASSERT_TRUE(result); 256 | } 257 | 258 | void RdKafka1CTest::StopLogging() 259 | { 260 | loger->level = Loger::Levels::NONE; 261 | 262 | std::string logfile = loger->GetLogFile(); 263 | ASSERT_STRNE(logfile.c_str(), ""); 264 | ASSERT_TRUE(std::filesystem::exists(logfile)); 265 | } 266 | 267 | std::string RdKafka1CTest::GetKeyFromMessage() 268 | { 269 | std::string metadata = rdk1c->MessageMetadata(); 270 | std::stringstream stream(metadata); 271 | boost::property_tree::ptree tree; 272 | std::string key; 273 | 274 | try 275 | { 276 | boost::property_tree::read_json(stream, tree); 277 | key = tree.get("key", ""); 278 | } 279 | catch (boost::property_tree::json_parser_error e) 280 | { 281 | throw "Failed to parse JSON: " + e.message(); 282 | } 283 | 284 | return key; 285 | } 286 | 287 | std::string RdKafka1CTest::GetHeadersFromMessage() 288 | { 289 | std::string metadata = rdk1c->MessageMetadata(); 290 | std::stringstream stream(metadata); 291 | boost::property_tree::ptree tree; 292 | 293 | try 294 | { 295 | boost::property_tree::read_json(stream, tree); 296 | 297 | stream.str(""); 298 | for (auto & keyValue : tree.get_child("headers")) 299 | { 300 | stream << keyValue.first << ":" 301 | << keyValue.second.get("") + ";"; 302 | } 303 | } 304 | catch (boost::property_tree::json_parser_error e) 305 | { 306 | throw "Failed to parse JSON: " + e.message(); 307 | } 308 | 309 | std::string result = stream.str(); 310 | 311 | return result.substr(0, result.length() - 1); 312 | } 313 | 314 | ///////////////////////////////////////////////////////////////////////////// 315 | // Support methods 316 | 317 | int RdKafka1CTest::NewRand() 318 | { 319 | srand(time(0)); 320 | return rand(); 321 | } 322 | 323 | void RdKafka1CTest::GenerateNewData() 324 | { 325 | std::stringstream stream; 326 | stream << "test message (тестовое сообщение) " << NewRand(); 327 | DATA = stream.str(); 328 | } 329 | 330 | void RdKafka1CTest::SetKey(std::string key) 331 | { 332 | KEY = key; 333 | } 334 | 335 | void RdKafka1CTest::SetHeaders(std::string headers) 336 | { 337 | HEADERS = headers; 338 | } 339 | 340 | void RdKafka1CTest::SetProperty(std::string name, std::string value) 341 | { 342 | rdk1c->SetConfigProperty(name, value); 343 | } 344 | 345 | 346 | 347 | 348 | -------------------------------------------------------------------------------- /test/RdKafka1CTest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "RdKafka1C.h" 11 | #include "utils.h" 12 | 13 | class RdKafka1CTest : public testing::Test 14 | { 15 | public: 16 | 17 | void SetUp(); 18 | void TearDown(); 19 | 20 | protected: 21 | 22 | Loger* loger; 23 | ErrorHandler* error; 24 | RdKafka1C* rdk1c; 25 | 26 | void CreateRdKafka1C(); 27 | void DeleteRdKafka1C(); 28 | 29 | void InitProducer(); 30 | void Produce(); 31 | void ProduceMessage(); 32 | void StopProducer(); 33 | 34 | void InitConsumer(); 35 | void Consume(); 36 | void ConsumeAll(); 37 | void ConsumeMessage(); 38 | void StopConsumer(); 39 | 40 | void GenerateNewData(); 41 | void StartLogging(); 42 | void StopLogging(); 43 | std::string GetKeyFromMessage(); 44 | std::string GetHeadersFromMessage(); 45 | void SetKey(std::string key); 46 | void SetHeaders(std::string headers); 47 | void SetProperty(std::string name, std::string value); 48 | 49 | private: 50 | 51 | const std::string BROKERS = "localhost"; 52 | const std::string TOPIC = "test"; 53 | const std::string CONSUMER_GROUP_ID = "testgroup"; 54 | const std::string LOG_FILE = "testing.log"; 55 | 56 | std::string DATA; 57 | std::string KEY; 58 | std::string HEADERS; 59 | 60 | int NewRand(); 61 | }; 62 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char *argv[]) { 5 | setlocale(LC_ALL, "ru_RU"); 6 | 7 | testing::InitGoogleTest(&argc, argv); 8 | testing::InitGoogleMock(&argc, argv); 9 | return RUN_ALL_TESTS(); 10 | } -------------------------------------------------------------------------------- /vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-registry": { 3 | "kind": "git", 4 | "baseline": "f45c0ede6a6d97b9ed5f023a4650a50a2beb8863", 5 | "repository": "https://github.com/microsoft/vcpkg" 6 | }, 7 | "registries": [ 8 | { 9 | "kind": "artifact", 10 | "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", 11 | "name": "microsoft" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /vcpkg-install.bat: -------------------------------------------------------------------------------- 1 | @REM This script installs the required dependencies 2 | @REM Before executing, install and add vcpkg to system PATH 3 | 4 | vcpkg install --triplet x64-windows-static-md 5 | 6 | pause -------------------------------------------------------------------------------- /vcpkg-install.sh: -------------------------------------------------------------------------------- 1 | # This script installs the required dependencies 2 | # Before executing, install and add vcpkg to system PATH 3 | 4 | vcpkg install --triplet x64-linux 5 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rdkafka-1c", 3 | "dependencies": [ 4 | "boost-property-tree", 5 | "boost-json", 6 | "boost-uuid", 7 | "boost-filesystem", 8 | "boost-iostreams", 9 | "boost-program-options", 10 | "openssl", 11 | { 12 | "name": "librdkafka", 13 | "features": [ 14 | "ssl" 15 | ] 16 | }, 17 | "lz4", 18 | "gtest" 19 | ], 20 | "overrides": [ 21 | { 22 | "name": "librdkafka", 23 | "version": "2.10.0#0" 24 | } 25 | ] 26 | } 27 | --------------------------------------------------------------------------------