├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── api ├── __init__.py ├── chat_event.py ├── chat_init.py ├── chat_request.py ├── create_chat.py └── create_inf.py ├── client-lib-py ├── .gitignore ├── MANIFEST.in ├── README.md ├── client-lib-cpp │ ├── .gitignore │ ├── CMakeLists.txt │ ├── ClientLib │ │ ├── Allocator.cpp │ │ ├── Allocator.h │ │ ├── Answer.c │ │ ├── Answer.h │ │ ├── CMakeLists.txt │ │ ├── CSData.hpp │ │ ├── ClientLib.c │ │ ├── ClientLib.h │ │ ├── ClientLib.hpp │ │ ├── Errors.h │ │ ├── InfData.c │ │ ├── InfData.h │ │ ├── ItemTypes.hpp │ │ ├── Protocol.hpp │ │ ├── SessionData.c │ │ ├── SessionData.h │ │ ├── csDataPack.cpp │ │ └── csDataPack.h │ ├── apcs │ │ ├── CMakeLists.txt │ │ ├── ap-server.c │ │ ├── csdata.c │ │ ├── csdata.h │ │ ├── libclient.c │ │ ├── readwrite.c │ │ └── readwrite.h │ ├── aptl │ │ └── avector.h │ └── nMemoryAllocator │ │ ├── CMakeLists.txt │ │ ├── nMemoryAllocator.cpp │ │ ├── nMemoryAllocator.h │ │ └── nMemoryAllocator.hpp ├── dp_client │ ├── __init__.py │ ├── answer.py │ ├── client.py │ ├── conftest.py │ ├── exceptions.py │ ├── inf.py │ ├── others.py │ ├── session.py │ └── test.py ├── pyClientLib.c ├── rebuild.sh ├── requirements.txt └── setup.py ├── command.py ├── config.py ├── external_modules └── __init__.py ├── main.py ├── requirements.txt ├── routes.py ├── run_server.sh └── tests ├── __init__.py ├── test_init.py └── test_request.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | .idea/ 38 | .env 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | external_modules/ 136 | kernel/ 137 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7 as build 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | ENV DEBIAN_FRONTEND noninteractive 5 | RUN set -eux; \ 6 | apt-get update && apt-get install -y \ 7 | cmake \ 8 | g++ \ 9 | pybind11-dev \ 10 | python3-dev \ 11 | netcat \ 12 | --no-install-recommends && \ 13 | apt-get remove -y --purge software-properties-common && \ 14 | apt-get -y autoremove && \ 15 | apt-get clean && \ 16 | rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 17 | 18 | WORKDIR /code 19 | COPY client-lib-py /code/ 20 | RUN set -eux; ./rebuild.sh 21 | RUN set -eux; python3 setup.py install 22 | 23 | FROM python:3.7 24 | 25 | ENV PYTHONUNBUFFERED 1 26 | ENV DEBIAN_FRONTEND noninteractive 27 | 28 | WORKDIR /code 29 | 30 | COPY requirements.txt /code/ 31 | COPY --from=build /code/ /code/client-lib-py/ 32 | 33 | RUN set -eux; python -m pip install --upgrade pip 34 | RUN pip install -r requirements.txt 35 | RUN set -eux; cd client-lib-py; python3 setup.py install 36 | COPY api /code/api 37 | COPY external_modules /code/external_modules 38 | COPY kernel /code/kernel 39 | COPY tests /code/tests 40 | COPY *.py /code/ 41 | COPY run_server.sh /code/run_server.sh 42 | RUN ["chmod", "+x", "/code/run_server.sh"] 43 | -------------------------------------------------------------------------------- /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 [2020] [Virtual Assistant, LLC] 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 | # sovaai 2 | # Описание. 3 | 4 | Сервис реализованный на Aiohttp\Python предоставляющий возможность работы чатов и позволяющий взаимодействовать 5 | с лингвистическим ядром. Имеет возможность масштабирования функционала за счет подключения новых файлов в проект, 6 | процесс подключения подробнее описан ниже. 7 | 8 | # Техническое описание. 9 | Сервис реализован по принципу модульности. Каждый из модулей несет в себе логическую нагрузку которая может 10 | масштабирована за исключением Dialog модуля который остается не изменным. В случае их подключения сервис 11 | последовательно обработает сообщение через все подключенные внешние модули. 12 | В сервисе реализованы unit тесты, которые тестируют базовый функционал сервиса. 13 | Сервис докерезирован. 14 | 15 | #### Pipeline обработки сообщения. 16 | Последовательный процесс обработки для каждого входящего сообщения происходит в модуле router и происходит следующим 17 | образом: 18 | 1. Context 19 | 2. Preprocessor 20 | 3. Dialog 21 | 4. Postprocess 22 | 5. Journal 23 | 6. Context (обновление информации в бд) 24 | -------------------------------------------------------------------------------- /api/__init__.py: -------------------------------------------------------------------------------- 1 | from .chat_event import ChatEvent 2 | from .chat_init import ChatInit 3 | from .chat_request import ChatRequest 4 | #TODO Вспомогательные методы. Удалить после разработки сервиса 5 | from .create_inf import CreateInfHelper 6 | from .create_chat import CreateChatHelper 7 | -------------------------------------------------------------------------------- /api/chat_event.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from kernel.router import MessageHandler 3 | import datetime 4 | 5 | 6 | class ChatEvent(web.View): 7 | 8 | async def post(self) -> web.Response: 9 | data = await self.request.json() 10 | message = await self.upgrade_info(data) 11 | m_handler = MessageHandler(message) 12 | message = await m_handler.process() 13 | if message.get("error"): 14 | return web.json_response(data=message['error'], status=m_handler.status_code) 15 | message = await self.clean_response(message) 16 | return web.json_response(data=message, status=m_handler.status_code) 17 | 18 | async def upgrade_info(self, message): 19 | message['type'] = 'event' 20 | message['technical_info'] = { 21 | "req_ts": datetime.datetime.now(), 22 | } 23 | return message 24 | 25 | async def clean_response(self, message): 26 | message.pop('type') 27 | message.pop('db_context') 28 | message.pop('technical_info') 29 | message.pop('euid') 30 | return { 31 | "result": { 32 | "text": { 33 | "value": message['response']['text'], 34 | }, 35 | "cuid": message['cuid'], 36 | "context": message['context'], 37 | "id": "" 38 | }, 39 | "id": "0" 40 | } 41 | -------------------------------------------------------------------------------- /api/chat_init.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from kernel.router import MessageHandler 3 | import logging 4 | 5 | 6 | class ChatInit(web.View): 7 | """ 8 | Инициализация чата 9 | """ 10 | async def post(self) -> web.Response: 11 | data = await self.request.json() 12 | message =await self.upgrade_info(data) 13 | m_handler = MessageHandler(message) 14 | message = await m_handler.process() 15 | if message.get("error"): 16 | return web.json_response(data=message['error'], status=m_handler.status_code) 17 | 18 | message = await self.generate_clean_resoponse(message) 19 | logging.info(f"Response {message}") 20 | return web.json_response(data=message, status=m_handler.status_code) 21 | 22 | async def upgrade_info(self, message): 23 | message['type'] = 'init' 24 | message['technical_info'] = {} 25 | return message 26 | 27 | async def generate_clean_resoponse(self, message): 28 | logging.debug(f"generate_clean_resoponse {message}") 29 | message.pop('uuid') 30 | message.pop('context') 31 | message.pop('type') 32 | message['inf'] = {"name": "text"} 33 | message['text'] = {"delay": 0} 34 | message['events'] = {} 35 | message['referer'] = None 36 | message['token'] = '' 37 | message['root'] = '' 38 | message.pop('technical_info') 39 | return {'result': message, 'id': 0} 40 | -------------------------------------------------------------------------------- /api/chat_request.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from kernel.router import MessageHandler 3 | import datetime 4 | 5 | 6 | class ChatRequest(web.View): 7 | 8 | async def post(self) -> web.Response: 9 | data = await self.request.json() 10 | message = await self.upgrade_info(data) 11 | m_handler = MessageHandler(message) 12 | message = await m_handler.process() 13 | if message.get("error"): 14 | return web.json_response(data=message['error'], status=m_handler.status_code) 15 | message = await self.clean_response(message) 16 | return web.json_response(data=message, status=m_handler.status_code) 17 | 18 | async def upgrade_info(self, message): 19 | message['type'] = 'request' 20 | message['technical_info'] = { 21 | "req_ts": datetime.datetime.now(), 22 | } 23 | return message 24 | 25 | async def clean_response(self, message): 26 | """ 27 | Подготовка ответа. Удаленние технической информации из сообщения. 28 | :param message: 29 | :return: 30 | """ 31 | return { 32 | "result": { 33 | "text": { 34 | "value": message['response']['text'], 35 | }, 36 | "cuid": message['cuid'], 37 | "context": message['context'], 38 | "id": "" 39 | }, 40 | "id": "0" 41 | } 42 | -------------------------------------------------------------------------------- /api/create_chat.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from external_modules.context.models import Chat, Infs 3 | import logging 4 | 5 | 6 | class CreateChatHelper(web.View): 7 | 8 | async def post(self): 9 | inf = Infs(inf_profile='test', uuid='e888d15d-9c2e-4d00-9b9c-b9afb64c4751') 10 | await inf.save() 11 | chat = Chat(inf=inf) 12 | await chat.save() 13 | 14 | logging.debug(f"{dir(chat)}") 15 | logging.debug(f"{chat.__dict__}") 16 | 17 | data = { 18 | "inf": inf.uuid_str, 19 | "cuid": chat.cuid_str 20 | } 21 | return web.json_response(data=data, status=200) -------------------------------------------------------------------------------- /api/create_inf.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | from external_modules.context.models import Infs 3 | 4 | 5 | class CreateInfHelper(web.View): 6 | 7 | async def post(self): 8 | data = await self.request.json() 9 | try: 10 | inf = await Infs().create(uuid=data['buid'], inf_profile=data['profile']) 11 | inf.uuid = inf.uuid_str 12 | return web.json_response(data=inf.__dict__, status=200) 13 | except Exception as err: 14 | return web.json_response(data=err.__dict__, status=200) 15 | -------------------------------------------------------------------------------- /client-lib-py/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .pytest_cache/ 3 | venv/ 4 | build/ 5 | *.swp 6 | *.so 7 | -------------------------------------------------------------------------------- /client-lib-py/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.so -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | /CMakeLists.txt.user -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( ClientLib ) 2 | cmake_minimum_required( VERSION 2.6 ) 3 | 4 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 5 | 6 | add_subdirectory( nMemoryAllocator ) 7 | add_subdirectory( apcs ) 8 | add_subdirectory( ClientLib ) 9 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "csDataPack.h" 3 | 4 | /** Аллокатор памяти для обмена данными с сервером. */ 5 | nMemoryAllocator ClientLibAllocator; 6 | 7 | extern "C" csdata_data_t * AllocateCSData( unsigned int aAttrNumber ) 8 | { 9 | // Выделение памяти под структуру. 10 | nAllocateNewObject( ClientLibAllocator, csdata_data_t, CSData ); 11 | if( !CSData ) 12 | return NULL; 13 | 14 | // Выделение памяти под элементы структуры. 15 | if( aAttrNumber > 0 ) 16 | { 17 | CSData->attr_list = nAllocateObjects( ClientLibAllocator, csdata_attr_t, aAttrNumber ); 18 | if( !( CSData->attr_list ) ) 19 | return NULL; 20 | } 21 | else 22 | CSData->attr_list = NULL; 23 | 24 | CSData->attr_count = aAttrNumber; 25 | 26 | return CSData; 27 | } 28 | 29 | extern "C" void ClientLibAllocatorReset() 30 | { 31 | ClientLibAllocator.Reset(); 32 | } 33 | 34 | extern "C" unsigned int GetAllocatedMemorySize() 35 | { 36 | return ClientLibAllocator.GetAllocatedMemorySize(); 37 | } 38 | 39 | extern "C" csdata_data_t * ClientLibPackData( csdata_data_t * aSource, int aDataPackFlags ) 40 | { 41 | return csDataPack( aSource, ClientLibAllocator, aDataPackFlags ); 42 | } 43 | 44 | extern "C" csdata_data_t * ClientLibUnPackData( csdata_data_t * aSource ) 45 | { 46 | return csDataUnPack( aSource, ClientLibAllocator, false ); 47 | } 48 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Allocator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Статический аллокатор для выделения памяти при передаче данных между клиентской библиотекой и сервером InfServer. 3 | */ 4 | 5 | #ifndef __Allocator_h__ 6 | #define __Allocator_h__ 7 | 8 | #include "csDataPack.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" 12 | { 13 | #endif 14 | 15 | /** 16 | * Выделение памяти под структуру обмена данных с помощью аллокатора памяти. 17 | * @param aAttrNumber - количество элементов в структуре. 18 | */ 19 | csdata_data_t * AllocateCSData( unsigned int aAttrNumber ); 20 | 21 | /** Сброс выделенной аллокатором памяти. */ 22 | void ClientLibAllocatorReset(); 23 | 24 | /** Получение размера выделенной аллокатором памяти. */ 25 | unsigned int GetAllocatedMemorySize(); 26 | 27 | /** 28 | * Упаковка данных для передачи серверу. 29 | * @param aSource - данные для упаковки. 30 | * @param aDataPackFlags - флаги упаковки. 31 | */ 32 | csdata_data_t * ClientLibPackData( csdata_data_t * aSource, int aDataPackFlags ); 33 | 34 | /** 35 | * Распаковка данных полученных от сервера. 36 | * @param aSource - данные полученные от сервера. 37 | */ 38 | csdata_data_t * ClientLibUnPackData( csdata_data_t * aSource ); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif /** __Allocator_h__ */ 45 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Answer.c: -------------------------------------------------------------------------------- 1 | #include "Answer.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "ItemTypes.hpp" 9 | 10 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 11 | * 12 | * Ответ сервера на запрос REQUEST и функции для работы с ним. 13 | * 14 | ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ 15 | 16 | void cl_answer_free( Answer * aAnswer ) 17 | { 18 | // Проверка аргументов. 19 | if( !aAnswer ) 20 | return; 21 | 22 | // Освобождение памяти, занимаемой аргументами элементов ответа. 23 | if( aAnswer->vItems ) 24 | { 25 | unsigned int i; 26 | for( i = 0; i < aAnswer->vItemsNumber; i++ ) 27 | { 28 | switch( aAnswer->vItems[i].vType ) 29 | { 30 | case AnswerItemTypeTextString: 31 | if( aAnswer->vItems[i].vValue.vString.vText ) 32 | free( aAnswer->vItems[i].vValue.vString.vText ); 33 | break; 34 | 35 | case AnswerItemTypeTagInf: 36 | if( aAnswer->vItems[i].vValue.vInf.vValue ) 37 | free( aAnswer->vItems[i].vValue.vInf.vValue ); 38 | if( aAnswer->vItems[i].vValue.vInf.vRequest ) 39 | free( aAnswer->vItems[i].vValue.vInf.vRequest ); 40 | break; 41 | 42 | case AnswerItemTypeTagBr: 43 | case AnswerItemTypeStartOList: 44 | case AnswerItemTypeStartUList: 45 | case AnswerItemTypeListItem: 46 | case AnswerItemTypeEndList: 47 | break; 48 | 49 | case AnswerItemTypeTagHref: 50 | if( aAnswer->vItems[i].vValue.vHref.vURL ) 51 | free( aAnswer->vItems[i].vValue.vHref.vURL ); 52 | if( aAnswer->vItems[i].vValue.vHref.vLink ) 53 | free( aAnswer->vItems[i].vValue.vHref.vLink ); 54 | if( aAnswer->vItems[i].vValue.vHref.vTarget ) 55 | free( aAnswer->vItems[i].vValue.vHref.vTarget ); 56 | break; 57 | 58 | case AnswerItemTypeInstruct: 59 | if( aAnswer->vItems[i].vValue.vInstruct.vVarName ) 60 | free( aAnswer->vItems[i].vValue.vInstruct.vVarName ); 61 | if( aAnswer->vItems[i].vValue.vInstruct.vValue ) 62 | free( aAnswer->vItems[i].vValue.vInstruct.vValue ); 63 | break; 64 | 65 | case AnswerItemTypeTagOpenWindow: 66 | if( aAnswer->vItems[i].vValue.vOpenWindow.vURL ) 67 | free( aAnswer->vItems[i].vValue.vOpenWindow.vURL ); 68 | break; 69 | 70 | case AnswerItemTypeTagRSS: 71 | if( aAnswer->vItems[i].vValue.vRSS.vURL ) 72 | free( aAnswer->vItems[i].vValue.vRSS.vURL ); 73 | if( aAnswer->vItems[i].vValue.vRSS.vAlt ) 74 | free( aAnswer->vItems[i].vValue.vRSS.vAlt ); 75 | break; 76 | } 77 | } 78 | } 79 | 80 | // Освобождение памяти, занимаемой массивом элементов ответа. 81 | if( aAnswer->vItems ) 82 | free( aAnswer->vItems ); 83 | 84 | // Освобождение памяти, занимаемой ответом. 85 | free( aAnswer ); 86 | } 87 | 88 | unsigned int cl_answer_get_size( const Answer * aAnswer ) 89 | { 90 | // Проверка аргументов. 91 | if( !aAnswer ) 92 | return 0; 93 | else 94 | return aAnswer->vItemsNumber; 95 | } 96 | 97 | ClientLibReturnCode cl_answer_get_type( const Answer * aAnswer, unsigned int aItemInd, AnswerItemType * aType ) 98 | { 99 | // Проверка аргументов. 100 | if( !aAnswer || !aType ) 101 | return clrcErrorInvArgs; 102 | 103 | // Проверка корректности запроса. 104 | if( aAnswer->vItemsNumber <= aItemInd ) 105 | return clrcErrorInvArgs; 106 | 107 | // Подготовка результата. 108 | *aType = aAnswer->vItems[aItemInd].vType; 109 | 110 | return clrcSuccess; 111 | } 112 | 113 | ClientLibReturnCode cl_answer_get_text( const Answer * aAnswer, unsigned int aItemInd, const char ** aTextString, unsigned int * aTextStringLength ) 114 | { 115 | // Проверка аргументов. 116 | if( !aAnswer || !aTextString || !aTextStringLength ) 117 | return clrcErrorInvArgs; 118 | 119 | // Проверка количества элементов. 120 | if( aItemInd >= aAnswer->vItemsNumber ) 121 | return clrcErrorInvArgs; 122 | 123 | // Проверка типа элемента. 124 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeTextString ) 125 | return clrcErrorInvArgs; 126 | 127 | // Получение данных. 128 | *aTextString = aAnswer->vItems[aItemInd].vValue.vString.vText; 129 | *aTextStringLength = aAnswer->vItems[aItemInd].vValue.vString.vTextLength; 130 | 131 | return clrcSuccess; 132 | } 133 | 134 | ClientLibReturnCode cl_answer_get_tag_inf( const Answer * aAnswer, unsigned int aItemInd, const char ** aValue, unsigned int * aValueLength, const char ** aRequest, unsigned int * aRequestLength ) 135 | { 136 | // Проверка аргументов. 137 | if( !aAnswer || !aValue || !aValueLength || !aRequest || !aRequestLength ) 138 | return clrcErrorInvArgs; 139 | 140 | // Проверка количества элементов. 141 | if( aItemInd >= aAnswer->vItemsNumber ) 142 | return clrcErrorInvArgs; 143 | 144 | // Проверка типа элемента. 145 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeTagInf ) 146 | return clrcErrorInvArgs; 147 | 148 | // Получение данных. 149 | *aValue = aAnswer->vItems[aItemInd].vValue.vInf.vValue; 150 | *aValueLength = aAnswer->vItems[aItemInd].vValue.vInf.vValueLength; 151 | *aRequest = aAnswer->vItems[aItemInd].vValue.vInf.vRequest; 152 | *aRequestLength = aAnswer->vItems[aItemInd].vValue.vInf.vRequestLength; 153 | 154 | return clrcSuccess; 155 | } 156 | 157 | ClientLibReturnCode cl_answer_get_tag_href( const Answer * aAnswer, unsigned int aItemInd, const char ** aURL, unsigned int * aURLLength, 158 | const char ** aTarget, unsigned int * aTargetLength, const char ** aLink, unsigned int * aLinkLength ) 159 | { 160 | // Проверка аргументов. 161 | if( !aAnswer || !aURL || !aURLLength || !aTarget || !aTargetLength || !aLink || !aLinkLength ) 162 | return clrcErrorInvArgs; 163 | 164 | // Проверка количества элементов. 165 | if( aItemInd >= aAnswer->vItemsNumber ) 166 | return clrcErrorInvArgs; 167 | 168 | // Проверка типа элемента. 169 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeTagHref ) 170 | return clrcErrorInvArgs; 171 | 172 | // Получение данных. 173 | *aURL = aAnswer->vItems[aItemInd].vValue.vHref.vURL; 174 | *aURLLength = aAnswer->vItems[aItemInd].vValue.vHref.vURLLength; 175 | 176 | *aLink = aAnswer->vItems[aItemInd].vValue.vHref.vLink; 177 | *aLinkLength = aAnswer->vItems[aItemInd].vValue.vHref.vLinkLength; 178 | 179 | *aTarget = aAnswer->vItems[aItemInd].vValue.vHref.vTarget; 180 | *aTargetLength = aAnswer->vItems[aItemInd].vValue.vHref.vTargetLength; 181 | 182 | return clrcSuccess; 183 | } 184 | 185 | ClientLibReturnCode cl_answer_get_instruct( const Answer * aAnswer, unsigned int aItemInd, const char ** aVarName, unsigned int * aVarNameLength, 186 | const char ** aValue, unsigned int * aValueLength ) 187 | { 188 | // Проверка аргументов. 189 | if( !aAnswer || !aVarName || !aVarNameLength || !aValue || !aValueLength ) 190 | return clrcErrorInvArgs; 191 | 192 | // Проверка количества элементов. 193 | if( aItemInd >= aAnswer->vItemsNumber ) 194 | return clrcErrorInvArgs; 195 | 196 | // Проверка типа элемента. 197 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeInstruct ) 198 | return clrcErrorInvArgs; 199 | 200 | // Получение данных. 201 | *aVarName = aAnswer->vItems[aItemInd].vValue.vInstruct.vVarName; 202 | *aVarNameLength = aAnswer->vItems[aItemInd].vValue.vInstruct.vVarNameLength; 203 | 204 | *aValue = aAnswer->vItems[aItemInd].vValue.vInstruct.vValue; 205 | *aValueLength = aAnswer->vItems[aItemInd].vValue.vInstruct.vValueLength; 206 | 207 | return clrcSuccess; 208 | } 209 | 210 | ClientLibReturnCode cl_answer_get_tag_open_window( const Answer * aAnswer, unsigned int aItemInd, const char ** aURL, unsigned int * aURLLength, unsigned int * aTarget ) 211 | { 212 | // Проверка аргументов. 213 | if( !aAnswer || !aURL || !aURLLength || !aTarget ) 214 | return clrcErrorInvArgs; 215 | 216 | // Проверка количества элементов. 217 | if( aItemInd >= aAnswer->vItemsNumber ) 218 | return clrcErrorInvArgs; 219 | 220 | // Проверка типа элемента. 221 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeTagOpenWindow ) 222 | return clrcErrorInvArgs; 223 | 224 | // Получение данных. 225 | *aURL = aAnswer->vItems[aItemInd].vValue.vOpenWindow.vURL; 226 | *aURLLength = aAnswer->vItems[aItemInd].vValue.vOpenWindow.vURLLength; 227 | 228 | *aTarget = aAnswer->vItems[aItemInd].vValue.vOpenWindow.vParentWindow; 229 | 230 | return clrcSuccess; 231 | } 232 | 233 | ClientLibReturnCode cl_answer_get_tag_rss( const Answer * aAnswer, unsigned int aItemInd, const char ** aURL, unsigned int * aURLLength, 234 | const char ** aAlt, unsigned int * aAltLength, unsigned int * aOffset, unsigned int * aShowTitle, 235 | unsigned int * aShowLink, unsigned int * aUpdatePeriod ) 236 | { 237 | // Проверка аргументов. 238 | if( !aAnswer || !aURL || !aURLLength || !aAlt || !aAltLength || !aOffset || !aShowTitle || !aShowLink || !aUpdatePeriod ) 239 | return clrcErrorInvArgs; 240 | 241 | // Проверка количества элементов. 242 | if( aItemInd >= aAnswer->vItemsNumber ) 243 | return clrcErrorInvArgs; 244 | 245 | // Проверка типа аргумента. 246 | if( aAnswer->vItems[aItemInd].vType != AnswerItemTypeTagRSS ) 247 | return clrcErrorInvArgs; 248 | 249 | // Получение данных. 250 | *aURL = aAnswer->vItems[aItemInd].vValue.vRSS.vURL; 251 | *aURLLength = aAnswer->vItems[aItemInd].vValue.vRSS.vURLLength; 252 | 253 | *aAlt = aAnswer->vItems[aItemInd].vValue.vRSS.vAlt; 254 | *aAltLength = aAnswer->vItems[aItemInd].vValue.vRSS.vAltLength; 255 | 256 | *aOffset = aAnswer->vItems[aItemInd].vValue.vRSS.vOffset; 257 | 258 | *aShowTitle = aAnswer->vItems[aItemInd].vValue.vRSS.vShowTitle; 259 | 260 | *aShowLink = aAnswer->vItems[aItemInd].vValue.vRSS.vShowLink; 261 | 262 | *aUpdatePeriod = aAnswer->vItems[aItemInd].vValue.vRSS.vUpdatePeriod; 263 | 264 | return clrcSuccess; 265 | } 266 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Answer.h: -------------------------------------------------------------------------------- 1 | #ifndef __Response_h__ 2 | #define __Response_h__ 3 | 4 | /** 5 | * @todo Нужно перейти на использование iAnswer::Item. 6 | */ 7 | 8 | #include "ClientLib.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" 12 | { 13 | #endif 14 | 15 | /** Элемент ответа сервера. */ 16 | typedef struct 17 | { 18 | /** Тип элемента ответа сервера. */ 19 | AnswerItemType vType; 20 | 21 | /** Значение элемента. */ 22 | union 23 | { 24 | 25 | /** Текстовая строка. */ 26 | struct 27 | { 28 | /** Текст. */ 29 | char * vText; 30 | /** Длина текста. */ 31 | unsigned int vTextLength; 32 | } vString; 33 | 34 | /** Кликабельный ответ инфа. */ 35 | struct 36 | { 37 | /** Текст запроса. */ 38 | char * vValue; 39 | /** Длина текста запроса. */ 40 | unsigned int vValueLength; 41 | /** Текст запроса, отправляемого движку. */ 42 | char * vRequest; 43 | /** Длина запроса, отправляемого движку. */ 44 | unsigned int vRequestLength; 45 | } vInf; 46 | 47 | /** Ссылка. */ 48 | struct 49 | { 50 | /** Урл ссылки. */ 51 | char * vURL; 52 | /** Длина урла ссылки. */ 53 | unsigned int vURLLength; 54 | /** Текст ссылки. */ 55 | char * vLink; 56 | /** Длина текста ссылки. */ 57 | unsigned int vLinkLength; 58 | /** Параметр target для ссылки. */ 59 | char * vTarget; 60 | /** Длина параметра target для ссылки. */ 61 | unsigned int vTargetLength; 62 | } vHref; 63 | 64 | /** Инструкция по изменению сессии. */ 65 | struct 66 | { 67 | /** Имя переменной. */ 68 | char * vVarName; 69 | /** Длина имени переменной. */ 70 | unsigned int vVarNameLength; 71 | /** Присваевоемое значение. */ 72 | char * vValue; 73 | /** Длина присваевоемого значения. */ 74 | unsigned int vValueLength; 75 | } vInstruct; 76 | 77 | /** Запрос открытия ссылки. */ 78 | struct 79 | { 80 | /** Значение урла ссылки. */ 81 | char * vURL; 82 | /** Длина значения урла ссылки. */ 83 | unsigned int vURLLength; 84 | /** Флаг, показывающий нужно ли открывать ссылку в новом окне или же в текущем. */ 85 | unsigned int vParentWindow; 86 | } vOpenWindow; 87 | 88 | /** Запрос RSS. */ 89 | struct 90 | { 91 | /** Значение урла RSS'а. */ 92 | char * vURL; 93 | /** Длина значения урла RSS'а. */ 94 | unsigned int vURLLength; 95 | /** Текст, показываемый при недоступности RSS. */ 96 | char * vAlt; 97 | /** Длина текста, показываемого при недоступности RSS. */ 98 | unsigned int vAltLength; 99 | /** Номер RSS записи. */ 100 | unsigned int vOffset; 101 | /** Флаг показа заголовка RSS. */ 102 | unsigned int vShowTitle; 103 | /** Флаг показа ссылки на RSS. */ 104 | unsigned int vShowLink; 105 | /** Частота обновления RSS. */ 106 | unsigned int vUpdatePeriod; 107 | } vRSS; 108 | } vValue; 109 | } __AnswerItem; 110 | 111 | /** Ответ сервера. */ 112 | struct __Answer 113 | { 114 | /** Количество элементов в ответе. **/ 115 | unsigned int vItemsNumber; 116 | 117 | /** Элементы ответа. **/ 118 | __AnswerItem * vItems; 119 | }; 120 | 121 | #ifdef __cplusplus 122 | } 123 | #endif 124 | 125 | #endif /** __Response_h__ */ 126 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( ClientLib ) 2 | cmake_minimum_required( VERSION 2.6 ) 3 | 4 | set( CMAKE_C_STANDARD 90 ) 5 | 6 | file( GLOB SOURCES *.c *.cpp *.h *.hpp ) 7 | 8 | add_library( ${PROJECT_NAME} STATIC ${SOURCES} $ $ ) 9 | 10 | target_compile_options( ${PROJECT_NAME} PRIVATE -fPIC ) 11 | 12 | target_include_directories( ${PROJECT_NAME} PRIVATE .. ) 13 | 14 | target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/.. ) 15 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/CSData.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file CSData.h 3 | * @author Fedor Zorky 4 | */ 5 | 6 | #ifndef __CSData_h__ 7 | #define __CSData_h__ 8 | 9 | #ifdef __cplusplus 10 | 11 | extern "C" 12 | { 13 | #include "../apcs/csdata.h" 14 | } 15 | 16 | #else 17 | 18 | #include "../apcs/csdata.h" 19 | 20 | #endif 21 | 22 | #endif /* __CSData_h__ */ 23 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/ClientLib.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __ClientLib_hpp__ 2 | #define __ClientLib_hpp__ 3 | 4 | #include "ClientLib.h" 5 | 6 | /** 7 | * Класс для коммуникации с сервером InfServer. 8 | */ 9 | class InfEngineClient 10 | { 11 | public: 12 | 13 | /** 14 | * Конструктор. 15 | * @param aConnectionString - строка соединения. Формат строки соединения: tcp:host:2255 или unix:socket 16 | * @param aTimeOut - значение таймаута в секундах. 17 | * @param aPackDataFlag - флаг, упаковки данных при пересылке между клиентом и сервером InfServer. 18 | */ 19 | InfEngineClient( const char * aConnectionString = NULL, unsigned int aTimeOut = CLIENT_LIB_DEFAULT_TIMEOUT, bool aPackDataFlag = true ) 20 | { 21 | vConnectionString = aConnectionString; 22 | vTimeOut = aTimeOut; 23 | vPackDataFlag = aPackDataFlag; 24 | } 25 | 26 | 27 | public: 28 | 29 | /** 30 | * Установка строки соединения, описывающей тип и адрес для его установки. 31 | * @param aConnectionString - строка соединения. Формат строки соединения: tcp:host:2255 или unix:socket 32 | */ 33 | void SetConnectData( const char * aConnectionString ) 34 | { 35 | vConnectionString = aConnectionString; 36 | } 37 | 38 | /** 39 | * Установка значения таймаута. 40 | * @param aTimeOut - значение таймаута в секундах. 41 | */ 42 | void SetTimeOut( unsigned int aTimeOut ) 43 | { 44 | vTimeOut = aTimeOut; 45 | } 46 | 47 | /** 48 | * Установка значения флага упаковки данных при пересылке между клиентом и сервером. 49 | * @param aPackDataFlag - флаг, упаковки данных при пересылке между клиентом и сервером InfServer. 50 | */ 51 | void SetPackDataFlag( bool aPackDataFlag ) 52 | { 53 | vPackDataFlag = aPackDataFlag; 54 | } 55 | 56 | 57 | public: 58 | 59 | /** 60 | * Запрос инициализации сервером сессии с идентификатором aSessionId для инфа aInfId. В aMissedDataMask помещается 61 | * битовая маска недостающих компонентов или 0, если таковых нет. 62 | * @param aInfId - идентификатор инфа. 63 | * @param aSessionId - идентификатор сессии. 64 | * @param aMissedDataMask - маска недостающих компонентов. 65 | */ 66 | ClientLibReturnCode InitSession( unsigned int aInfId, unsigned int aSessionId, unsigned int & aMissedDataMask ) const 67 | { 68 | return cl_cmd_init( aInfId, aSessionId, &aMissedDataMask, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 69 | } 70 | 71 | /** 72 | * Удаление сессии с идентификатором SessionId из кеша сервера. 73 | * @param aSessionId - идентификатор сессии. 74 | */ 75 | ClientLibReturnCode PurgeSession( unsigned int aSessionId ) 76 | { 77 | return cl_cmd_purge_session( aSessionId, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 78 | } 79 | 80 | /** 81 | * Обновление или добавление сессии в кэш сервера. 82 | * @param aSessionData - данные сессии. 83 | */ 84 | ClientLibReturnCode SendSession( const SessionData & aSessionData ) const 85 | { 86 | return cl_cmd_send_session( &aSessionData, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 87 | } 88 | 89 | /** 90 | * Обновление данных сессии. 91 | * @param aSessionData - изменения, которые нужно внести в данные сессии. 92 | */ 93 | ClientLibReturnCode UpdateSession( const SessionData & aSessionData ) const 94 | { 95 | return cl_cmd_update_session( &aSessionData, vConnectionString, vTimeOut, vPackDataFlag ); 96 | } 97 | 98 | 99 | 100 | public: 101 | 102 | /** 103 | * Запрос ответа сервера на запрос aRequest, относящийся к сессии с идентификатором aSessionId 104 | * и инфу с идентификатором aInfId. 105 | * @param aSessionId - идентификатор сессии. 106 | * @param aInfId - идентификатор инфа. 107 | * @param aRequest - реплика пользователя. 108 | * @param aVarsList - список переменных, которые нужно обновить до ответа на запрос. 109 | * @param aMissedDataMask - маска недостающих компонентов. 110 | * @param aAnswer - ответ бэкэнда на вопрос пользователя. Память под ответ выделяется. Освобождать ее нужно cl_answer_free. 111 | */ 112 | ClientLibReturnCode SendRequest( unsigned int aSessionId, unsigned int aInfId, const char * aRequest, const SessionData & aVarsList, unsigned int & aMissedDataMask, Answer* & aAnswer ) const 113 | { 114 | return cl_cmd_request( aSessionId, aInfId, aRequest, &aVarsList, &aMissedDataMask, &aAnswer, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 115 | } 116 | 117 | 118 | public: 119 | 120 | /** 121 | * Удаление инфа из кэша бэкэнда. 122 | * @param aInfId - идентификатор инфа. 123 | */ 124 | ClientLibReturnCode PurgeInf( unsigned int aInfId ) 125 | { 126 | return cl_cmd_purge_inf( aInfId, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 127 | } 128 | 129 | /** 130 | * Обновление или добавление в кэш сервера данных инфа. 131 | * @param aInfData - данные инфа. 132 | */ 133 | ClientLibReturnCode SendInf( const InfData & aInfData ) const 134 | { 135 | return cl_cmd_send_inf( &aInfData, vConnectionString, vTimeOut, vPackDataFlag ? 1 : 0 ); 136 | } 137 | 138 | 139 | private: 140 | /** Сторка соединения с сервером. */ 141 | const char * vConnectionString; 142 | 143 | /** Таймаут. */ 144 | unsigned int vTimeOut; 145 | 146 | /** Флаг, упаковки данных при пересылке между клиентом и сервером InfServer. */ 147 | bool vPackDataFlag; 148 | }; 149 | 150 | #endif /** __ClientLib_hpp__ */ 151 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Errors.h: -------------------------------------------------------------------------------- 1 | #ifndef __InfEngineErrors_h__ 2 | #define __InfEngineErrors_h__ 3 | 4 | /** 5 | * Коды возврата ошибок. 6 | */ 7 | typedef enum 8 | { 9 | /** Успех. */ 10 | INF_ENGINE_SUCCESS = 0, 11 | 12 | /** Неизвестная ошибка. **/ 13 | INF_ENGINE_ERROR_FAULT = -200, 14 | /** Выход данных за допустимые границы. **/ 15 | INF_ENGINE_ERROR_OUT_OF_RANGE = -201, 16 | /** Ошибка при работе с fstorage. **/ 17 | INF_ENGINE_ERROR_FSTORAGE = -202, 18 | /** Ошибка работы с файлами. **/ 19 | INF_ENGINE_ERROR_FILE = -203, 20 | /** Ошибка в данных. **/ 21 | INF_ENGINE_ERROR_DATA = -204, 22 | /** Некорректное состояние объекта. **/ 23 | INF_ENGINE_ERROR_STATE = -205, 24 | /** Функции были переданы некорректные аргументы. **/ 25 | INF_ENGINE_ERROR_INV_ARGS = -206, 26 | /** Неверное количество аргументов при вызове функции. */ 27 | INF_ENGINE_ERROR_ARGC = -207, 28 | /** Не найдена точка входа в динамической библиотеке. */ 29 | INF_ENGINE_ERROR_ENTRY_POINT = -208, 30 | /** Ошибка работы с фнкцией в динамической библиотеке. */ 31 | INF_ENGINE_ERROR_DLF = -209, 32 | /** Ошибка работы с фнкцией в динамической библиотеке. */ 33 | INF_ENGINE_ERROR_INVALID_ARG = -210, 34 | /** Недопустимая версия функции. */ 35 | INF_ENGINE_ERROR_FUNC_VERSION = -211, 36 | /** Исключить из рассмотрения шаблон-ответ, в котором функция вернула такой результат. */ 37 | INF_ENGINE_ERROR_DLF_SKIP_ANSWER = -212, 38 | /** Недопустимая версия API функции. */ 39 | INF_ENGINE_ERROR_FUNC_API_VERSION = -213, 40 | /** Низвестный алиас. */ 41 | INF_ENGINE_ERROR_UNKNOWN_ALIAS = -214, 42 | /** Низвестный тэг, представленный как функция. */ 43 | INF_ENGINE_ERROR_UNKNOWN_FUNCTIONALIKE_TAG = -215, 44 | /** Внтуренняя DL-функция не инициализирована. */ 45 | INF_ENGINE_ERROR_FUNC_NOT_INITIALIZED = -216, 46 | 47 | /** Неудачная попытка, необходмо повторить процедуру. **/ 48 | INF_ENGINE_AGAIN = 200, 49 | 50 | 51 | 52 | 53 | 54 | /** Внутренняя ошибка. **/ 55 | INF_ENGINE_ERROR_INTERNAL = -101, 56 | 57 | 58 | 59 | /* Ошибка работы с памятью - не могу выделить нужный объем памяти. */ 60 | INF_ENGINE_ERROR_NOFREE_MEMORY = -6, 61 | /* Ошибка открытия файла или другого объекта. */ 62 | INF_ENGINE_ERROR_CANT_OPEN = -8, 63 | /* Обшика разбора. */ 64 | INF_ENGINE_ERROR_CANT_PARSE = -9, 65 | /* Некорректные данные. */ 66 | INF_ENGINE_ERROR_INV_DATA = -10, 67 | /* Ошибка операции создания объекта. */ 68 | INF_ENGINE_ERROR_CANT_CREATE = -12, 69 | /* Ошибка операции чтения. */ 70 | INF_ENGINE_ERROR_CANT_READ = -13, 71 | /* Ошибка операции записи. */ 72 | INF_ENGINE_ERROR_CANT_WRITE = -14, 73 | /* Ошибка при соединении или в процессе обмена данными. */ 74 | INF_ENGINE_ERROR_CANT_CONNECT = -15, 75 | /* Ошибка чексуммы. */ 76 | INF_ENGINE_ERROR_CHECKSUMM = -16, 77 | /* На входе - пустая строка. */ 78 | INF_ENGINE_ERROR_EMPTY_STRING = -17, 79 | 80 | /* Некорректный протокол. */ 81 | INF_ENGINE_ERROR_INV_PROTOCOL = -100, 82 | 83 | /* Фатальная ошибка сервера. */ 84 | INF_ENGINE_ERROR_FATAL = -102, 85 | 86 | /* Ошибки нет, но операция не успешна. */ 87 | INF_ENGINE_WARN_UNSUCCESS = 1, 88 | 89 | /* Ошибка библиотеки NanoLib */ 90 | INF_ENGINE_ERROR_NANOLIB = -102, 91 | /* Достигнут лимит на количест-во элементов. */ 92 | INF_ENGINE_ERROR_LIMIT = -103, 93 | /**/ 94 | INF_ENGINE_ERROR_EMPTY = -104, 95 | /* Не получается добавить элемент в хэш. */ 96 | INF_ENGINE_ERROR_INSERT = -105, 97 | 98 | /* Ошибка при попытке добавить термин. */ 99 | INF_ENGINE_ERROR_ADD_TERM = -107, 100 | 101 | // Ошибка работы с кэшем. 102 | INF_ENGINE_ERROR_CACHE = -108, 103 | 104 | 105 | 106 | 107 | /* Предупреждение библиотеки NanoLib */ 108 | INF_ENGINE_WARN_NANOLIB = 102, 109 | 110 | /* Предупреждение библиотеки NanoLib */ 111 | INF_ENGINE_WARN_SYNONYM_DUPLICATE = 103, 112 | 113 | INF_ENGINE_WARN_ELEMENT_EXISTS = 104, /** Элемент существует. */ 114 | 115 | INF_ENGINE_WARN_ELEMENT_DOESNT_EXIST = 105, /** Элемент не существует. */ 116 | 117 | INF_ENGINE_WARN_BAD_FORMAT = 106, /** Неверный формат данных. */ 118 | 119 | 120 | /** Ошибка таймаута. */ 121 | INF_ENGINE_ERROR_TIMEOUT = -300, 122 | 123 | /** Ошибка компиляции шаблонов. */ 124 | INF_ENGINE_ERROR_PATTERN_COMPILATION = -301, 125 | 126 | /** Процесс завершился падением. */ 127 | INF_ENGINE_SERVER_CRASHED = -303, 128 | 129 | /** Процесс сервера получил сигналл KILL. */ 130 | INF_ENGINE_ERROR_SERVER_KILLED = -302, 131 | 132 | } InfEngineErrors; 133 | #endif // __InfEngineErrors_h__ 134 | 135 | 136 | #define INF_ENGINE_STRING_ERROR_INTERNAL "Internal error." 137 | 138 | #define INF_ENGINE_STRING_ERROR_INVALID_ARGUMENTS "Internal error. Invalid arguments." 139 | 140 | #define INF_ENGINE_STRING_ERROR_CANT_ALLOCATE_MEMORY "Can't allocate memory." 141 | 142 | #define INF_ENGINE_STRING_ERROR_INVALID_DATA "Internal error. Invalid data." 143 | 144 | #define INF_ENGINE_STRING_ERROR_RECREATE "Internal error. Trying recreate object, that has been created already." 145 | #define INF_ENGINE_STRING_ERROR_REINIT "Internal error. Trying reinitialize object, that has been initialized already." 146 | #define INF_ENGINE_STRING_ERROR_STATE "Internal error. Object has incorrect status." 147 | 148 | 149 | #define INF_ENGINE_STRING_ERROR_LOW_SAVE_BUFFER_SIZE "Internal error. Size of buffer is not enough for saving object." 150 | #define INF_ENGINE_STRING_ERROR_INCORRECT_SIZE_OF_SAVING_RESULT "Internal error. Incorrect size of saving result." 151 | #define INF_ENGINE_STRING_ERROR_INCORRECT_SIZE_OF_LOADING_RESULT "Internal error. Incorrect size of loading result." 152 | 153 | #define INF_ENGINE_STRING_ERROR_FAILED_LOAD_DL "Internal error. Loading dynamic library failed." 154 | #define INF_ENGINE_STRING_ERROR_FAILED_FOUND_ENTRY_POINT "Internal error. Binding dynamic library failed." 155 | #define INF_ENGINE_STRING_ERROR_DLF "Internal error. Dynamic library function error." 156 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/InfData.c: -------------------------------------------------------------------------------- 1 | #include "InfData.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "ClientLib.h" 7 | 8 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 9 | * 10 | * Данные инфа и функции для работы с ними. 11 | * 12 | ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ 13 | 14 | ClientLibReturnCode cl_inf_init( InfData * aInfData ) 15 | { 16 | // Проверка аргументов. 17 | if( !aInfData ) 18 | return clrcErrorInvArgs; 19 | 20 | // Инициализция профиля инфа. 21 | aInfData->vInfId = 0; 22 | aInfData->vTemplates = NULL; 23 | aInfData->vVarsNumber = 0; 24 | aInfData->vVars = NULL; 25 | aInfData->vDictsNumber = 0; 26 | aInfData->vDicts = NULL; 27 | aInfData->vMemory = NULL; 28 | aInfData->vMemAvalible = 0; 29 | 30 | return clrcSuccess; 31 | } 32 | 33 | InfData * cl_inf_create() 34 | { 35 | // Выделение памяти под профиль данных инфа. 36 | InfData * NewInfData = (InfData*)malloc( sizeof( InfData ) ); 37 | if( !NewInfData ) 38 | return NULL; 39 | 40 | // Инициализация профиля данных инфа. 41 | cl_inf_init( NewInfData ); 42 | 43 | return NewInfData; 44 | } 45 | 46 | ClientLibReturnCode cl_inf_resize( InfData * aInfData, unsigned int aVarsNumber, unsigned int aDictsNumber ) 47 | { 48 | // Проверка аргументов. 49 | if( !aInfData ) 50 | return clrcErrorInvArgs; 51 | 52 | // Выделение памяти. 53 | if( aInfData->vMemAvalible < aVarsNumber * sizeof( __Var ) + aDictsNumber * sizeof( __Dict ) ) 54 | { 55 | // Выделение памяти. 56 | if( aInfData->vMemory ) 57 | aInfData->vMemory = realloc( aInfData->vMemory, aVarsNumber * sizeof( __Var ) + aDictsNumber * sizeof( __Dict ) ); 58 | else 59 | aInfData->vMemory = malloc( aVarsNumber * sizeof( __Var ) + aDictsNumber * sizeof( __Dict ) ); 60 | 61 | if( !aInfData->vMemory ) 62 | { 63 | cl_inf_init( aInfData ); 64 | 65 | return clrcErrorNoFreeMemory; 66 | } 67 | 68 | aInfData->vMemAvalible = aVarsNumber * sizeof( __Var ) + aDictsNumber * sizeof( __Dict ); 69 | } 70 | 71 | // Очистка буфера. 72 | bzero( aInfData->vMemory, aVarsNumber * sizeof( __Var ) + aDictsNumber * sizeof( __Dict ) ); 73 | aInfData->vVars = aInfData->vMemory; 74 | aInfData->vDicts = aInfData->vMemory + aVarsNumber * sizeof( __Var ); 75 | 76 | aInfData->vVarsNumber = aVarsNumber; 77 | aInfData->vDictsNumber = aDictsNumber; 78 | 79 | return clrcSuccess; 80 | } 81 | 82 | void cl_inf_set_var( InfData * aInfData, unsigned int aVarInd, const char * aVarName, const char * aVarValue ) 83 | { 84 | // Проверка аргументов. 85 | if( !aInfData || !aVarName ) 86 | return; 87 | 88 | if( aVarInd >= aInfData->vVarsNumber ) 89 | return; 90 | 91 | // Установка данных. 92 | aInfData->vVars[aVarInd].vName = aVarName; 93 | aInfData->vVars[aVarInd].vValue = aVarValue; 94 | } 95 | 96 | void cl_inf_set_dict( InfData * aInfData, unsigned int aDictInd, const char * aDictName, const char * aDict ) 97 | { 98 | // Проверка аргументов. 99 | if( !aInfData || !aDictName ) 100 | return; 101 | 102 | if( aDictInd >= aInfData->vDictsNumber ) 103 | return; 104 | 105 | // Установка данных. 106 | aInfData->vDicts[aDictInd].vName = aDictName; 107 | aInfData->vDicts[aDictInd].vData = aDict; 108 | } 109 | 110 | void cl_inf_set_id( InfData * aInfData, unsigned int aInfId ) 111 | { 112 | if( aInfData ) 113 | aInfData->vInfId = aInfId; 114 | } 115 | 116 | void cl_inf_set_templates( InfData * aInfData, const char * aTemplates ) 117 | { 118 | if( aInfData ) 119 | aInfData->vTemplates = aTemplates; 120 | } 121 | 122 | unsigned int cl_inf_get_vars_cnt( const InfData * aInfData ) 123 | { 124 | if( !aInfData ) 125 | return 0; 126 | else 127 | return aInfData->vVarsNumber; 128 | } 129 | 130 | unsigned int cl_inf_get_dicts_cnt( const InfData * aInfData ) 131 | { 132 | if( !aInfData ) 133 | return 0; 134 | else 135 | return aInfData->vDictsNumber; 136 | } 137 | 138 | ClientLibReturnCode cl_inf_get_var( const InfData * aInfData, unsigned int aVarInd, const char ** aVarName, const char ** aVarValue ) 139 | { 140 | // Проверка аргументов. 141 | if( !aInfData || !aVarName || !aVarValue ) 142 | return clrcErrorInvArgs; 143 | 144 | if( aVarInd >= aInfData->vVarsNumber ) 145 | return clrcErrorInvArgs; 146 | 147 | // Получение данных. 148 | *aVarName = aInfData->vVars[aVarInd].vName; 149 | *aVarValue = aInfData->vVars[aVarInd].vValue; 150 | 151 | return clrcSuccess; 152 | } 153 | 154 | ClientLibReturnCode cl_inf_get_dict( const InfData * aInfData, unsigned int aDictInd, const char ** aDictName, const char ** aDictText ) 155 | { 156 | // Проверка аргументов. 157 | if( !aInfData || !aDictName || !aDictText ) 158 | return clrcErrorInvArgs; 159 | 160 | if( aDictInd >= aInfData->vDictsNumber ) 161 | return clrcErrorInvArgs; 162 | 163 | // Получение данных. 164 | *aDictName = aInfData->vDicts[aDictInd].vName; 165 | *aDictText = aInfData->vDicts[aDictInd].vData; 166 | 167 | return clrcSuccess; 168 | } 169 | 170 | void cl_inf_free( InfData * aInfData ) 171 | { 172 | // Проверка аргументов. 173 | if( !aInfData ) 174 | return; 175 | 176 | // Освобождение памяти, занимаемой переменными профиля данных инфа. 177 | if( aInfData->vMemAvalible ) 178 | free( aInfData->vMemory ); 179 | 180 | // Освобождение памяти, занимаемой структурой профиля данных инфа. 181 | free( aInfData ); 182 | } 183 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/InfData.h: -------------------------------------------------------------------------------- 1 | #ifndef __InfData_h__ 2 | #define __InfData_h__ 3 | 4 | #include "SessionData.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | 11 | /** Структура описывающая словарь. */ 12 | typedef struct 13 | { 14 | /** Имя словаря. */ 15 | const char * vName; 16 | 17 | /** Данные словаря. */ 18 | const char * vData; 19 | } __Dict; 20 | 21 | /** Структура описывающая данные инфа. */ 22 | struct __InfData 23 | { 24 | /** Идентификатор инфа. */ 25 | unsigned int vInfId; 26 | 27 | /** Шаблоны инфа. */ 28 | const char * vTemplates; 29 | 30 | /** Количество переменных инфа. */ 31 | unsigned int vVarsNumber; 32 | 33 | /** Переменные инфа. */ 34 | __Var * vVars; 35 | 36 | /** Количество словарей инфа. */ 37 | unsigned int vDictsNumber; 38 | 39 | /** Словари инфа. */ 40 | __Dict * vDicts; 41 | 42 | /** Буфер, выделенный под данные инфа. */ 43 | void * vMemory; 44 | 45 | /** Количество памяти, выделенной под данные инфа. Может превышать реальный размер данных. */ 46 | unsigned int vMemAvalible; 47 | }; 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif /** __InfData_h__ */ 54 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/ItemTypes.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __InfPatternItemTypes_h__ 2 | #define __InfPatternItemTypes_h__ 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | namespace InfPatternItems 9 | { 10 | #endif 11 | 12 | /** Типы элементов. **/ 13 | typedef enum 14 | { 15 | itInstruct = 1, /** Тэг изменения значения переменной. */ 16 | itText = 2, /** Текстовая строка. */ 17 | itInf = 3, /** Тэг ответа инфа. */ 18 | itBr = 4, /** Тег переноса строки. */ 19 | itHref = 5, /** Тэг ссылки. */ 20 | itCommercial = 7, /** Запрос к клиентской базе данных. */ 21 | itOpenWindow = 8, /** Тэг открытия ссылки в новом окне. */ 22 | itReference = 9, /** Ссылка на фрагмент поискового шаблона. */ 23 | itGetAnswer = 10, /** Тэг обращения к шаблон-ответу другого шаблона. */ 24 | itDict = 11, /** Тэг обращения к словарю. */ 25 | itIf = 12, /** Тэг выбора. */ 26 | itVar = 13, /** Тэг обращения к переменной. */ 27 | itStar = 14, /** Тэг обращения к звездочке. */ 28 | itDictInline = 15, /** Тэг словаря-inline. */ 29 | itCondition = 16, /** Условие. */ 30 | itExtCall = 17, /** Запрос к внешнему сервису. */ 31 | itEliStar = 18, /** Тэг звездочки, используемый для шаблонов эллипсисов. */ 32 | itEliReference = 19, /** Ссылка на фрагмент поискового шаблона эллипсисов. */ 33 | itFunction = 20, /** Тэг функции. */ 34 | itFunctionArg = 21, /** Аргумент функции. */ 35 | itTagRSS = 22, /** Тэг запроса RSS. */ 36 | itSpace = 23, /** Тэг пробельного символа. */ 37 | itKeywordArgument = 24, /** Именованный аргумент. */ 38 | itExtServiceCall = 25, /** Тэг запроса к универсальному сервису. */ 39 | itBreak = 26, /** Тег отбрасывания ответа. */ 40 | itExtendAnswer = 27, /** Тег добавления к текущему шаблон-ответу шаблон-ответа из другого шаблона. */ 41 | itDictRef = 28, /** Ссылка на словарь в шаблон-вопросе по его порядковому номеру. */ 42 | itPre = 29, /** Неинтерпретируемый текст. */ 43 | itSwitch = 30, /** Тэг выбора. */ 44 | itTLCS = 31, /** Условный оператор уровня шаблона. */ 45 | itNothing = 32, /** Тэг nothing. */ 46 | itDisableautovars = 33, /** Тэг отключения автоматического изменения переменных. */ 47 | itStartOList = 34, /** Тэг начала упорядоченного списка. */ 48 | itStartUList = 35, /** Тэг начала неупорядоченного списка. */ 49 | itListItem = 36, /** Тэг начала элемента списка. */ 50 | itEndList = 37, /** Тэг завершения списка */ 51 | } ItemType; 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif /** __InfPatternItemTypes_h__ */ 57 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/Protocol.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __InfEngineProtocol_hpp__ 2 | #define __InfEngineProtocol_hpp__ 3 | 4 | #include 5 | 6 | #ifndef CSDATA_EXTENDED 7 | #define CSDATA_EXTENDED 8 | #endif /** CSDATA_EXTENDED */ 9 | 10 | #include "Errors.h" 11 | 12 | #define PEDANTIC_PROTOCOL 13 | 14 | #include "CSData.hpp" 15 | 16 | /** Текущая версия протокола. */ 17 | const int INF_ENGINE_PROTOCOL_VERSION = 6; 18 | 19 | /** Минимальная версия, совместимая с текущей. */ 20 | const int INF_ENGINE_MIN_COMPATIBLE_PROTOCOL_VERSION = 4; 21 | 22 | /** Количество команд в протоколе. */ 23 | const int INF_ENGINE_COMMANDS_NUMBER = 11; 24 | 25 | /** Команды протокола. */ 26 | typedef enum InfEngineProtocol 27 | { 28 | INF_ENGINE_PROTOCOL_INIT = 1, 29 | INF_ENGINE_PROTOCOL_PURGE_SESSION = 2, 30 | INF_ENGINE_PROTOCOL_SET_SESSION = 3, 31 | INF_ENGINE_PROTOCOL_REQUEST = 4, 32 | INF_ENGINE_PROTOCOL_PURGE_INF = 5, 33 | INF_ENGINE_PROTOCOL_SET_INF = 6, 34 | INF_ENGINE_PROTOCOL_GET_CACHED_SESSIONS_COUNT = 7, 35 | INF_ENGINE_PROTOCOL_GET_SESSIONS_IDS = 8, 36 | INF_ENGINE_PROTOCOL_GET_CACHED_SESSION_DATA = 9, 37 | INF_ENGINE_PROTOCOL_GET_CACHED_SESSIONS_ALL_DATA = 10, 38 | INF_ENGINE_PROTOCOL_UPDATE_SESSION = 11 39 | } InfEngineProtocol; 40 | 41 | /** 42 | * Проверка версии протокола. 43 | * @param aProtocolVersion - версия протокола. 44 | * @return 1, в случае положительной проверки, иначе 0. 45 | */ 46 | inline int CheckProtocolVersion( unsigned int aProtocolVersion ) 47 | { 48 | return INF_ENGINE_MIN_COMPATIBLE_PROTOCOL_VERSION <= aProtocolVersion && aProtocolVersion <= INF_ENGINE_PROTOCOL_VERSION ? 1 : 0; 49 | } 50 | 51 | /** 52 | * Получение значение поля типа int. 53 | * 54 | * @param aData - указатель на пакет. 55 | * @param aPos - позиция элемента. 56 | * @param aName - имя для проверки названия элемента. 57 | * @param aResult - указатель на результат. 58 | * 59 | * @retval INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 60 | */ 61 | inline InfEngineErrors IEP_GetInt( csdata_data_t * aData, int aPos, const char * aName, int * aResult ) 62 | { 63 | if( aData->attr_count < (unsigned int)aPos + 1 ) 64 | return INF_ENGINE_ERROR_INV_DATA; 65 | 66 | if( !( aData->attr_list[aPos].attr_type & CSDATA_INT ) ) 67 | return INF_ENGINE_ERROR_INV_DATA; 68 | 69 | #ifdef PEDANTIC_PROTOCOL 70 | if( aName && strcmp( aData->attr_list[aPos].attr_name, aName ) ) 71 | return INF_ENGINE_ERROR_INV_DATA; 72 | #endif 73 | 74 | *aResult = aData->attr_list[aPos].attr_value.attr_int; 75 | 76 | return INF_ENGINE_SUCCESS; 77 | } 78 | 79 | inline InfEngineErrors IEP_GetUInt32( csdata_data_t * aData, int aPos, const char * aName, uint32_t * aResult ) 80 | { 81 | if( aData->attr_count < (unsigned int)aPos + 1 ) 82 | return INF_ENGINE_ERROR_INV_DATA; 83 | 84 | if( !( aData->attr_list[aPos].attr_type & CSDATA_INT ) ) 85 | return INF_ENGINE_ERROR_INV_DATA; 86 | 87 | #ifdef PEDANTIC_PROTOCOL 88 | if( aName && strcmp( aData->attr_list[aPos].attr_name, aName ) ) 89 | return INF_ENGINE_ERROR_INV_DATA; 90 | #endif 91 | 92 | // Копирование без каста. 93 | memcpy( aResult, &( aData->attr_list[aPos].attr_value.attr_int ), sizeof( uint32_t ) ); 94 | 95 | return INF_ENGINE_SUCCESS; 96 | } 97 | 98 | /** 99 | * Получение значение поля типа string. 100 | * 101 | * @param aData - указатель на пакет. 102 | * @param aPos - позиция элемента. 103 | * @param aName - имя для проверки названия элемента. 104 | * @param aResult - указатель на результат. 105 | * 106 | * @retval INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 107 | */ 108 | inline InfEngineErrors IEP_GetString( csdata_data_t * aData, int aPos, const char * aName, const char ** aResult ) 109 | { 110 | if( aData->attr_count < (unsigned int)aPos + 1 ) 111 | return INF_ENGINE_ERROR_INV_DATA; 112 | 113 | if( !( aData->attr_list[aPos].attr_type & CSDATA_STRING ) ) 114 | return INF_ENGINE_ERROR_INV_DATA; 115 | 116 | #ifdef PEDANTIC_PROTOCOL 117 | if( aName && strcmp( aData->attr_list[aPos].attr_name, aName ) ) 118 | return INF_ENGINE_ERROR_INV_DATA; 119 | #endif 120 | 121 | *aResult = aData->attr_list[aPos].attr_value.attr_string; 122 | 123 | return INF_ENGINE_SUCCESS; 124 | } 125 | 126 | /** 127 | * Получение версии протокола. 128 | * 129 | * @param aData - указатель на пакет. 130 | * @param aResult - указатель на результат. 131 | * 132 | * @retval INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 133 | */ 134 | inline InfEngineErrors IEP_GetProtocol( csdata_data_t * aData, int * aResult ) 135 | { 136 | return IEP_GetInt( aData, 0, "protocol", aResult ); 137 | } 138 | 139 | /** 140 | * Получение статуса. 141 | * 142 | * @param aData - указатель на пакет. 143 | * @param aResult - указатель на результат. 144 | * 145 | * @retval: INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 146 | */ 147 | inline InfEngineErrors IEP_GetStatus( csdata_data_t * aData, int * aResult ) 148 | { 149 | return IEP_GetInt( aData, 1, "status", aResult ); 150 | } 151 | 152 | /** 153 | * Получение команды. 154 | * 155 | * @param aData - указатель на пакет. 156 | * @param aResult - указатель на результат. 157 | * 158 | * @retval: INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 159 | */ 160 | inline InfEngineErrors IEP_GetCmd( csdata_data_t * aData, InfEngineProtocol * aResult ) 161 | { 162 | int tmp = 0; 163 | InfEngineErrors iee = IEP_GetInt( aData, 1, "cmd", &tmp ); 164 | *aResult = (InfEngineProtocol)tmp; 165 | return iee; 166 | } 167 | 168 | /** 169 | * Получение идентификатора инфа. 170 | * 171 | * @param aData - указатель на пакет. 172 | * @param aResult - указатель на результат. 173 | * 174 | * @retval INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 175 | */ 176 | inline InfEngineErrors IEP_GetInfId( csdata_data_t * aData, int aPos, uint32_t * aResult ) 177 | { 178 | return IEP_GetUInt32( aData, aPos, "infid", aResult ); 179 | } 180 | 181 | /** 182 | * Получение идентификатора сессии. 183 | * 184 | * @param aData - указатель на пакет. 185 | * @param aResult - указатель на результат. 186 | * 187 | * @retval INF_ENGINE_SUCCESS, INF_ENGINE_ERROR_INV_DATA 188 | */ 189 | inline InfEngineErrors IEP_GetSessionId( csdata_data_t * aData, int aPos, uint32_t * aResult ) 190 | { 191 | return IEP_GetUInt32( aData, aPos, "sessionid", aResult ); 192 | } 193 | 194 | inline void IEP_SetInt( csdata_data_t * aData, int aPos, const char * aName, int aValue ) 195 | { 196 | aData->attr_list[aPos].attr_name = (char*)aName; 197 | aData->attr_list[aPos].attr_name_size = aName ? strlen( aName ) : 0; 198 | aData->attr_list[aPos].attr_type = (CSDATA_DATA_TYPES)( CSDATA_INT | CSDATA_KEEP_ANAME ); 199 | aData->attr_list[aPos].attr_value.attr_int = aValue; 200 | aData->attr_list[aPos].attr_value_size = sizeof( uint32_t ); 201 | } 202 | 203 | inline void IEP_SetUInt32( csdata_data_t * aData, int aPos, const char * aName, uint32_t aValue ) 204 | { 205 | int tmp; 206 | 207 | // Копируем данные каста. 208 | memcpy( &tmp, &aValue, sizeof( uint32_t ) ); 209 | 210 | aData->attr_list[aPos].attr_name = (char*)aName; 211 | aData->attr_list[aPos].attr_name_size = aName ? strlen( aName ) : 0; 212 | aData->attr_list[aPos].attr_type = (CSDATA_DATA_TYPES)( CSDATA_INT | CSDATA_KEEP_ANAME ); 213 | aData->attr_list[aPos].attr_value.attr_int = tmp; 214 | aData->attr_list[aPos].attr_value_size = sizeof( uint32_t ); 215 | } 216 | 217 | inline void IEP_SetString( csdata_data_t * aData, int aPos, const char * aName, const char * aValue ) 218 | { 219 | if( aName ) 220 | { 221 | aData->attr_list[aPos].attr_name = (char*)aName; 222 | aData->attr_list[aPos].attr_name_size = strlen( aName ); 223 | } 224 | else 225 | { 226 | aData->attr_list[aPos].attr_name = (char*)""; 227 | aData->attr_list[aPos].attr_name_size = 0; 228 | } 229 | aData->attr_list[aPos].attr_type = (CSDATA_DATA_TYPES)( CSDATA_STRING | CSDATA_KEEP_ANAME | CSDATA_KEEP_AVALUE ); 230 | aData->attr_list[aPos].attr_value.attr_string = (char*)aValue; 231 | aData->attr_list[aPos].attr_value_size = aValue ? strlen( aValue ) : 0; 232 | } 233 | 234 | /* 235 | * Проверка на ошибку. 236 | */ 237 | 238 | 239 | /* 240 | * Передача версии протокола. 241 | */ 242 | inline void IEP_SetProtocol( csdata_data_t * aData, unsigned int aProtocolVersion ) 243 | { 244 | IEP_SetInt( aData, 0, "protocol", aProtocolVersion ); 245 | } 246 | inline void IEP_SetCmd( csdata_data_t * aData, InfEngineProtocol aCmd ) 247 | { 248 | IEP_SetInt( aData, 1, "cmd", aCmd ); 249 | } 250 | inline void IEP_SetInfId( csdata_data_t * aData, int aPos, uint32_t aInfId ) 251 | { 252 | IEP_SetUInt32( aData, aPos, "infid", aInfId ); 253 | } 254 | inline void IEP_SetSessionId( csdata_data_t * aData, int aPos, uint32_t aSession ) 255 | { 256 | IEP_SetUInt32( aData, aPos, "sessionid", aSession ); 257 | } 258 | inline void IEP_SetStatus( csdata_data_t * aData, int aStatus ) 259 | { 260 | IEP_SetInt( aData, 1, "status", aStatus ); 261 | } 262 | 263 | #endif /** __InfEngineProtocol_hpp__ */ 264 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/SessionData.c: -------------------------------------------------------------------------------- 1 | #include "SessionData.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "ClientLib.h" 7 | 8 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 9 | * 10 | * Данные сессии и функции для работы с ней. 11 | * 12 | ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ 13 | 14 | ClientLibReturnCode cl_session_init( SessionData * aSessionData ) 15 | { 16 | // Проверка аргументов. 17 | if( !aSessionData ) 18 | return clrcErrorInvArgs; 19 | 20 | // Инициализация структуры. 21 | aSessionData->vInfId = 0; 22 | aSessionData->vSessionId = -1; 23 | aSessionData->vVarsNumber = 0; 24 | aSessionData->vVarsAvalible = 0; 25 | aSessionData->vVars = NULL; 26 | 27 | return clrcSuccess; 28 | } 29 | 30 | SessionData * cl_session_create() 31 | { 32 | // Выделение памяти под данные сессии. 33 | SessionData * NewSessionData = (SessionData*)malloc( sizeof( SessionData ) ); 34 | if( !NewSessionData ) 35 | return NULL; 36 | 37 | // Инициализация данных сессии. 38 | cl_session_init( NewSessionData ); 39 | 40 | return NewSessionData; 41 | } 42 | 43 | ClientLibReturnCode cl_session_resize( SessionData * aSessionData, unsigned int aVarsNumber ) 44 | { 45 | // Проверка аргументов. 46 | if( !aSessionData ) 47 | return clrcErrorInvArgs; 48 | 49 | // Выделение памяти. 50 | if( aSessionData->vVarsAvalible < aVarsNumber ) 51 | { 52 | if( aSessionData->vVars ) 53 | aSessionData->vVars = realloc( aSessionData->vVars, aVarsNumber * sizeof( __Var ) ); 54 | else 55 | aSessionData->vVars = malloc( aVarsNumber * sizeof( __Var ) ); 56 | 57 | if( !aSessionData->vVars ) 58 | { 59 | cl_session_init( aSessionData ); 60 | 61 | return clrcErrorNoFreeMemory; 62 | } 63 | 64 | aSessionData->vVarsAvalible = aVarsNumber; 65 | } 66 | 67 | // Очистка переменных. 68 | if( aVarsNumber ) 69 | bzero( aSessionData->vVars, sizeof( __Var ) * aVarsNumber ); 70 | 71 | aSessionData->vVarsNumber = aVarsNumber; 72 | 73 | return clrcSuccess; 74 | } 75 | 76 | void cl_session_set_var( SessionData * aSessionData, unsigned int aVarInd, const char * aVarName, const char * aVarValue ) 77 | { 78 | // Проверка аргументов. 79 | if( !aSessionData || !aVarName ) 80 | return; 81 | 82 | if( aVarInd >= aSessionData->vVarsNumber ) 83 | return; 84 | 85 | aSessionData->vVars[aVarInd].vName = aVarName; 86 | aSessionData->vVars[aVarInd].vValue = aVarValue; 87 | } 88 | 89 | void cl_session_set_id( SessionData * aSessionData, unsigned int aSessionId ) 90 | { 91 | if( aSessionData ) 92 | aSessionData->vSessionId = aSessionId; 93 | } 94 | 95 | void cl_session_set_inf_id( SessionData * aSessionData, unsigned int aInfId ) 96 | { 97 | if( aSessionData ) 98 | aSessionData->vInfId = aInfId; 99 | } 100 | 101 | unsigned int cl_session_get_size( const SessionData * aSessionData ) 102 | { 103 | if( !aSessionData ) 104 | return 0; 105 | else 106 | return aSessionData->vVarsNumber; 107 | } 108 | 109 | ClientLibReturnCode cl_session_get( const SessionData * aSessionData, unsigned int aVarInd, const char ** aVarName, const char ** aVarValue ) 110 | { 111 | // Проверка аргументов. 112 | if( !aSessionData || !aVarName || !aVarValue ) 113 | return clrcErrorInvArgs; 114 | 115 | if( aVarInd >= aSessionData->vVarsNumber ) 116 | return clrcErrorInvArgs; 117 | 118 | // Присовение значений. 119 | *aVarName = aSessionData->vVars[aVarInd].vName; 120 | *aVarValue = aSessionData->vVars[aVarInd].vValue; 121 | 122 | return clrcSuccess; 123 | } 124 | 125 | void cl_session_free( SessionData * aSessionData ) 126 | { 127 | // Проверка аргументов. 128 | if( !aSessionData ) 129 | return; 130 | 131 | // Освобождение памяти, занятой переменными. 132 | if( aSessionData->vVarsAvalible ) 133 | free( aSessionData->vVars ); 134 | 135 | // Освобождение памяти, занятой объектом сессии. 136 | free( aSessionData ); 137 | } 138 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/SessionData.h: -------------------------------------------------------------------------------- 1 | #ifndef __SessionData_h__ 2 | #define __SessionData_h__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | /** Структура описывающая переменную. */ 10 | typedef struct 11 | { 12 | /** Имя переменной. */ 13 | const char * vName; 14 | 15 | /** Значение переменной. */ 16 | const char * vValue; 17 | } __Var; 18 | 19 | /** Структура описывающая сессию. */ 20 | struct __SessionData 21 | { 22 | /** Идентификатор инфа. */ 23 | unsigned int vInfId; 24 | 25 | /** Идентификатор сессии. */ 26 | unsigned int vSessionId; 27 | 28 | /** Количество переменных в сессии. */ 29 | unsigned int vVarsNumber; 30 | 31 | /** Количество выделенной под переменные памяти. */ 32 | unsigned int vVarsAvalible; 33 | 34 | /** Список переменных. */ 35 | __Var * vVars; 36 | }; 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif /** __SessionData_h__ */ 43 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/ClientLib/csDataPack.h: -------------------------------------------------------------------------------- 1 | #ifndef __csDataPack_h__ 2 | #define __csDataPack_h__ 3 | 4 | /** 5 | * Подключение необходимых внешних библиотек. 6 | */ 7 | #include 8 | 9 | // @todo remove this ifdef. 10 | #ifndef CSDATA_EXTENDED 11 | # define CSDATA_EXTENDED 12 | #endif //CSDATA_EXTENDED 13 | 14 | #include "CSData.hpp" 15 | 16 | // Получение версии протокола упаковки данных. 17 | const char * csDataPackVersion(); 18 | 19 | 20 | /*************************************************************************************************** 21 | 22 | Флаги управляющие упаковкой данных. 23 | 24 | ***************************************************************************************************/ 25 | /** 26 | * На данный момент установка любого из флагов CSDATAPACK_SPLIT или CSDATAPACK_JOIN равносильна 27 | * установке флага CSDATAPACK_FULL. 28 | */ 29 | // Разрезать слишком большие данные. 30 | #define CSDATAPACK_SPLIT 1 31 | // Объединять слишком маленькие данные. 32 | #define CSDATAPACK_JOIN 2 33 | // Упаковывать и слишком большие и слишком маленькие данные. 34 | #define CSDATAPACK_FULL ( CSDATAPACK_SPLIT | CSDATAPACK_JOIN ) 35 | 36 | 37 | /*************************************************************************************************** 38 | 39 | Функции настройки размера передаваемых пакетов. 40 | 41 | ***************************************************************************************************/ 42 | /** 43 | * Функция возвращает максимально допустимый размер аттрибута в структуре csdata_data_t, 44 | * порождаемой функцией csDataPack. 45 | */ 46 | size_t GetMaxChunkSize(); 47 | /** 48 | * Функция устанавливает максимально допустимый размер аттрибута в структуре csdata_data_t, 49 | * порождаемой функцией csDataPack. Но при этом, если aNewMaxChunkSize больше чем 2^16, то 50 | * максимально допустимый размер аттрибута будет установлен в 2^16. Аналогично, если 51 | * aNewMaxChunkSize меньше чем 2^4, то максимальный размер аттрибута будет установлен в 2^4. 52 | * 53 | * @param aNewMaxChunkSize - новое значение для максимально допустимого размера аттрибута. 54 | */ 55 | #ifdef __cplusplus 56 | extern "C" 57 | { 58 | #endif 59 | void SetMaxChunkSize( size_t aNewMaxChunkSize ); 60 | #ifdef __cplusplus 61 | } 62 | #endif 63 | 64 | 65 | #ifdef __cplusplus 66 | /*************************************************************************************************** 67 | 68 | Функции упаковки и распаковки с возможностью использования внешнего реаллокатора памяти. 69 | С++ версия. 70 | 71 | ***************************************************************************************************/ 72 | /** Подключение менеджера памяти. **/ 73 | //#include 74 | 75 | /** 76 | * Упаковка подготовленных для отправки данных. Сгенерированные функцией данные, в случае 77 | * использования не полной упаковки, могут иметь прямые ссылки на элементы исходной структуры 78 | * aSource. Body не передается! 79 | * Вся память выделяется через aAllocator. 80 | * 81 | * @param aSource - исходные данные для упаковки. 82 | * @param aAllocator - ссылка на менеджер памяти. 83 | * @param aDataPackFlags - флаги, определяющие тип упаковки. 84 | */ 85 | csdata_data_t * csDataPack( csdata_data_t * aSource, nMemoryAllocator & aAllocator, int aDataPackFlags ); 86 | /** 87 | * Распаковка полученных данных. Сгенерированные функцией данные могут иметь прямые ссылки на 88 | * элементы исходной структуры aSource, если не использован флаг aFullAllocate в значении true. 89 | * Вся память выделяется через aAllocator. 90 | * 91 | * @param aSource - исходные данные для распаковки. 92 | * @param aAllocator - ссылка на менеджер памяти. 93 | * @param aFullAllocate - флаг, указывающий, что нужно копировать всю информацию из упакованной 94 | * структуры, а не использовать ее по ссылке. 95 | */ 96 | csdata_data_t * csDataUnPack( csdata_data_t * aSource, nMemoryAllocator & aAllocator, bool aFullAllocate = false ); 97 | 98 | #else 99 | /*************************************************************************************************** 100 | 101 | Вызовы функций упаковки и распаковки без возможности использования реаллокатора памяти. 102 | C версия. В данном случае аллокатор создается сам по себе и память освобождается путем вызова 103 | соответствующих функций. 104 | 105 | ***************************************************************************************************/ 106 | /** 107 | * Упаковка подготовленных для отправки данных. Сгенерированные функцией данные, в случае 108 | * использования не полной упаковки, могут иметь прямые ссылки на элементы исходной структуры 109 | * aSource. Body не передается! 110 | * Вся память выделяется через статический nMemoryAllocator. 111 | * 112 | * @param aSource - исходные данные для упаковки. 113 | * @param aDataPackFlags - флаги, определяющие тип упаковки. 114 | */ 115 | csdata_data_t * csDataPack( csdata_data_t * aSource, int aDataPackFlags ); 116 | /** 117 | * Распаковка полученных данных. Сгенерированные функцией данные могут иметь прямые ссылки на 118 | * элементы исходной структуры aSource, если не использован флаг aFullAllocate в значении true. 119 | * Вся память выделяетсячерез статический nMemoryAllocator. 120 | * 121 | * @param aSource - исходные данные для упаковки. 122 | * @param aFullAllocate - флаг, указывающий, что нужно копировать всю информацию из упакованной 123 | * структуры, а не использовать ее по ссылке. TRUE = 1, FALSE = 0. 124 | */ 125 | csdata_data_t * csDataUnPack( csdata_data_t * aSource, int aFullAllocate ); 126 | 127 | 128 | /** 129 | * Очистка памяти статического аллокатора. После вызова этой функции аллокатор начинает 130 | * использовать ранее выделенную память для новых выделений, поэтому все ранее полученные данные 131 | * становятся не валидными. 132 | */ 133 | void csAllocatorReset(); 134 | /** 135 | * Фактическое освобождение памяти аллокатором. После вызова этой функции все ранее полученные 136 | * данные становятся не валидными. 137 | */ 138 | void csAllocatorFree(); 139 | 140 | 141 | /** 142 | * Настройка шага выделения памяти. Шаг выделения памяти статического аллокатора nMemoryAllocator 143 | * устанавливается в значение aNewMemoryStep. 144 | * 145 | * @param aNewMemoryStep - новое значение для шага выделения памяти. 146 | */ 147 | void csAllocatorSetMemoryStep( unsigned int aNewMemoryStep ); 148 | // Получение общего размера выделенной стаическим nMemoryAllocator'ом памяти. 149 | size_t csAllocatorAllocatedMemorySize(); 150 | 151 | #endif //__cplusplus 152 | 153 | #endif // __csDataPack_h__ 154 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( apcs ) 2 | 3 | cmake_minimum_required( VERSION 2.6 ) 4 | 5 | add_definitions( -DCSDATA_EXTENDED ) 6 | 7 | set( CMAKE_C_FLAGS "-fPIC" ) 8 | set( CMAKE_CXX_FLAGS "-fPIC" ) 9 | 10 | file( GLOB SOURCES *.h *.c ) 11 | 12 | add_library( ${PROJECT_NAME}obj OBJECT ${SOURCES} ) 13 | add_library( ${PROJECT_NAME} STATIC ${SOURCES} ) 14 | target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/.. ) 15 | target_link_libraries( ${PROJECT_NAME} m ) 16 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/ap-server.c: -------------------------------------------------------------------------------- 1 | /* -*- C -*- 2 | * File: ap-server.c 3 | * 4 | * Created: Sun Apr 13 16:21:03 2003 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "csdata.h" 31 | #include "readwrite.h" 32 | 33 | #if defined(_UNIXDEBUG) && defined(OS_LINUX) 34 | #include 35 | #endif /* _UNIXDEBUG */ 36 | 37 | #ifndef MASTER_STAT_TAKEN 38 | 39 | #define MASTER_STAT_TAKEN 0 40 | #define MASTER_STAT_AVAIL 1 41 | #define MASTER_FLOW_READ 3 42 | #define MASTER_FLOW_WRITE 4 43 | #define MASTER_STATUS_FD 5 44 | #define MASTER_LISTEN_FD 6 45 | #endif 46 | 47 | 48 | #define MAX_ACTIONS 1000 49 | #define MAX_ACT_PER_RULE 10 50 | #define MAX_HDR_PER_ACTION 10 51 | #define MAX_TO 10 52 | 53 | typedef struct _MASTER_STATUS 54 | { 55 | int pid; 56 | int avail; 57 | } MASTER_STATUS; 58 | 59 | /** Current Socket Id. For internal use only. */ 60 | static int gSocketFD = 0; 61 | 62 | 63 | int static_log_level = LOG_NOTICE; 64 | 65 | void cs_set_server_loglevel( int loglevel ) 66 | { 67 | 68 | static_log_level = loglevel; 69 | } 70 | 71 | void default_logger( int loglevel, char *fmt, ... ) 72 | { 73 | va_list ap; 74 | if( loglevel > static_log_level ) return; 75 | va_start( ap, fmt ); 76 | vsyslog( LOG_INFO, fmt, ap ); 77 | va_end( ap ); 78 | } 79 | 80 | cs_server_logger_t logger = (cs_server_logger_t)default_logger; 81 | 82 | void cs_set_server_logger( cs_server_logger_t n ) 83 | { 84 | logger = n; 85 | } 86 | 87 | void process_connection( int fd, cs_server_callback_t cb, unsigned int aTimeOut ) 88 | { 89 | int status = 11; 90 | csdata_data_t *input = csdata_recv_data( fd, &status, aTimeOut ); 91 | if( !input ) 92 | { 93 | if( logger ) 94 | ( *logger )( LOG_ERR, "Cannot receive data, Status: %d", status ); 95 | } 96 | else 97 | { 98 | csdata_data_t *out = ( *cb )( input ); 99 | if( out ) 100 | { 101 | csdata_send_data( fd, out, aTimeOut ); 102 | csdata_clear_data( out ); 103 | } 104 | csdata_clear_data( input ); 105 | } 106 | close( fd ); 107 | } 108 | 109 | 110 | int graceful_exit = 0; 111 | 112 | void sighup( int sig ) 113 | { 114 | graceful_exit++; 115 | } 116 | 117 | int cs_server_main( cs_server_callback_t cb, int max_requests, int alrm ) 118 | { 119 | fd_set rfd; 120 | struct timeval tv; 121 | int flags, sel, a_fd; 122 | struct sockaddr_un sun_accepted; 123 | socklen_t s_len; 124 | int req_count = 0; 125 | 126 | signal( SIGHUP, sighup ); 127 | 128 | flags = fcntl( MASTER_LISTEN_FD, F_GETFL, 0 ); 129 | if( fcntl( MASTER_LISTEN_FD, F_SETFL, flags | O_NONBLOCK ) == -1 ) 130 | { 131 | if( logger ) 132 | logger( LOG_ERR, "Cannot set O_NONBLOCK on MASTER_LISTEN_FD" ); 133 | } 134 | while( 1 ) 135 | { 136 | FD_ZERO( &rfd ); 137 | bzero( &tv, sizeof (tv ) ); 138 | tv.tv_sec = 1; 139 | FD_SET( MASTER_LISTEN_FD, &rfd ); 140 | sel = select( MASTER_LISTEN_FD + 1, &rfd, NULL, NULL, &tv ); 141 | if( sel < 0 && errno != EINTR ) 142 | { 143 | if( logger ) 144 | logger( LOG_ERR, "Select: %s", strerror( errno ) ); 145 | return -1; 146 | } 147 | else if( sel > 0 ) 148 | { 149 | if( FD_ISSET( MASTER_LISTEN_FD, &rfd ) ) 150 | { 151 | // trying to accept 152 | s_len = sizeof (sun_accepted ); 153 | a_fd = accept( MASTER_LISTEN_FD, (struct sockaddr*)&sun_accepted, &s_len ); 154 | if( a_fd < 0 ) 155 | { 156 | if( errno != EWOULDBLOCK && errno != ECONNABORTED && 157 | errno != EINTR 158 | #ifdef EPROTO 159 | && errno != EPROTO 160 | #endif 161 | ) 162 | { 163 | if( logger ) 164 | logger( LOG_ERR, "Accept: %s", strerror( errno ) ); 165 | } 166 | } 167 | else 168 | { 169 | MASTER_STATUS ms; 170 | memset( &ms, 0, sizeof (ms ) ); 171 | ms.pid = getpid( ); 172 | ms.avail = MASTER_STAT_TAKEN; 173 | if( nbwrite( MASTER_STATUS_FD, &ms, sizeof (ms ), alrm * 1000000 ) != sizeof (ms ) ) 174 | { 175 | if( logger ) 176 | logger( LOG_ERR, "Can\'t inform master, exiting" ); 177 | graceful_exit = 1; 178 | } 179 | // set blocking to socket 180 | #if 1 181 | flags = fcntl( a_fd, F_GETFL, 0 ); 182 | flags &= ~O_NONBLOCK; 183 | fcntl( a_fd, F_SETFL, flags ); 184 | #endif 185 | if( alrm ) 186 | alarm( alrm ); 187 | gSocketFD = a_fd; 188 | process_connection( a_fd, cb, alrm * 1000000 ); 189 | gSocketFD = 0; 190 | if( alrm ) 191 | alarm( 0 ); 192 | memset( &ms, 0, sizeof (ms ) ); 193 | ms.pid = getpid( ); 194 | ms.avail = MASTER_STAT_AVAIL; 195 | if( nbwrite( MASTER_STATUS_FD, &ms, sizeof (ms ), alrm * 1000 ) != sizeof (ms ) ) 196 | { 197 | if( logger ) 198 | logger( LOG_ERR, "Can\'t inform master, exiting" ); 199 | graceful_exit = 1; 200 | } 201 | } 202 | } 203 | } 204 | if( graceful_exit ) 205 | break; 206 | req_count++; 207 | if( max_requests && req_count >= max_requests ) 208 | break; 209 | } 210 | return 0; 211 | } 212 | 213 | void csAbnormalExit( csdata_data_t* aReturnData, int aReturnCode, unsigned int aTimeOut ) 214 | { 215 | // Посылка данных клиенту. 216 | if( gSocketFD && aReturnData ) 217 | csdata_send_data( gSocketFD, aReturnData, aTimeOut*1000000 ); 218 | 219 | // Очистка клиентских данных. 220 | // @todo Нужно продумать и сделать флаг, показывающий как была выделена память. 221 | /* 222 | if( aReturnData ) 223 | csdata_clear_data( aReturnData ); 224 | */ 225 | 226 | // Выход. 227 | _exit( aReturnCode ); 228 | } 229 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/csdata.c: -------------------------------------------------------------------------------- 1 | /* -*- C -*- 2 | * File: csdata.c 3 | * 4 | * Created: Sun Jul 6 20:12:28 2008 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "csdata.h" 17 | 18 | #include "readwrite.h" 19 | 20 | csdata_data_t* csdata_alloc_data( size_t attr_count ) 21 | { 22 | csdata_data_t* ret = calloc( sizeof (csdata_data_t ), 1 ); 23 | if( !ret ) 24 | return NULL; 25 | if( attr_count > 0 ) 26 | { 27 | if( !( ret->attr_list = calloc( sizeof (csdata_attr_t ), attr_count ) ) ) 28 | { 29 | free( ret ); 30 | return NULL; 31 | } 32 | ret->attr_count = attr_count; 33 | } 34 | return ret; 35 | } 36 | 37 | void csdata_clear_data( csdata_data_t *data ) 38 | { 39 | int i; 40 | if( !data ) return; 41 | if( data->body_ptr ) 42 | free( data->body_ptr ); 43 | if( data->attr_list && data->attr_count ) 44 | { 45 | for( i = 0; i < data->attr_count; i++ ) 46 | { 47 | // clear attribute name 48 | if( data->attr_list[i].attr_name 49 | && !( data->attr_list[i].attr_type & CSDATA_KEEP_ANAME ) ) 50 | free( data->attr_list[i].attr_name ); 51 | 52 | // and (string) value 53 | if( ( data->attr_list[i].attr_type & CSDATA_TYPEMASK ) == CSDATA_STRING 54 | && data->attr_list[i].attr_value.attr_string 55 | && !( data->attr_list[i].attr_type & CSDATA_KEEP_AVALUE ) 56 | ) 57 | free( data->attr_list[i].attr_value.attr_string ); 58 | } 59 | } 60 | if( data->attr_list ) 61 | free( data->attr_list ); 62 | free( data ); 63 | } 64 | 65 | static int send_int( int fd, uint32_t type, uint32_t value, unsigned int aTimeOut ) 66 | { 67 | uint32_t n_type = htonl( type ); 68 | uint32_t len = sizeof (value ); 69 | uint32_t n_len = htonl( len ); 70 | uint32_t n_value = htonl( value ); 71 | 72 | struct iovec iov[3]; 73 | iov[0].iov_base = &n_type; 74 | iov[0].iov_len = sizeof (uint32_t ); 75 | iov[1].iov_base = &n_len; 76 | iov[1].iov_len = sizeof (uint32_t ); 77 | iov[2].iov_base = &n_value; 78 | iov[2].iov_len = sizeof (uint32_t ); 79 | 80 | return nbwritev( fd, iov, 3, aTimeOut ); 81 | } 82 | 83 | static int send_string( int fd, uint32_t type, char *string, uint32_t string_len, unsigned int aTimeOut ) 84 | { 85 | uint32_t n_type = htonl( type ); 86 | uint32_t len = string_len ? string_len : strlen( string ); 87 | uint32_t n_len = htonl( len ); 88 | 89 | struct iovec iov[3]; 90 | iov[0].iov_base = &n_type; 91 | iov[0].iov_len = sizeof ( n_type ); 92 | iov[1].iov_base = &n_len; 93 | iov[1].iov_len = sizeof ( n_len ); 94 | iov[2].iov_base = string; 95 | iov[2].iov_len = len; 96 | 97 | return nbwritev( fd, iov, 3, aTimeOut ); 98 | } 99 | 100 | int csdata_send_data( int fd, csdata_data_t *data, unsigned int aTimeOut ) 101 | { 102 | uint32_t attrcount = 0, i; 103 | int ret; 104 | if( !data ) 105 | return EINVAL; 106 | 107 | /* 108 | // ���� ������ � ������� ������� 109 | /// type(4 �����), ����� (4 �����), ������ (���������� �����) 110 | // �������� ���������� � ���� ������� 111 | // CSDATA_ATTRNAME/�����/��� �������� + CSDATA_STRING|INT/�����/�������� �������� 112 | // ������ ���������� ��� ������������ ����, ���� ���� �� ������ � ������ ����� 113 | 114 | // �������� magic 115 | */ 116 | if( ( ret = send_int( fd, CSDATA_MARKER_TYPE, CSDATA_MAGIC, aTimeOut ) ) < 0 ) 117 | return ret; 118 | 119 | // ������� ���������� ��������� � ��������� ������, �������� ���������� ��������� 120 | for( i = 0; i < data->attr_count; i++ ) 121 | { 122 | if( data->attr_list[i].attr_name && data->attr_list[i].attr_type ) 123 | { 124 | attrcount++; 125 | } 126 | } 127 | if( ( ret = send_int( fd, CSDATA_ATTRCOUNT, attrcount, aTimeOut ) ) < 0 ) 128 | return ret; 129 | // �������� �������� 130 | if( attrcount > 0 ) 131 | { 132 | for( i = 0; i < data->attr_count; i++ ) 133 | { 134 | if( data->attr_list[i].attr_name && data->attr_list[i].attr_type ) 135 | { 136 | #ifdef CSDATA_EXTENDED 137 | if( ( ret = send_string( fd, CSDATA_ATTRNAME, data->attr_list[i].attr_name, data->attr_list[i].attr_name_size, aTimeOut ) ) < 0 ) 138 | return ret; 139 | #else 140 | if( ( ret = send_string( fd, CSDATA_ATTRNAME, data->attr_list[i].attr_name, 0, aTimeOut ) ) < 0 ) 141 | return ret; 142 | #endif //CSDATA_EXTENDED 143 | 144 | if( ( data->attr_list[i].attr_type & CSDATA_TYPEMASK ) == CSDATA_STRING ) 145 | { 146 | #ifdef CSDATA_EXTENDED 147 | if( ( ret = send_string( fd, CSDATA_STRING, data->attr_list[i].attr_value.attr_string, data->attr_list[i].attr_value_size, aTimeOut ) ) < 0 ) 148 | return ret; 149 | #else 150 | if( ( ret = send_string( fd, CSDATA_STRING, data->attr_list[i].attr_value.attr_string, 0, aTimeOut ) ) < 0 ) 151 | return ret; 152 | #endif //CSDATA_EXTENDED 153 | } 154 | else 155 | { 156 | if( ( ret = send_int( fd, data->attr_list[i].attr_type & CSDATA_TYPEMASK, data->attr_list[i].attr_value.attr_int, aTimeOut ) ) < 0 ) 157 | return ret; 158 | } 159 | } 160 | } 161 | } 162 | 163 | // �������� body 164 | if( data->body_ptr ) 165 | { 166 | if( ( ret = send_string( fd, CSDATA_BODY, data->body_ptr, data->body_size, aTimeOut ) ) < 0 ) 167 | return ret; 168 | } 169 | else 170 | { 171 | // �������� ������ ������� body 172 | if( ( ret = send_int( fd, CSDATA_EMPTYBODY, 0, aTimeOut ) ) < 0 ) 173 | return ret; 174 | } 175 | // �������� EOF 176 | if( ( ret = send_int( fd, CSDATA_MARKER_TYPE, CSDATA_EOF, aTimeOut ) ) < 0 ) 177 | return ret; 178 | return 0; 179 | } 180 | 181 | static int recv_int( int fd, uint32_t *type, uint32_t *value, unsigned int aTimeOut ) 182 | { 183 | uint32_t n_type, n_len, n_value; 184 | 185 | // Получение типа и размера пакета. 186 | struct iovec iov[2]; 187 | iov[0].iov_base = &n_type; 188 | iov[0].iov_len = sizeof ( uint32_t ); 189 | iov[1].iov_base = &n_len; 190 | iov[1].iov_len = sizeof ( uint32_t ); 191 | 192 | int RetCode = nbreadv( fd, iov, 2, aTimeOut ); 193 | if( RetCode < 0 ) 194 | return RetCode; 195 | else if( RetCode != 2 * sizeof ( uint32_t ) ) 196 | { 197 | errno = EINVAL; 198 | return -1; 199 | } 200 | 201 | // @info Нужна ли проверка типа? 202 | *type = ntohl( n_type ); 203 | // Проверка размера пакета. 204 | if( ntohl( n_len ) != sizeof ( uint32_t ) ) 205 | { 206 | errno = EINVAL; 207 | return -1; 208 | } 209 | 210 | // Получение значения. 211 | RetCode = nbread( fd, &n_value, sizeof ( uint32_t ), aTimeOut ); 212 | if( RetCode < 0 ) 213 | return RetCode; 214 | else if( RetCode != sizeof ( uint32_t ) ) 215 | { 216 | errno = EINVAL; 217 | return -1; 218 | } 219 | 220 | *value = ntohl( n_value ); 221 | 222 | return 0; 223 | } 224 | 225 | static int csdata_recv_attr( int fd, csdata_attr_t *attr, unsigned int aTimeOut ) 226 | { 227 | uint32_t n_type, n_len, type, len, n_val; 228 | 229 | // Получение типа и размера пакета. 230 | struct iovec iov[2]; 231 | iov[0].iov_base = &n_type; 232 | iov[0].iov_len = sizeof ( uint32_t ); 233 | iov[1].iov_base = &n_len; 234 | iov[1].iov_len = sizeof ( uint32_t ); 235 | 236 | int RetCode = nbreadv( fd, iov, 2, aTimeOut ); 237 | if( RetCode < 0 ) 238 | return RetCode; 239 | else if( RetCode != 2 * sizeof ( uint32_t ) ) 240 | { 241 | errno = EINVAL; 242 | return -1; 243 | } 244 | 245 | // Проверка типа пакета. 246 | type = ntohl( n_type ) & CSDATA_TYPEMASK; 247 | if( type != CSDATA_ATTRNAME ) 248 | { 249 | errno = EINVAL; 250 | return -1; 251 | } 252 | 253 | // Выделение памяти для получении имени атрибута. 254 | len = ntohl( n_len ); 255 | if( !( attr->attr_name = malloc( len + 1 ) ) ) 256 | { 257 | errno = EINVAL; 258 | return -1; 259 | } 260 | 261 | // Получение имени атрибута. 262 | RetCode = nbread( fd, attr->attr_name, len, aTimeOut ); 263 | if( RetCode < 0 ) 264 | return RetCode; 265 | else if( RetCode != len ) 266 | { 267 | errno = EINVAL; 268 | return -1; 269 | } 270 | 271 | attr->attr_name[len] = '\0'; 272 | #ifdef CSDATA_EXTENDED 273 | attr->attr_name_size = len; 274 | #endif 275 | 276 | 277 | // Получение типа и размера пакета. 278 | iov[0].iov_base = &n_type; 279 | iov[0].iov_len = sizeof ( uint32_t ); 280 | iov[1].iov_base = &n_len; 281 | iov[1].iov_len = sizeof ( uint32_t ); 282 | 283 | RetCode = nbreadv( fd, iov, 2, aTimeOut ); 284 | if( RetCode < 0 ) 285 | return RetCode; 286 | else if( RetCode != 2 * sizeof ( uint32_t ) ) 287 | { 288 | errno = EINVAL; 289 | return -1; 290 | } 291 | 292 | // Получение типа пакета. 293 | type = ntohl( n_type ) & CSDATA_TYPEMASK; 294 | // Получение размера значения пакета. 295 | len = ntohl( n_len ); 296 | 297 | if( type == CSDATA_INT ) 298 | { 299 | // Значение аргумента - число. 300 | if( len != sizeof ( uint32_t ) ) 301 | { 302 | errno = EINVAL; 303 | return -1; 304 | } 305 | 306 | // Получение значения атрибута. 307 | RetCode = nbread( fd, &n_val, sizeof ( uint32_t ), aTimeOut ); 308 | if( RetCode < 0 ) 309 | return RetCode; 310 | else if( RetCode != sizeof ( uint32_t ) ) 311 | { 312 | errno = EINVAL; 313 | return -1; 314 | } 315 | 316 | attr->attr_value.attr_int = ntohl( n_val ); 317 | attr->attr_type = type; 318 | } 319 | else if( type == CSDATA_STRING ) 320 | { 321 | // Значение атрибута - строка. 322 | 323 | // Выделение памяти под значение. 324 | if( !( attr->attr_value.attr_string = malloc( len + 1 ) ) ) 325 | { 326 | errno = ENOMEM; 327 | return -1; 328 | } 329 | 330 | // Получение значения атрибута. 331 | RetCode = nbread( fd, attr->attr_value.attr_string, len, aTimeOut ); 332 | if( RetCode < 0 ) 333 | return RetCode; 334 | else if( RetCode != len ) 335 | { 336 | errno = EINVAL; 337 | return -1; 338 | } 339 | attr->attr_value.attr_string[len] = '\0'; 340 | #ifdef CSDATA_EXTENDED 341 | attr->attr_value_size = len; 342 | #endif 343 | attr->attr_type = type; 344 | } 345 | else 346 | { 347 | // Неизвестный тип. 348 | errno = EINVAL; 349 | return -1; 350 | } 351 | 352 | // Атрибут успешно считан. 353 | return 0; 354 | } 355 | 356 | static int csdata_recv_body( int fd, csdata_data_t *data, unsigned int aTimeOut ) 357 | { 358 | uint32_t n_type, n_len, type, len; 359 | 360 | struct iovec iov[2]; 361 | 362 | // Получение типа и размера пакета. 363 | iov[0].iov_base = &n_type; 364 | iov[0].iov_len = sizeof ( uint32_t ); 365 | iov[1].iov_base = &n_len; 366 | iov[1].iov_len = sizeof ( uint32_t ); 367 | 368 | int RetCode = nbreadv( fd, iov, 2, aTimeOut ); 369 | if( RetCode < 0 ) 370 | return RetCode; 371 | else if( RetCode != 2 * sizeof ( uint32_t ) ) 372 | { 373 | errno = EINVAL; 374 | return -1; 375 | } 376 | 377 | // Получение типа пакета. 378 | type = ntohl( n_type ) & CSDATA_TYPEMASK; 379 | // Получение размера пакета. 380 | len = ntohl( n_len ); 381 | 382 | if( type == CSDATA_BODY ) 383 | { 384 | // Пакет с непустым телом. 385 | if( !( data->body_ptr = malloc( len + 1 ) ) ) 386 | { 387 | errno = ENOMEM; 388 | return -5; 389 | } 390 | 391 | // Получение тела. 392 | RetCode = nbread( fd, data->body_ptr, len, aTimeOut ); 393 | if( RetCode < 0 ) 394 | return RetCode; 395 | else if( RetCode != len ) 396 | { 397 | errno = EINVAL; 398 | return -1; 399 | } 400 | 401 | data->body_ptr[len] = '\0'; 402 | data->body_size = len; 403 | } 404 | else if( type == CSDATA_EMPTYBODY ) 405 | { 406 | // Пакет с пустым телом. 407 | if( len != sizeof ( uint32_t ) ) 408 | { 409 | errno = EINVAL; 410 | return -1; 411 | } 412 | 413 | uint32_t ph; 414 | 415 | data->body_ptr = NULL; 416 | data->body_size = 0; 417 | 418 | // Получение пакета. 419 | RetCode = nbread( fd, &ph, sizeof ( uint32_t ), aTimeOut ); 420 | if( RetCode < 0 ) 421 | return RetCode; 422 | else if( RetCode != sizeof ( uint32_t ) ) 423 | { 424 | errno = EINVAL; 425 | return -1; 426 | } 427 | } 428 | else 429 | { 430 | errno = EINVAL; 431 | return -1; 432 | } 433 | 434 | // Тело успешно считано. 435 | return 0; 436 | } 437 | 438 | csdata_data_t * csdata_recv_data( int fd, int *status, unsigned int aTimeOut ) 439 | { 440 | uint32_t ival, itype, attrcount, i; 441 | csdata_data_t *ret; 442 | 443 | // Получение magic 444 | int RetCode = recv_int( fd, &itype, &ival, aTimeOut ); 445 | if( RetCode < 0 ) 446 | { 447 | if( status ) 448 | *status = errno; 449 | 450 | return NULL; 451 | } 452 | 453 | if( ival != CSDATA_MAGIC ) 454 | { 455 | if( status ) 456 | *status = errno; 457 | 458 | return NULL; 459 | } 460 | 461 | RetCode = recv_int( fd, &itype, &attrcount, aTimeOut ); 462 | if( RetCode != 0 ) 463 | { 464 | if( status ) 465 | *status = errno; 466 | 467 | return NULL; 468 | } 469 | 470 | if( itype != CSDATA_ATTRCOUNT ) 471 | { 472 | if( status ) 473 | *status = errno; 474 | return NULL; 475 | } 476 | 477 | if( !( ret = csdata_alloc_data( attrcount ) ) ) 478 | { 479 | if( status ) 480 | *status = ENOMEM; 481 | 482 | return NULL; 483 | } 484 | for( i = 0; i < attrcount; i++ ) 485 | { 486 | if( ( RetCode = csdata_recv_attr( fd, &ret->attr_list[i], aTimeOut ) ) < 0 ) 487 | { 488 | csdata_clear_data( ret ); 489 | 490 | if( status ) 491 | *status = errno; 492 | 493 | return NULL; 494 | } 495 | } 496 | if( ( RetCode = csdata_recv_body( fd, ret, aTimeOut ) ) < 0 ) 497 | { 498 | csdata_clear_data( ret ); 499 | 500 | if( status ) 501 | *status = errno; 502 | 503 | return NULL; 504 | } 505 | if( ( RetCode = recv_int( fd, &itype, &ival, aTimeOut ) ) < 0 ) 506 | { 507 | if( status ) 508 | *status = errno; 509 | 510 | return NULL; 511 | } 512 | if( ival != CSDATA_EOF ) 513 | { 514 | if( status ) 515 | *status = EINVAL; 516 | 517 | return NULL; 518 | } 519 | 520 | if( status ) 521 | *status = 0; 522 | 523 | return ret; 524 | } 525 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/csdata.h: -------------------------------------------------------------------------------- 1 | /* -*- C -*- 2 | * File: csdata.h 3 | * 4 | * Created: Sun Jul 6 12:04:42 2008 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #ifndef __CSDATA_H 11 | #define __CSDATA_H 12 | 13 | typedef enum 14 | { 15 | CSDATA_MARKER_TYPE = 0x00000001U, 16 | CSDATA_MAGIC = 0x00173414U, 17 | CSDATA_EOF = 0x22221111U, 18 | 19 | CSDATA_ATTRCOUNT = 0x00000002U, 20 | 21 | CSDATA_ATTRNAME = 0x00000004U, 22 | 23 | CSDATA_STRING = 0x00000008U, 24 | CSDATA_INT = 0x00000010U, 25 | CSDATA_BODY = 0x00001000U, 26 | CSDATA_EMPTYBODY = 0x00001001U, 27 | CSDATA_TYPEMASK = 0x0000ffffU, 28 | CSDATA_KEEP_ANAME = 0x10000000U, 29 | CSDATA_KEEP_AVALUE = 0x20000000U 30 | } CSDATA_DATA_TYPES; 31 | 32 | typedef struct 33 | { 34 | CSDATA_DATA_TYPES attr_type; 35 | 36 | char* attr_name; 37 | #ifdef CSDATA_EXTENDED 38 | unsigned int attr_name_size; 39 | #endif //CSDATA_EXTENDED 40 | 41 | union 42 | { 43 | int attr_int; 44 | char* attr_string; 45 | } attr_value; 46 | #ifdef CSDATA_EXTENDED 47 | unsigned int attr_value_size; 48 | #endif //CSDATA_EXTENDED 49 | } csdata_attr_t; 50 | 51 | typedef struct 52 | { 53 | uint32_t attr_count; 54 | csdata_attr_t* attr_list; 55 | uint32_t body_size; 56 | char* body_ptr; 57 | } csdata_data_t; 58 | 59 | csdata_data_t* csdata_alloc_data( size_t attr_count ); 60 | void csdata_clear_data( csdata_data_t *data ); 61 | int csdata_send_data( int fd, csdata_data_t *data, unsigned int aTimeOut ); 62 | csdata_data_t* csdata_recv_data( int fd, int* status, unsigned int aTimeOut ); 63 | 64 | typedef csdata_data_t *(*cs_server_callback_t)(csdata_data_t *); 65 | typedef void (*cs_server_logger_t)(int loglevel, const char * fmt, ...); 66 | 67 | // Server library functions 68 | int cs_server_main( cs_server_callback_t, int max_requests, int alarm ); 69 | void cs_set_server_logger( cs_server_logger_t ); 70 | void cs_set_server_loglevel( int loglevel ); 71 | 72 | // Client functions 73 | 74 | /** 75 | * Выполнение запроса к серверу. 76 | * @param aConnectionString - строка, определяющая соединение с сервером. 77 | * @param aTimeOut - таймаут в милисекундах. 78 | * @param aRequest - запрос к серверу. 79 | * @param aStatus - статус запроса. 80 | */ 81 | csdata_data_t * csdata_rpc_call( const char * aConnectionString, long aTimeOut, csdata_data_t* aRequest, int* aStatus ); 82 | 83 | /** 84 | * Фунция для принудительного выхода из серверного процесса с предварительной посылкой ответа клиенту. 85 | * @param aReturnData - возвращаемые данные. 86 | * @param aReturnCode - код выхода для серверного процесса. 87 | * @param aTimeOut - таймаут на операцию посылки данных клиенту. 88 | */ 89 | void csAbnormalExit( csdata_data_t* aReturnData, int aReturnCode, unsigned int aTimeOut ); 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/libclient.c: -------------------------------------------------------------------------------- 1 | /* -*- C -*- 2 | * File: libclient.c 3 | * 4 | * Created: Sun Jul 6 12:04:30 2008 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "csdata.h" 29 | 30 | #ifdef NO_INET_ATON 31 | 32 | int 33 | inet_aton( cp, addr ) 34 | register const char *cp; 35 | struct in_addr *addr; 36 | { 37 | u_long parts[4]; 38 | in_addr_t val; 39 | char *c; 40 | char *endptr; 41 | int gotend, n; 42 | 43 | c = (char *)cp; 44 | n = 0; 45 | /* 46 | * Run through the string, grabbing numbers until 47 | * the end of the string, or some error 48 | */ 49 | gotend = 0; 50 | while( !gotend ) 51 | { 52 | errno = 0; 53 | val = strtoul( c, &endptr, 0 ); 54 | 55 | if( errno == ERANGE ) /* Fail completely if it overflowed. */ 56 | return (0 ); 57 | 58 | /* 59 | * If the whole string is invalid, endptr will equal 60 | * c.. this way we can make sure someone hasn't 61 | * gone '.12' or something which would get past 62 | * the next check. 63 | */ 64 | if( endptr == c ) 65 | return (0 ); 66 | parts[n] = val; 67 | c = endptr; 68 | 69 | /* Check the next character past the previous number's end */ 70 | switch( *c ) 71 | { 72 | case '.': 73 | /* Make sure we only do 3 dots .. */ 74 | if( n == 3 ) /* Whoops. Quit. */ 75 | return (0 ); 76 | n++; 77 | c++; 78 | break; 79 | 80 | case '\0': 81 | gotend = 1; 82 | break; 83 | 84 | default: 85 | if( isspace( (unsigned char)*c ) ) 86 | { 87 | gotend = 1; 88 | break; 89 | } 90 | else 91 | return (0 ); /* Invalid character, so fail */ 92 | } 93 | 94 | } 95 | 96 | /* 97 | * Concoct the address according to 98 | * the number of parts specified. 99 | */ 100 | 101 | switch( n ) 102 | { 103 | case 0: /* a -- 32 bits */ 104 | /* 105 | * Nothing is necessary here. Overflow checking was 106 | * already done in strtoul(). 107 | */ 108 | break; 109 | case 1: /* a.b -- 8.24 bits */ 110 | if( val > 0xffffff || parts[0] > 0xff ) 111 | return (0 ); 112 | val |= parts[0] << 24; 113 | break; 114 | 115 | case 2: /* a.b.c -- 8.8.16 bits */ 116 | if( val > 0xffff || parts[0] > 0xff || parts[1] > 0xff ) 117 | return (0 ); 118 | val |= ( parts[0] << 24 ) | ( parts[1] << 16 ); 119 | break; 120 | 121 | case 3: /* a.b.c.d -- 8.8.8.8 bits */ 122 | if( val > 0xff || parts[0] > 0xff || parts[1] > 0xff || 123 | parts[2] > 0xff ) 124 | return (0 ); 125 | val |= ( parts[0] << 24 ) | ( parts[1] << 16 ) | ( parts[2] << 8 ); 126 | break; 127 | } 128 | 129 | if( addr != NULL ) 130 | addr->s_addr = htonl( val ); 131 | return (1 ); 132 | } 133 | #endif 134 | 135 | /* translating given name to sockaddr_in structure */ 136 | 137 | /* on errors sin_port will be -1 */ 138 | static int normalize_inet_name( const char *xname, struct sockaddr_in *addr ) 139 | { 140 | 141 | struct hostent *h; 142 | struct servent *serv; 143 | char *host, *port, *first, *second, *name = NULL; 144 | int ret = 0; 145 | 146 | if( !( name = strdup( xname ) ) ) 147 | return ENOMEM; 148 | 149 | if( !( first = strchr( name, ':' ) ) || !( second = strrchr( name, ':' ) ) || !( first == second ) ) 150 | { 151 | ret = EINVAL; 152 | goto exit; 153 | } 154 | 155 | *first = '\0'; 156 | host = (char *)name; 157 | port = first + 1; 158 | 159 | addr->sin_family = AF_INET; 160 | 161 | /* check for numeric addresses by normal way. now possible bugs */ 162 | if( *host >= '0' && *host <= '9' ) 163 | addr->sin_addr.s_addr = inet_addr( host ); 164 | else 165 | { 166 | h = gethostbyname( host ); 167 | if( !h ) 168 | { 169 | ret = ENOENT; 170 | goto exit; 171 | } 172 | addr->sin_addr = *( (struct in_addr *)h->h_addr ); 173 | } 174 | 175 | if( *port >= '0' && *port <= '9' ) 176 | addr->sin_port = htons( atoi( port ) ); 177 | else 178 | { 179 | serv = getservbyname( port, (char*)0 ); 180 | if( serv ) 181 | addr->sin_port = serv->s_port; 182 | else 183 | { 184 | ret = ENOENT; 185 | goto exit; 186 | } 187 | } 188 | exit: 189 | free( name ); 190 | return ret; 191 | } 192 | 193 | int wait_for_fd( int fd, long timeout_ms ) 194 | { 195 | fd_set rfd; 196 | struct timeval tv; 197 | int state; 198 | 199 | FD_ZERO( &rfd ); 200 | FD_SET( fd, &rfd ); 201 | bzero( &tv, sizeof (tv ) ); 202 | tv.tv_sec = timeout_ms / 1000; 203 | tv.tv_usec = ( timeout_ms % 1000 )*1000; 204 | 205 | state = select( fd + 1, &rfd, NULL, NULL, &tv ); 206 | if( state > 0 && FD_ISSET( fd, &rfd ) ) 207 | { 208 | return fd; 209 | } 210 | else if( state == 0 ) 211 | { 212 | return ETIMEDOUT; 213 | } 214 | else 215 | { 216 | return ECONNREFUSED; 217 | } 218 | } 219 | 220 | /* connecting to TCP socket */ 221 | static int inet_connect( const struct sockaddr_in *addr, long timeout_ms ) 222 | { 223 | int retval; 224 | int flags; 225 | int state; 226 | int t = 1; 227 | struct linger l; 228 | int fd; 229 | 230 | if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) 231 | { 232 | // s->logp(s, LOG_ERR, "Cannot allocate socket: %s",strerror(errno)); 233 | return ECONNREFUSED; 234 | } 235 | 236 | if( -1 == ( flags = fcntl( fd, F_GETFL, 0 ) ) ) 237 | { 238 | close( fd ); 239 | // s->logp(s, LOG_ERR, "Cannot get flags for socket %d: %s", 240 | // s->filter_fd,strerror(errno)); 241 | return ECONNREFUSED; 242 | } 243 | #if 0 244 | if( -1 == fcntl( fd, F_SETFL, flags | O_NONBLOCK ) ) 245 | { 246 | close( fd ); 247 | // s->logp(s, LOG_ERR, "Cannot set NONBLOCK on socket %d: %s", 248 | // s->filter_fd,strerror(errno)); 249 | return ECONNREFUSED; 250 | } 251 | #endif 252 | 253 | l.l_onoff = 1; 254 | l.l_linger = 0; 255 | if( -1 == setsockopt( fd, SOL_SOCKET, SO_LINGER, &l, sizeof (l ) ) ) 256 | { 257 | close( fd ); 258 | // s->logp(s, LOG_ERR, "Cannot set lingering close on socket %d: %s", 259 | // s->filter_fd,strerror(errno)); 260 | return ECONNREFUSED; 261 | } 262 | if( -1 == setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &t, sizeof (t ) ) ) 263 | { 264 | // s->logp(s,LOG_ERR,"Could not set TCP_NODELAY on socket: %s",strerror(errno)); 265 | close( fd ); 266 | return ECONNREFUSED; 267 | } 268 | 269 | if( ( state = connect( fd, (struct sockaddr *)addr, sizeof (*addr ) ) ) < 0 ) 270 | { 271 | if( errno != EINPROGRESS ) 272 | { 273 | // s->logp(s, LOG_ERR, "Failed to connect: %s",strerror(errno)); 274 | close( fd ); 275 | return state; 276 | } 277 | else 278 | { 279 | retval = wait_for_fd( fd, timeout_ms ); 280 | if( retval < 0 && fd > 0 ) 281 | { 282 | close( fd ); 283 | } 284 | return retval; 285 | } 286 | } 287 | else 288 | { 289 | // s->logp(s, LOG_DEBUG+1, "Connected immediately, fd=%d",s->filter_fd); 290 | return fd; 291 | } 292 | } 293 | 294 | /* connecting to unix socket */ 295 | static int unix_connect( const char *sockname, long timeout_ms ) 296 | { 297 | 298 | int flags; 299 | int state; 300 | struct sockaddr_un port; 301 | int fd = 0; 302 | 303 | port.sun_family = AF_LOCAL; 304 | strncpy( port.sun_path, sockname, sizeof (port.sun_path ) - 1 ); 305 | if( ( fd = socket( AF_LOCAL, SOCK_STREAM, 0 ) ) < 0 ) 306 | { 307 | return ECONNREFUSED; 308 | } 309 | 310 | if( -1 == ( flags = fcntl( fd, F_GETFL, 0 ) ) ) 311 | { 312 | close( fd ); 313 | return ECONNREFUSED; 314 | } 315 | if( ( state = connect( fd, (struct sockaddr *)&port, sizeof port ) ) < 0 ) 316 | { 317 | if( errno != EINPROGRESS ) 318 | { 319 | return ECONNREFUSED; 320 | } 321 | else 322 | { 323 | return wait_for_fd( fd, timeout_ms ); 324 | } 325 | } 326 | else 327 | { 328 | return fd; 329 | } 330 | } 331 | 332 | int cs_connect( const char *addr, long timeout_ms ) 333 | { 334 | 335 | if( !strncmp( addr, "unix:", 5 ) ) 336 | return unix_connect( addr + 5, timeout_ms ); 337 | else if( !strncmp( addr, "tcp:", 4 ) ) 338 | { 339 | int status; 340 | struct sockaddr_in ia; 341 | if( ( status = normalize_inet_name( addr + 4, &ia ) ) < 0 ) 342 | { 343 | return status; 344 | } 345 | return inet_connect( &ia, timeout_ms ); 346 | } 347 | else 348 | { 349 | errno = EINVAL; 350 | return -1; 351 | } 352 | } 353 | 354 | csdata_data_t * csdata_rpc_call( const char *addr, long timeout_ms, csdata_data_t *input, int* status ) 355 | { 356 | int fd = cs_connect( addr, timeout_ms ); 357 | int rc; 358 | csdata_data_t *ret = NULL; 359 | if( fd < 0 ) 360 | { 361 | if( status ) 362 | *status = errno; 363 | return NULL; 364 | } 365 | if( ( rc = csdata_send_data( fd, input, timeout_ms * 1000 ) ) < 0 ) 366 | { 367 | close( fd ); 368 | if( status ) 369 | *status = errno; 370 | return NULL; 371 | } 372 | ret = csdata_recv_data( fd, status, timeout_ms * 1000 ); 373 | close( fd ); 374 | return ret; 375 | } 376 | 377 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/readwrite.c: -------------------------------------------------------------------------------- 1 | #include "readwrite.h" 2 | 3 | /** 4 | * @todo Нужно поддержать полноценный таймаут на общее время выполнения всех функций. 5 | * @todo Нужно, чтобы параметр aTimeOut уменьшался на время выполнения функции. 6 | */ 7 | 8 | ssize_t nbread( int aFileDescriptor, void *aBuffer, size_t aTargetSize, unsigned int aTimeOut ) 9 | { 10 | fd_set rfds; 11 | 12 | // Устанавливаем таймаут. 13 | struct timeval timeout; 14 | timeout.tv_sec = floor( (double)aTimeOut / 1000000 ); 15 | timeout.tv_usec = aTimeOut % 1000000; 16 | 17 | // Считываем данные. 18 | size_t size = 0; 19 | while( size < aTargetSize ) 20 | { 21 | FD_ZERO( &rfds ); 22 | FD_SET( aFileDescriptor, &rfds ); 23 | 24 | // Вызываем селект чтобы проверить статус сокета. 25 | int sel_status = select( aFileDescriptor + 1, &rfds, NULL, NULL, &timeout ); 26 | if( sel_status < 0 ) 27 | { 28 | if( errno != EINTR ) 29 | // Ошибка. 30 | return -1; 31 | else 32 | continue; 33 | } 34 | else if( sel_status == 0 ) 35 | { 36 | // Сработал таймаут. 37 | errno = 0; 38 | return -1; 39 | } 40 | else if( !FD_ISSET( aFileDescriptor, &rfds ) ) 41 | continue; 42 | 43 | // Читаем данные из сокета. 44 | ssize_t res = read( aFileDescriptor, (char*)aBuffer + size, aTargetSize - size ); 45 | if( res < 0 ) 46 | { 47 | if( errno != EINTR && errno != EAGAIN ) 48 | // Ошибка. 49 | return -1; 50 | else 51 | continue; 52 | } 53 | else if( res == 0 ) 54 | return size; 55 | else 56 | size += res; 57 | } 58 | 59 | return size; 60 | } 61 | 62 | ssize_t nbreadv( int aFileDescriptor, const struct iovec *iov, int iovcnt, unsigned int aTimeOut ) 63 | { 64 | ssize_t size = 0; 65 | 66 | // Считываем данные. 67 | int i; 68 | for( i = 0; i < iovcnt; i++ ) 69 | { 70 | // Считываем i-ый буффер. 71 | ssize_t res = nbread( aFileDescriptor, iov[i].iov_base, iov[i].iov_len, aTimeOut ); 72 | if( res < 0 ) 73 | return res; 74 | else 75 | size += res; 76 | } 77 | 78 | return size; 79 | }; 80 | 81 | ssize_t nbwrite( int aFileDescriptor, const void *aBuffer, size_t aTargetSize, unsigned int aTimeOut ) 82 | { 83 | fd_set rfds; 84 | 85 | // Устанавливем таймаут. 86 | struct timeval TimeOut; 87 | 88 | TimeOut.tv_sec = floor( (double)aTimeOut / 1000000 ); 89 | TimeOut.tv_usec = aTimeOut % 1000000; 90 | 91 | // Записываем данные. 92 | size_t size = 0; 93 | while( size < aTargetSize ) 94 | { 95 | FD_ZERO( &rfds ); 96 | FD_SET( aFileDescriptor, &rfds ); 97 | 98 | struct timeval LocalTimeOut = TimeOut; 99 | 100 | // Вызываем селект чтобы проверить статус сокета. 101 | int sel_status = select( aFileDescriptor + 1, NULL, &rfds, NULL, &LocalTimeOut ); 102 | if( sel_status < 0 ) 103 | { 104 | // Ошибка. 105 | if( errno != EINTR ) 106 | return -1; 107 | else 108 | continue; 109 | } 110 | else if( sel_status == 0 ) 111 | { 112 | // Сработал таймаут. 113 | errno = 0; 114 | return -1; 115 | } 116 | else if( !FD_ISSET( aFileDescriptor, &rfds ) ) 117 | continue; 118 | 119 | // Пишем данные в сокет. 120 | ssize_t res = write( aFileDescriptor, (const char *)aBuffer + size, aTargetSize - size ); 121 | if( res < 0 ) 122 | { 123 | if( errno != EINTR && errno != EAGAIN ) 124 | // Ошибка. 125 | return -1; 126 | else 127 | continue; 128 | } 129 | else if( res == 0 ) 130 | return size; 131 | else 132 | size += res; 133 | } 134 | 135 | return size; 136 | } 137 | 138 | ssize_t nbwritev( int aFileDescriptor, const struct iovec *iov, int iovcnt, unsigned int aTimeOut ) 139 | { 140 | ssize_t size = 0; 141 | 142 | // Запись данных. 143 | int i; 144 | for( i = 0; i < iovcnt; i++ ) 145 | { 146 | ssize_t res = nbwrite( aFileDescriptor, iov[i].iov_base, iov[i].iov_len, aTimeOut ); 147 | if( res < 0 ) 148 | return res; 149 | else 150 | size += res; 151 | } 152 | 153 | return size; 154 | }; 155 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/apcs/readwrite.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file readwrite.h 3 | * @author Fedor Zorky 4 | * 5 | * @brief Функции считывания и записи данных через сокет с обработкой прерываний и таймаута. 6 | */ 7 | 8 | #ifndef __ReadWrite_h__ 9 | #define __ReadWrite_h__ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | 22 | /** 23 | * Считывание из сокета указанного количества байт в буффер. 24 | * @param aFileDescriptor - дескриптор файла. 25 | * @param aBuffer - буфер, куда считывать данные. 26 | * @param aTargetSize - количество байт, которые надо считать. 27 | * @param aTimeOut - таймаут в микросекундах. Микросекунда = 10^{-6} секунды. 28 | * 29 | * @retval - Количество полученных байт; в случае ошибки устанавливает значение errno и возвращает -1; в случае 30 | * прерывания по таймауту errno устанавливается в 0. 31 | */ 32 | ssize_t nbread( int aFileDescriptor, void *aBuffer, size_t aTargetSize, unsigned int aTimeOut ); 33 | 34 | 35 | /** 36 | * Считывание из сокета указанного количества байт в набор буфферов. 37 | * @param aFileDescriptor - дескриптор файла. 38 | * @param iov - буфера, куда считывать данные. 39 | * @param iovcnt - количество буфферов. 40 | * @param aTimeOut - таймаут в микросекундах. Микросекунда = 10^{-6} секунды. 41 | * 42 | * @retval - Количество полученных байт; в случае ошибки устанавливает значение errno и возвращает -1; в случае 43 | * прерывания по таймауту errno устанавливается в 0. 44 | */ 45 | ssize_t nbreadv( int aFileDescriptor, const struct iovec *iov, int iovcnt, unsigned int aTimeOut ); 46 | 47 | 48 | /** 49 | * Запись в сокет указанного количества байт из буффера. 50 | * @param aFileDescriptor - дескриптор файла. 51 | * @param aBuffer - буфер, откуда брать данные. 52 | * @param aTargetSize - количество байт, которые надо записать. 53 | * @param aTimeOut - таймаут в микросекундах. Микросекунда = 10^{-6} секунды. 54 | * 55 | * @retval - Количество полученных байт; в случае ошибки устанавливает значение errno и возвращает -1; в случае 56 | * прерывания по таймауту errno устанавливается в 0. 57 | */ 58 | ssize_t nbwrite( int aFileDescriptor, const void *aBuffer, size_t aTargetSize, unsigned int aTimeOut ); 59 | 60 | 61 | /** 62 | * Запись в сокет указанного количества байт из набора буфферов. 63 | * @param aFileDescriptor - дескриптор файла. 64 | * @param iov - буфера, откуда брать данные. 65 | * @param iovcnt - количество буфферов. 66 | * @param aTimeOut - таймаут в микросекундах. Микросекунда = 10^{-6} секунды. 67 | * 68 | * @retval - Количество полученных байт; в случае ошибки устанавливает значение errno и возвращает -1; в случае 69 | * прерывания по таймауту errno устанавливается в 0. 70 | */ 71 | ssize_t nbwritev( int aFileDescriptor, const struct iovec *iov, int iovcnt, unsigned int aTimeOut ); 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif /** __ReadWrite_h__ */ 78 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/aptl/avector.h: -------------------------------------------------------------------------------- 1 | #ifndef __a_vector_h__ 2 | #define __a_vector_h__ 3 | //============================================================================// 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _MSC_VER 9 | #pragma warning(disable:4786) // identifier was truncated to '255' characters in the debug information 10 | #endif 11 | //============================================================================// 12 | // avector DECLARATION 13 | //============================================================================// 14 | template 15 | class avector 16 | { 17 | private: 18 | /* copy prevention */ 19 | avector(const avector&) { } 20 | avector& operator = (const avector&) { return *this; } 21 | 22 | public: 23 | /* CONSTRUCTORS AND DESTRUCTORS */ 24 | avector(size_t growing_increment = 0, 25 | size_t growing_power = 0, 26 | size_t auto_free_limit = 0, 27 | size_t alloc_limit = size_t(-1)) : 28 | m_size(0), m_alloc(0), m_buffer(0), m_no_memory_flag(false) 29 | { 30 | m_growing_increment = growing_increment; 31 | m_growing_power = growing_power; 32 | m_auto_free_limit = auto_free_limit; 33 | m_alloc_limit = alloc_limit; 34 | m_initial_size = 0; 35 | } 36 | 37 | virtual ~avector() { free_buffer(); } 38 | 39 | /* PUBLIC ACCESS = vector's methods */ 40 | 41 | // clear - Erases the elements of the vector. 42 | void clear() { resize(0); } 43 | 44 | // empty - Tests if the vector container is empty. 45 | bool empty() const { return (m_size == 0); } 46 | 47 | // size - Returns the number of elements in the vector. 48 | size_t size() const { return m_size; } 49 | 50 | // size_bytes - Returns total memory occupied by the vector's elements. 51 | size_t size_bytes() const { return m_size * sizeof(T); } 52 | 53 | // resize - Specifies a new size for a vector. 54 | void resize(size_t new_size); 55 | 56 | // push_back - Add an element to the end of the vector. 57 | void push_back(const T& item); 58 | 59 | // pop_back - Deletes the element at the end of the vector. 60 | void pop_back() { if(m_size) resize(m_size - 1); } 61 | 62 | // reserve - Reserves a minimum length of storage for a vector object. 63 | void reserve(size_t new_capacity) { ensure_alloc(new_capacity); } 64 | 65 | // capacity - Returns the number of elements that the vector could contain without allocating more storage. 66 | size_t capacity() const { return m_alloc; } 67 | 68 | // max_size - Returns the maximum length of the vector. 69 | size_t max_size() const { return m_alloc_limit; } 70 | 71 | // at - Returns a reference to the element at a specified location in the vector. 72 | T& at(size_t pos) { return m_buffer[pos]; } 73 | const T& at(size_t pos) const { return m_buffer[pos]; }; 74 | 75 | // operator[] - Returns a reference to the vector element at a specified position. 76 | T& operator[](size_t pos) { return m_buffer[pos]; } 77 | const T& operator[](size_t pos) const { return m_buffer[pos]; } 78 | 79 | // back - Returns a reference to the last element of the vector. 80 | T& back() { return m_buffer[m_size - 1]; } 81 | const T& back() const { return m_buffer[m_size - 1]; } 82 | 83 | // front - Returns a reference to the first element in a vector. 84 | T& front() { return m_size ? m_buffer[0] : 0; } 85 | const T& front() const { return m_size ? m_buffer[0] : 0; } 86 | 87 | // assign - Erases a vector and copies the specified elements to the empty vector 88 | // begin - Returns a random-access iterator to the first element in the container. 89 | // end - Returns a random-access iterator that points just beyond the end of the vector. 90 | // erase - Removes an element or a range of elements in a vector from specified positions. 91 | // get_allocator - Returns an object to the allocator class used by a vector. 92 | // insert - Inserts an element or a number of elements into the vector at a specified position. 93 | // rbegin - Returns an iterator to the first element in a reversed vector. 94 | // rend - Returns an iterator to the end of a reversed vector. 95 | // swap - Exchanges the elements of two vectors. 96 | 97 | /* PUBLIC ACCESS = extra methods */ 98 | 99 | // free allocated memory 100 | void free_buffer() { resize(0); if(m_buffer) free(m_buffer); m_buffer = NULL; m_alloc = 0; m_no_memory_flag = false; } 101 | 102 | // check status of last realloc 103 | bool no_memory() const { return m_no_memory_flag; } 104 | 105 | // add a new element and return pointer to it, NULL on error 106 | T* grow(); 107 | 108 | // add a new ***UNINITIALIZED*** element and return pointer to it, NULL on error 109 | // WARNING: caller MUST construct (by inplace new or by other way) object T 110 | T* uninitialized_grow(size_t nGrow=1); 111 | 112 | // returns pointer to buffer, may become invalid after next realloc 113 | T* get_buffer() const { return m_buffer; } 114 | 115 | void remove(size_t pos); 116 | 117 | void qsort(int (*comp_func)(const void *, const void *)); 118 | 119 | protected: 120 | void set_initial_size(size_t initial_size) { m_initial_size = initial_size; } 121 | void set_growing_increment(size_t growing_increment) { m_growing_increment = growing_increment; } 122 | void set_growing_power(size_t growing_power) { m_growing_power = growing_power; } 123 | 124 | private: 125 | /* PRIVATE MEMBERS */ 126 | bool ensure_alloc(size_t new_alloc); 127 | 128 | /* PRIVATE DATA */ 129 | size_t m_size; 130 | size_t m_alloc; 131 | T* m_buffer; 132 | bool m_no_memory_flag; 133 | 134 | size_t m_growing_increment; 135 | size_t m_growing_power; 136 | size_t m_initial_size; 137 | size_t m_auto_free_limit; 138 | size_t m_alloc_limit; 139 | 140 | enum { DEFAULT_GROWING_INCREMENT = 16, 141 | DEFAULT_GROWING_POWER = 5, 142 | DEFAULT_INITIAL_SIZE = 32}; 143 | }; 144 | 145 | //============================================================================// 146 | // astring DECLARATION 147 | /*----------------------------------------------------------------------------*/ 148 | class astring : public avector 149 | { 150 | private: 151 | /* copy prevention */ 152 | astring(const astring&): avector() { } 153 | astring& operator = (const astring&) { return *this; } 154 | 155 | public: 156 | astring(size_t growing_increment = 0, 157 | size_t growing_power = 0, 158 | size_t auto_free_limit = 0, 159 | size_t alloc_limit = size_t(-1)) 160 | : avector(growing_increment, growing_power, auto_free_limit, alloc_limit) 161 | {} 162 | 163 | operator char*() { return get_buffer(); } 164 | operator const char*() const { return get_buffer(); } 165 | }; 166 | 167 | //============================================================================// 168 | // avector IMPLEMENTATION 169 | //============================================================================// 170 | /* SAFE CONSTRUCTION AND DISTRUCTION */ 171 | /*----------------------------------------------------------------------------*/ 172 | struct __the_avector_element_ptr 173 | { 174 | }; 175 | 176 | inline void* operator new(size_t, __the_avector_element_ptr* pt) 177 | { return pt; } 178 | 179 | inline void operator delete(void*, __the_avector_element_ptr*) 180 | { } 181 | /*----------------------------------------------------------------------------*/ 182 | // class 183 | template 184 | inline void __safe_avector_construct_def(A* p, size_t n) 185 | { 186 | memset(p, 0, n * sizeof(A)); 187 | while(n-- > 0) 188 | new ((__the_avector_element_ptr*)(p++))A; 189 | } 190 | 191 | template 192 | inline void __safe_avector_destruct(A* pt, size_t n) 193 | { for ( ; n-- > 0; pt++ ) pt->~A(); } 194 | 195 | template 196 | inline void __safe_avector_construct_cpy(A* p, B r) 197 | { 198 | new ((__the_avector_element_ptr*)p)A(r); 199 | } 200 | /*----------------------------------------------------------------------------*/ 201 | /* ALLOC AND RESIZE IMPLEMENTATION */ 202 | /*----------------------------------------------------------------------------*/ 203 | template 204 | inline bool avector::ensure_alloc(size_t new_alloc) 205 | { 206 | // check limit 207 | if(new_alloc > m_alloc_limit) 208 | { 209 | m_no_memory_flag = true; 210 | return false; 211 | } 212 | 213 | // already allocated 214 | if(new_alloc <= m_alloc) 215 | { 216 | m_no_memory_flag = false; 217 | return true; 218 | } 219 | 220 | // default growing parameters 221 | size_t growing_increment = m_growing_increment; 222 | size_t growing_power = m_growing_power; 223 | if(!growing_increment && !growing_power) 224 | growing_power = static_cast( DEFAULT_GROWING_POWER ); 225 | 226 | // count delta 227 | size_t delta = 0; 228 | if(m_alloc == 0) 229 | delta = m_initial_size ? m_initial_size : static_cast( DEFAULT_INITIAL_SIZE ); 230 | else if(growing_power) 231 | { 232 | delta = m_alloc >> (growing_power - 1); 233 | if(delta < growing_increment) 234 | delta = growing_increment; 235 | } 236 | else 237 | delta = m_growing_increment; 238 | if(delta == 0) 239 | delta = static_cast( DEFAULT_GROWING_INCREMENT ); 240 | 241 | // count needed_size 242 | size_t needed_size = m_alloc + delta; 243 | if(needed_size < new_alloc) 244 | needed_size = new_alloc; 245 | else if(needed_size > m_alloc_limit) 246 | needed_size = m_alloc_limit; 247 | 248 | // allocating memory 249 | T* buffer = static_cast(realloc(m_buffer, (needed_size * sizeof(T)))); 250 | if(!buffer) 251 | { 252 | m_no_memory_flag = true; 253 | return false; 254 | } 255 | else 256 | { 257 | m_no_memory_flag = false; 258 | m_buffer = buffer; 259 | m_alloc = needed_size; 260 | return true; 261 | } 262 | } 263 | /*----------------------------------------------------------------------------*/ 264 | template 265 | inline void avector::resize(size_t new_size) 266 | { 267 | if(new_size == m_size) 268 | return; 269 | 270 | // add new elements 271 | if(new_size > m_size) 272 | { 273 | if(!ensure_alloc(new_size)) 274 | return; // no memory 275 | __safe_avector_construct_def(m_buffer + m_size, new_size - m_size); 276 | m_size = new_size; 277 | return; 278 | } 279 | 280 | // delete elements 281 | if(new_size < m_size) 282 | { 283 | __safe_avector_destruct(m_buffer + new_size, m_size - new_size); 284 | m_size = new_size; 285 | return; 286 | } 287 | } 288 | /*----------------------------------------------------------------------------*/ 289 | template 290 | inline void avector::push_back(const T& item) 291 | { 292 | if(!ensure_alloc(m_size + 1)) 293 | return; // no memory 294 | __safe_avector_construct_cpy(m_buffer + m_size, item); 295 | m_size++; 296 | } 297 | /*----------------------------------------------------------------------------*/ 298 | template 299 | inline void avector::remove(size_t pos) 300 | { 301 | if(pos < m_size) 302 | { 303 | __safe_avector_destruct(m_buffer + pos, 1); 304 | memmove(m_buffer+pos, m_buffer+pos+1, (m_size-pos-1)* sizeof(T)); 305 | m_size--; 306 | } 307 | } 308 | /*----------------------------------------------------------------------------*/ 309 | template 310 | inline T* avector::uninitialized_grow(size_t nGrow) 311 | { 312 | if(!ensure_alloc(m_size+nGrow)) 313 | return 0; // no memory 314 | m_size+=nGrow; 315 | return m_buffer + (m_size - nGrow); 316 | } 317 | 318 | template 319 | inline T* avector::grow() 320 | { 321 | resize(m_size + 1); 322 | if(m_no_memory_flag) 323 | return NULL; 324 | else 325 | return m_buffer + (m_size - 1); 326 | } 327 | /*----------------------------------------------------------------------------*/ 328 | template 329 | inline void avector::qsort(int (*comp_func)(const void *, const void *)) 330 | { 331 | ::qsort(m_buffer, m_size, sizeof(T), comp_func); 332 | } 333 | //============================================================================// 334 | #endif /* __a_vector_h__ */ 335 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/nMemoryAllocator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project( nMemoryAllocator ) 2 | cmake_minimum_required( VERSION 2.6 ) 3 | 4 | set( CMAKE_C_FLAGS "-fPIC" ) 5 | set( CMAKE_CXX_FLAGS "-fPIC" ) 6 | 7 | file( GLOB_RECURSE SOURCES nMemoryAllocator.h nMemoryAllocator.hpp nMemoryAllocator.cpp ) 8 | 9 | add_library( ${PROJECT_NAME} OBJECT ${SOURCES} ) 10 | target_compile_options( ${PROJECT_NAME} PRIVATE "--std=c++11" ) 11 | 12 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/nMemoryAllocator/nMemoryAllocator.cpp: -------------------------------------------------------------------------------- 1 | #include "nMemoryAllocator.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 10 | * 11 | * Параметры и функции для работы с технической частью выделяемых секторов 12 | * 13 | ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ 14 | 15 | /** Определение размера технической области каждого сектора выделяемой памяти. **/ 16 | static size_t gReservedSectorPartSize = sizeof( void* ) + sizeof( size_t ); 17 | 18 | /** Получение сектора, следующего за указанным. **/ 19 | inline void* GetNextSector( void* aSector ) 20 | { 21 | return *static_cast(aSector); 22 | } 23 | 24 | /** Запись указателя на следущий сектор для указанного. **/ 25 | inline void SetNextSector( void* aSector, void* aNextSector ) 26 | { 27 | memcpy( aSector, &aNextSector, sizeof( void* ) ); 28 | } 29 | 30 | /** Получение размера указанного сектора. **/ 31 | inline size_t GetSectorSize( void* aSector ) 32 | { 33 | return *reinterpret_cast((static_cast(aSector)+sizeof(void*))); 34 | } 35 | 36 | /** Установка размера указанного сектора. **/ 37 | inline void SetSectorSize( void* aSector, size_t aSectorSize ) 38 | { 39 | *reinterpret_cast(static_cast(aSector)+sizeof(void*)) = aSectorSize; 40 | } 41 | 42 | nMemoryAllocator::nMemoryAllocator( size_t aFirstSectorSize, size_t aSectorSize ) 43 | { 44 | if( aSectorSize <= gReservedSectorPartSize || aSectorSize == size_t(-1) ) 45 | vSectorSize = 1000; 46 | else 47 | vSectorSize = aSectorSize; 48 | 49 | if( aFirstSectorSize <= gReservedSectorPartSize || aFirstSectorSize == size_t(-1) ) 50 | vFirstSectorSize = vSectorSize; 51 | else 52 | vFirstSectorSize = aFirstSectorSize; 53 | 54 | // Инициализация всех переменных. 55 | vFirstSector = NULL; 56 | vCurrentSector = NULL; 57 | vFreeMemory = NULL; 58 | 59 | vAllocatedMemory = 0; 60 | vFullAllocatedMemorySize = 0; 61 | } 62 | 63 | void nMemoryAllocator::SetMemoryStep( size_t aSectorSize ) 64 | { 65 | if( aSectorSize > gReservedSectorPartSize && aSectorSize != size_t(-1) ) 66 | vSectorSize = aSectorSize; 67 | } 68 | 69 | void* nMemoryAllocator::Allocate( size_t aSize ) 70 | { 71 | // Проверка аргументов. 72 | if( aSize == 0 || size_t(-1) - aSize <= sizeof(uint32_t) ) 73 | return NULL; 74 | 75 | // Приведение размера к кратности. 76 | aSize = aSize + ( aSize%sizeof(uint32_t) ? sizeof(uint32_t)-aSize%sizeof(uint32_t) : 0 ) ; 77 | 78 | if( !vCurrentSector ) 79 | { 80 | // Проверка на превышение общего лимита выделения памяти. 81 | if( size_t(-1) - aSize <= gReservedSectorPartSize || 82 | size_t(-1) - vFullAllocatedMemorySize <= gReservedSectorPartSize + aSize ) 83 | return NULL; 84 | 85 | // Память еще не выделялась. 86 | size_t size = 0; 87 | if( vFirstSectorSize < aSize + gReservedSectorPartSize ) 88 | size = aSize + gReservedSectorPartSize; 89 | else 90 | size = vFirstSectorSize; 91 | 92 | // Выделяем память. 93 | void* nptr = malloc( size ); 94 | if( !nptr ) 95 | return NULL; 96 | 97 | // Зануленье памяти. 98 | memset( nptr, 0, size ); 99 | 100 | vFullAllocatedMemorySize += size; 101 | 102 | // Формируем техническую часть сектора. 103 | SetSectorSize( nptr, size-gReservedSectorPartSize ); 104 | SetNextSector( nptr, NULL ); 105 | 106 | // Установка указателей класса. 107 | vCurrentSector = nptr; 108 | vFirstSector = nptr; 109 | vFreeMemory = static_cast(nptr)+gReservedSectorPartSize; 110 | vAllocatedMemory = size-gReservedSectorPartSize; 111 | } 112 | else if( aSize > vAllocatedMemory ) 113 | { 114 | // Памяти в текущем секторе недостаточно. 115 | void* ptr = NULL; 116 | void* prev = vCurrentSector; 117 | 118 | if( GetNextSector( vCurrentSector ) != NULL ) 119 | { 120 | // Пытаемся использовать ранее выделенную память. 121 | ptr = GetNextSector( vCurrentSector ); 122 | while( ptr ) 123 | { 124 | if( GetSectorSize( ptr ) >= aSize ) 125 | break; 126 | 127 | prev = ptr; 128 | ptr = GetNextSector( ptr ); 129 | } 130 | } 131 | 132 | if( ptr ) 133 | { 134 | // Нужный сектор найден. 135 | if( prev != vCurrentSector ) 136 | { 137 | // Переставляем сектора. 138 | void* next = GetNextSector( vCurrentSector ); 139 | void* tail = GetNextSector( ptr ); 140 | 141 | SetNextSector( vCurrentSector, ptr ); 142 | SetNextSector( ptr, next ); 143 | SetNextSector( prev, tail ); 144 | } 145 | 146 | vCurrentSector = ptr; 147 | vFreeMemory = static_cast(ptr)+gReservedSectorPartSize; 148 | vAllocatedMemory = GetSectorSize( ptr ); 149 | } 150 | else 151 | { 152 | // Ранее выделенной памяти нехватает. 153 | 154 | // Проверка на превышение общего лимита выделения памяти. 155 | if( size_t(-1) - aSize <= gReservedSectorPartSize || 156 | size_t(-1) - vFullAllocatedMemorySize <= gReservedSectorPartSize + aSize ) 157 | return NULL; 158 | 159 | size_t size = 0; 160 | if( vSectorSize < aSize + gReservedSectorPartSize || size_t(-1) - vSectorSize <= vFullAllocatedMemorySize ) 161 | size = aSize + gReservedSectorPartSize; 162 | else 163 | size = vSectorSize; 164 | 165 | // Выделяем память. 166 | void* nptr = malloc( size ); 167 | if( !nptr ) 168 | return NULL; 169 | 170 | // Зануленье памяти. 171 | memset( nptr, 0, size ); 172 | 173 | vFullAllocatedMemorySize += size; 174 | 175 | SetSectorSize( nptr, size-gReservedSectorPartSize ); 176 | SetNextSector( nptr, GetNextSector( vCurrentSector ) ); 177 | SetNextSector( vCurrentSector, nptr ); 178 | 179 | // Установка указателей класса. 180 | vCurrentSector = nptr; 181 | vFreeMemory = static_cast(nptr)+gReservedSectorPartSize; 182 | vAllocatedMemory = size-gReservedSectorPartSize; 183 | } 184 | } 185 | 186 | // Памяти достаточно. 187 | void* ptr = vFreeMemory; 188 | 189 | // Передвигаем указатель на свободную память. 190 | vFreeMemory = static_cast(vFreeMemory) + aSize; 191 | 192 | // Уменьшаем счетчик доступной памяти. 193 | if( aSize <= vAllocatedMemory ) 194 | vAllocatedMemory -= aSize; 195 | else 196 | vAllocatedMemory = 0; 197 | 198 | return ptr; 199 | } 200 | 201 | void nMemoryAllocator::Reset() 202 | { 203 | vCurrentSector = vFirstSector; 204 | if( vCurrentSector ) 205 | { 206 | vFreeMemory = static_cast(vCurrentSector)+gReservedSectorPartSize; 207 | vAllocatedMemory = GetSectorSize( vCurrentSector ); 208 | } 209 | else 210 | vAllocatedMemory = 0; 211 | } 212 | 213 | void nMemoryAllocator::Free() 214 | { 215 | void* ptr = vFirstSector; 216 | 217 | unsigned int i = 0; 218 | while( ptr ) 219 | { 220 | i++; 221 | void* cur = ptr; 222 | ptr = GetNextSector( ptr ); 223 | free( cur ); 224 | } 225 | 226 | vFirstSector = NULL; 227 | vCurrentSector = NULL; 228 | 229 | vFullAllocatedMemorySize = 0; 230 | vAllocatedMemory = 0; 231 | } 232 | 233 | /** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 234 | * 235 | * Обертка на C для nMemoryAllocator 236 | * 237 | ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/ 238 | #include "nMemoryAllocator.h" 239 | 240 | extern "C" ncMemoryAllocator* ncMemoryAllocatorCreate() 241 | { 242 | // Создание аллокатора. 243 | return reinterpret_cast(new nMemoryAllocator); 244 | } 245 | 246 | extern "C" void ncMemoryAllocatorDestroy( ncMemoryAllocator* aMemoryAllocator ) 247 | { 248 | // Проверка аргументов. 249 | if( !aMemoryAllocator ) 250 | return; 251 | 252 | // Удаление аллокатора. 253 | delete reinterpret_cast(aMemoryAllocator); 254 | } 255 | 256 | extern "C" void* AllocatorAllocate( ncMemoryAllocator* aMemoryAllocator, size_t aTargetMemorySize ) 257 | { 258 | // Проверка аргументов. 259 | if( !aMemoryAllocator || aTargetMemorySize == 0 ) 260 | return NULL; 261 | 262 | // Выделение памяти. 263 | return reinterpret_cast(aMemoryAllocator)->Allocate( aTargetMemorySize ); 264 | } 265 | 266 | extern "C" void ncMemoryAllocatorFree( ncMemoryAllocator* aMemoryAllocator ) 267 | { 268 | // Проверка аргументов. 269 | if( !aMemoryAllocator ) 270 | return; 271 | 272 | // Освобождение памяти. 273 | reinterpret_cast(aMemoryAllocator)->Free(); 274 | } 275 | 276 | extern "C" void ncMemoryAllocatorReset( ncMemoryAllocator* aMemoryAllocator ) 277 | { 278 | // Проверка аргументов. 279 | if( !aMemoryAllocator ) 280 | return; 281 | 282 | // Очистка памяти. 283 | reinterpret_cast(aMemoryAllocator)->Reset(); 284 | } 285 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/nMemoryAllocator/nMemoryAllocator.h: -------------------------------------------------------------------------------- 1 | #ifndef __nMemoryAllocator_h__ 2 | #define __nMemoryAllocator_h__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | /** Определение структуры, которая будет исполнять роль аллокатора. */ 10 | typedef struct __ncMemoryAllocator ncMemoryAllocator; 11 | 12 | /** Создание нового аллокатора. */ 13 | ncMemoryAllocator* ncMemoryAllocatorCreate(); 14 | 15 | /** 16 | * Удаление существующего аллокатора. 17 | * @param aMemoryAllocator - существующий аллокатор. 18 | */ 19 | void ncMemoryAllocatorDestroy( ncMemoryAllocator* aMemoryAllocator ); 20 | 21 | /** 22 | * Выделение памяти с помощью аллокатора. 23 | * @param aMemoryAllocator - существующий аллокатор. 24 | * @param aTargetMemorySize - необходимый размер памяти. 25 | */ 26 | void* AllocatorAllocate( ncMemoryAllocator* aAllocator, size_t aTargetMemorySize ); 27 | 28 | /** 29 | * Очистка памяти, выделенной аллокатором. 30 | * @param aMemoryAllocator - существующий аллокатор. 31 | */ 32 | void ncMemoryAllocatorReset( ncMemoryAllocator* aMemoryAllocator ); 33 | 34 | /** 35 | * Освобождение памяти, выделенной аллокатором. 36 | * @param aMemoryAllocator - существующий аллокатор. 37 | */ 38 | void ncMemoryAllocatorFree( ncMemoryAllocator* aMemoryAllocator ); 39 | 40 | #ifdef __cplusplus 41 | } 42 | #endif 43 | 44 | #endif /** __nMemoryAllocator_h__ */ 45 | -------------------------------------------------------------------------------- /client-lib-py/client-lib-cpp/nMemoryAllocator/nMemoryAllocator.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Аллокатор памяти предназначен для работы с многочисленными выделениями памяти, освобождение которой 3 | * происходит единомоментно. Аллокатор выделяет память большими кусками, после чего раздает ее на запросы 4 | * выделения памяти. В случае, когда вся память, выделенная аллокатором выбрана, аллокатор выделяет 5 | * дополнительный кусок памяти. 6 | */ 7 | #ifndef __nMemoryAllocator_hpp__ 8 | #define __nMemoryAllocator_hpp__ 9 | 10 | #include 11 | 12 | /** 13 | * Класс для работы с многочисленными мелкими выделениями памяти при единомоментной ее очистке. 14 | */ 15 | class nMemoryAllocator 16 | { 17 | public: 18 | /** 19 | * Конструктор. Заметим, что при указании размеров секторов нужно учитывать, что кроме собственно памяти 20 | * выделяемой по запросу Allocate в секторе будет хранится некоторое количество технической информации. 21 | * @param aFirstSectorSize - размер первого сектора выделения памяти. Если значение равно 0, то используется 22 | * значение aSectorSize. 23 | * @param aSectorSize - размер всех секторов, кроме первого. 24 | */ 25 | nMemoryAllocator( size_t aFirstSectorSize = 0, size_t aSectorSize = 1024*1024 ); 26 | /** Деструктор. */ 27 | ~nMemoryAllocator() 28 | { Free(); } 29 | 30 | 31 | public: 32 | /** 33 | * Смена размера секторов. 34 | * @param aSectorSize - новый размер сектора. 35 | */ 36 | void SetMemoryStep( size_t aSectorSize ); 37 | 38 | /** 39 | * Выделение памяти. 40 | * @param aSize - нужный размер памяти. 41 | */ 42 | void* Allocate( size_t aSize ); 43 | 44 | /** Получение информации о общем объеме выделенной памяти. */ 45 | size_t GetAllocatedMemorySize() const 46 | { return vFullAllocatedMemorySize; } 47 | 48 | 49 | public: 50 | /** Очистка памяти. */ 51 | void Reset(); 52 | 53 | /** Освобождение памяти. */ 54 | void Free(); 55 | 56 | 57 | private: 58 | /** Ссылка на первый сектор памяти. */ 59 | void* vFirstSector; 60 | 61 | /** Ссылка на текущий сектор памяти. */ 62 | void* vCurrentSector; 63 | 64 | /** Ссылка на Свободную память. */ 65 | void* vFreeMemory; 66 | 67 | /** Количество имеющейся свободной памяти в текущем секторе. */ 68 | size_t vAllocatedMemory; 69 | 70 | /** Шаг выделения памяти. */ 71 | size_t vFirstSectorSize; 72 | /** Шаг выделения памяти. */ 73 | size_t vSectorSize; 74 | 75 | /** Объем выделенной памяти. */ 76 | size_t vFullAllocatedMemorySize; 77 | }; 78 | 79 | /** 80 | * Вспомогательная структура и определение операторов new и delete для выделения с помощью nMemoryAllocator'а 81 | * памяти под объекты требующие инициализации конструкторами. 82 | */ 83 | typedef struct 84 | { 85 | } nMemoryAllocatorElementPtr; 86 | 87 | inline void* operator new( size_t, nMemoryAllocatorElementPtr* pt ) { return pt; } 88 | 89 | inline void operator delete( void*, nMemoryAllocatorElementPtr* ) { } 90 | 91 | 92 | #define nAllocateObject( aAllocator, aClass ) static_cast( (aAllocator).Allocate( sizeof( aClass ) )) 93 | 94 | 95 | #define nAllocateNewObject( aAllocator, aClass, aName ) \ 96 | aClass* aName = static_cast( (aAllocator).Allocate( sizeof( aClass ) )) 97 | 98 | 99 | #define nAllocateObjects( aAllocator, aClass, aNumber ) \ 100 | static_cast( (aAllocator).Allocate( sizeof( aClass )*aNumber )) 101 | 102 | #define nAllocateNewObjects( aAllocator, aClass, aNumber, aName ) \ 103 | aClass* aName = static_cast( (aAllocator).Allocate( sizeof( aClass )*aNumber )) 104 | 105 | #endif /** __nMemoryAllocator_hpp__ */ 106 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/__init__.py: -------------------------------------------------------------------------------- 1 | from . import session, inf, answer, exceptions, client, others 2 | import pydpclient 3 | 4 | __all__ = [ 5 | "session", 6 | "inf", 7 | "answer", 8 | "exceptions", 9 | "client", 10 | "others", 11 | "pydpclient", 12 | ] 13 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/answer.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Callable, Optional 2 | from .exceptions import DPClientException 3 | from pydpclient import AnswerPointerType, cl_answer_free, cl_answer_get_size,\ 4 | cl_answer_get_type, cl_answer_get_text, cl_answer_get_tag_inf,\ 5 | cl_answer_get_tag_href, cl_answer_get_instruct,\ 6 | cl_answer_get_tag_open_window, cl_answer_get_tag_rss 7 | 8 | 9 | class Answer: 10 | """ 11 | Класс для работы с объектом ответа. 12 | Сам объект AnswerPointerType представляет собой указатель на 13 | Си-структуру Answer. 14 | """ 15 | 16 | # Типы ответа и их описание 17 | _answer_types = { 18 | 1: ( 19 | "AnswerItemTypeTextString", 20 | "Текстовая строка", 21 | ), 22 | 2: ( 23 | "AnswerItemTypeTagInf", 24 | "Тэг inf, обозначающий кликабельный ответ инфу", 25 | ), 26 | 3: ( 27 | "AnswerItemTypeTagBr", 28 | "Тэг br, обозначающий перенос строки", 29 | ), 30 | 4: ( 31 | "AnswerItemTypeTagHref", 32 | "Тэг href, обозначающий ссылку", 33 | ), 34 | 5: ( 35 | "AnswerItemTypeInstruct", 36 | "Инструкция на изменение сессии", 37 | ), 38 | 6: ( 39 | "AnswerItemTypeTagOpenWindow", 40 | "Тэг open_window, обозначающий команду открытия " 41 | "ссылки в окне браузера", 42 | ), 43 | 7: ( 44 | "AnswerItemTypeTagRSS", 45 | "Тэг запроса RSS", 46 | ), 47 | 8: ( 48 | "AnswerItemTypeStartUList", 49 | "Начало ненумерованного форматированного списка", 50 | ), 51 | 9: ( 52 | "AnswerItemTypeStartOList", 53 | "Начало нумерованного форматированного списка", 54 | ), 55 | 10: ( 56 | "AnswerItemTypeListItem", 57 | "Начало элемента форматированного списка", 58 | ), 59 | 11: ( 60 | "AnswerItemTypeEndList", 61 | "Конец форматированного списка", 62 | ), 63 | } 64 | 65 | def __init__(self, answer_obj: AnswerPointerType): 66 | """ 67 | Инициализация объекта ответа. 68 | Обязательно передавать объект указатель, т.к. нет функционала 69 | для создния пустого ответа. 70 | Args: 71 | answer_obj: объект-указатель на структуру Answer. 72 | """ 73 | self.answer_obj = answer_obj 74 | 75 | def __del__(self): 76 | """ 77 | Высвобождение памяти, занятой объектом ответа и 78 | объектом-указателем на него. 79 | """ 80 | ret_code = cl_answer_free(self.answer_obj) 81 | del self.answer_obj 82 | if ret_code: 83 | raise DPClientException(ret_code) 84 | 85 | # Базовые функции 86 | 87 | def get_size(self) -> int: 88 | """ 89 | Получение числа сообщений в ответе. 90 | Returns: 91 | число сообщений в ответе. 92 | """ 93 | return cl_answer_get_size(self.answer_obj) 94 | 95 | def get_type(self, message_num: int) -> Tuple[int, Tuple[str, str]]: 96 | """ 97 | Получение типа соообщения в ответе по его индексу. 98 | Args: 99 | message_num: индекс сообщения ответа. 100 | Returns: 101 | кортеж, в котором первый элемент является целым числом - номер типа, 102 | а второй элемент представляет собой кортеж из двух строк - 103 | название типа в Си-коде и его русскоязычного описания. 104 | """ 105 | ret_code, type_num = cl_answer_get_type(self.answer_obj, message_num) 106 | if ret_code: 107 | raise DPClientException(ret_code) 108 | return type_num, self._answer_types.get(type_num, ('', '')) 109 | 110 | def get_text(self, message_num: int) -> str: 111 | """ 112 | Получение значения сообщения как текста. 113 | Args: 114 | message_num: индекс сообщения ответа. 115 | Returns: 116 | строковое представление сообщения 117 | """ 118 | ret_code, text = cl_answer_get_text(self.answer_obj, message_num) 119 | if ret_code: 120 | raise DPClientException(ret_code) 121 | return text 122 | 123 | def get_tag_inf(self, message_num: int) -> Tuple[str, str]: 124 | """ 125 | Получение данных сообщения как тэга запроса к инфу. 126 | Args: 127 | message_num: индекс сообщения в ответе. 128 | Returns: 129 | кортеж из двух строк - текста ссылки и текста запроса к серверу. 130 | """ 131 | ret_code, a_value, a_request = cl_answer_get_tag_inf( 132 | self.answer_obj, message_num, 133 | ) 134 | if ret_code: 135 | raise DPClientException(ret_code) 136 | return a_value, a_request 137 | 138 | def get_tag_href(self, message_num: int) -> Tuple[str, str, str]: 139 | """ 140 | Получение данных сообщения как тэга ссылки. 141 | Args: 142 | message_num: индекс сообщения в ответе. 143 | Returns: 144 | кортеж из трех строк - URL ссылки, Target ссылки и текст ссылки. 145 | """ 146 | ret_code, url, target, link = cl_answer_get_tag_href( 147 | self.answer_obj, message_num, 148 | ) 149 | if ret_code: 150 | raise DPClientException(ret_code) 151 | return url, target, link 152 | 153 | def get_instruct(self, message_num: int) -> Tuple[str, str]: 154 | """ 155 | Получение данных сообщения как инструкции по изменению сессии. 156 | Args: 157 | message_num: индекс сообщения в ответе. 158 | Returns: 159 | кортеж из двух строк - имени и значения переменной. 160 | """ 161 | ret_code, v_name, v_value = cl_answer_get_instruct( 162 | self.answer_obj, message_num, 163 | ) 164 | if ret_code: 165 | raise DPClientException(ret_code) 166 | return v_name, v_value 167 | 168 | def get_tag_open_window(self, message_num: int) -> Tuple[str, str]: 169 | """ 170 | Получение данных сообщения как тэга открытия ссылки в окне браузера. 171 | Args: 172 | message_num: индекс сообщеия в ответе. 173 | Returns: 174 | кортеж из двух строк - URL и идентификатор окна, в 175 | котором нужно открыть ссылку. 176 | """ 177 | ret_code, url, target = cl_answer_get_tag_open_window( 178 | self.answer_obj, message_num, 179 | ) 180 | if ret_code: 181 | raise DPClientException(ret_code) 182 | return url, target 183 | 184 | def get_tag_rss( 185 | self, 186 | message_num: int, 187 | ) -> Tuple[str, str, int, int, int, int]: 188 | """ 189 | Получение данных сообщения как тэга запроса RSS. 190 | Args: 191 | message_num: индекс сообщения в ответе. 192 | Returns: 193 | кортеж вида (retCode, aURL, aAlt, aOffset, aShowTitle, aShowLink, 194 | aUpdatePeriod), где retCode - код операции, aURL - URL RSS-а, aAlt - 195 | текст, показываемый при недоступности RSS, aOffset - номер RSS 196 | записи, aShowTitle - флаг показа заголовка RSS, aShowLink - флаг 197 | показа ссылки на RSS, aUpdatePeriod - частота обновления RSS. 198 | """ 199 | ret_code, *others = cl_answer_get_tag_rss(self.answer_obj, message_num) 200 | if ret_code: 201 | raise DPClientException(ret_code) 202 | return others 203 | 204 | # Расширенные методы TODO надо что-то придумать другое 205 | 206 | def bindings(self, message_type: int) -> Callable: 207 | """ 208 | Получения соответствующего обработчика сообщения в 209 | зависимости от его типа. 210 | Args: 211 | message_type: номер типа сообщения в ответе. 212 | Returns: 213 | функция-обработчик. 214 | """ 215 | if message_type == 1: 216 | return self.get_text 217 | elif message_type == 2: 218 | return self.get_tag_inf 219 | elif message_type == 3: 220 | return lambda *_: tuple() 221 | elif message_type == 4: 222 | return self.get_tag_href 223 | elif message_type == 5: 224 | return self.get_instruct 225 | elif message_type == 6: 226 | return self.get_tag_open_window 227 | elif message_type == 7: 228 | return self.get_tag_rss 229 | elif message_type in (8, 9, 10, 11): 230 | return lambda *_: tuple() 231 | else: 232 | raise DPClientException(-1) 233 | 234 | def process_message(self, message_num) -> Optional[Tuple]: 235 | """ 236 | Обработка сообщения по его индексу. 237 | Args: 238 | message_num: индекс сообщения. 239 | Returns: 240 | кортеж из элементов, которые вернет обработчик. 241 | """ 242 | tp = self.get_type(message_num) 243 | handler = self.bindings(tp[0]) 244 | if handler is None: 245 | return None 246 | others = handler(message_num) 247 | return others 248 | 249 | def process_all(self) -> tuple: 250 | """ 251 | Обработка всех сообщений в ответе. 252 | Генерируются кортежи из данных, которые вернут обработчики. 253 | Yields: 254 | значения, которые вернут обработчики. 255 | """ 256 | message_amount = self.get_size() 257 | for i in range(message_amount): 258 | data = self.process_message(i) 259 | yield data 260 | return 261 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/client.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Optional 2 | from .exceptions import DPClientException 3 | from .answer import Answer 4 | from .session import Session 5 | from .inf import Inf 6 | from pydpclient import cl_cmd_init, cl_cmd_purge_session, cl_cmd_purge_inf, \ 7 | cl_cmd_update_session, cl_cmd_send_session, cl_cmd_send_inf, cl_cmd_request 8 | import re 9 | 10 | 11 | class Client: 12 | """ 13 | Класс для работы с сервером InfServer. 14 | """ 15 | 16 | def __init__( 17 | self, 18 | connection_string: str = '', 19 | time_out: int = 1000, 20 | pack_data_flag: bool = True, 21 | session: Session = None, 22 | inf: Inf = None, 23 | answer: Answer = None, 24 | ): 25 | """ 26 | Инициализация объекта. 27 | Args: 28 | connection_string: строка соединения. Формат строки соединения: 29 | tcp:host:2255 или unix:socket. 30 | time_out: значение таймаута в секундах. 31 | pack_data_flag: флаг упаковки данных при пересылке между 32 | клиентом и сервером InfServer. 33 | """ 34 | self.session = session 35 | self.inf = inf 36 | self.connection_string = connection_string 37 | self.time_out = time_out 38 | self.pack_data_flag = pack_data_flag 39 | self.answer = answer 40 | 41 | def __del__(self): 42 | """ 43 | Высвобождение памяти, занимаемой собственными объектами. 44 | """ 45 | del self.session 46 | del self.inf 47 | del self.answer 48 | 49 | def initialize( 50 | self, 51 | session_id: Optional[int] = None, 52 | inf_id: Optional[int] = None, 53 | ) -> int: 54 | """ 55 | Запрос инициализации сервером сессии с идентификатором session_id 56 | для инфа inf_id. Если идентификаторы не указаны - берутся айди 57 | связанных объектов. 58 | Args: 59 | session_id: идентификатор сессии. 60 | inf_id: идентификатор инфа. 61 | Returns: 62 | маска недостающих компонентов. 63 | """ 64 | if session_id is None: 65 | session_id = self.session.get_id() 66 | if inf_id is None: 67 | inf_id = self.inf.get_id() 68 | ret_code, missed_data_mask = cl_cmd_init( 69 | inf_id, session_id, 70 | self.connection_string, self.time_out, self.pack_data_flag, 71 | ) 72 | if ret_code: 73 | raise DPClientException(ret_code) 74 | return missed_data_mask 75 | 76 | def purge_session(self, session_id: Optional[int] = None) -> None: 77 | """ 78 | Удаление сессии с идентификатором session_id из кеша сервера. 79 | Если идентификатор не указан - удаляется сессия с идентификатором 80 | связанной сессии. 81 | Args: 82 | session_id: идентификатор сессии. 83 | """ 84 | if session_id is None: 85 | session_id = self.session.get_id() 86 | ret_code = cl_cmd_purge_session( 87 | session_id, 88 | self.connection_string, 89 | self.time_out, 90 | self.pack_data_flag, 91 | ) 92 | if ret_code: 93 | raise DPClientException(ret_code) 94 | return 95 | 96 | def purge_inf(self, inf_id: Optional[int] = None) -> None: 97 | """ 98 | Удаление инфа из кэша бэкэнда по его идентифитаору. 99 | Если идентификатор не указан - удаляется инф с идентификатором 100 | связанного инфа. 101 | Args: 102 | inf_id: идентификатор инфа. 103 | """ 104 | if inf_id is None: 105 | inf_id = self.inf.get_id() 106 | ret_code = cl_cmd_purge_inf( 107 | inf_id, self.connection_string, self.time_out, self.pack_data_flag, 108 | ) 109 | if ret_code: 110 | raise DPClientException(ret_code) 111 | return 112 | 113 | def send_session(self, session: Optional[Session] = None) -> None: 114 | """ 115 | Обновление или добавление сессии в кэш сервера. 116 | Если сессия не указана, то отправляется связанная. 117 | Args: 118 | session: объект сессии. 119 | """ 120 | if session is None: 121 | session = self.session 122 | ret_code = cl_cmd_send_session( 123 | session.session_obj, 124 | self.connection_string, 125 | self.time_out, 126 | self.pack_data_flag, 127 | ) 128 | if ret_code: 129 | raise DPClientException(ret_code) 130 | return 131 | 132 | def update_session(self, session: Optional[Session] = None) -> None: 133 | """ 134 | Обновление значений переменных сессии в кэшэ сервера. 135 | Если сессия не указана, то обновляется связанная сессия. 136 | Args: 137 | session: объект сессии. 138 | """ 139 | if session is None: 140 | session = self.session 141 | ret_code = cl_cmd_update_session( 142 | session.session_obj, 143 | self.connection_string, 144 | self.time_out, 145 | self.pack_data_flag, 146 | ) 147 | if ret_code: 148 | raise DPClientException(ret_code) 149 | return 150 | 151 | def send_inf(self, inf: Optional[Inf] = None) -> None: 152 | """ 153 | Обновление или добавление в кэш сервера данных инфа. 154 | Если инф не передан, то отправляется связанный инф. 155 | Args: 156 | inf: объект инфа. 157 | """ 158 | if inf is None: 159 | inf = self.inf 160 | ret_code = cl_cmd_send_inf( 161 | inf.inf_obj, 162 | self.connection_string, 163 | self.time_out, 164 | self.pack_data_flag, 165 | ) 166 | if ret_code: 167 | raise DPClientException(ret_code) 168 | return 169 | 170 | def request( 171 | self, 172 | session: Optional[Session] = None, 173 | request: str = '', 174 | ) -> Tuple[Answer, int]: 175 | """ 176 | Запрос ответа сервера на запрос request, относящийся к сессии с 177 | идентификатором session_id и инфу с идентификатором inf_id. 178 | Если не указана сессия, то отправится связанная сессия. 179 | Args: 180 | session: объект сессии. 181 | request: запрос. 182 | Returns: 183 | кортеж из двух элементов - объекта ответа и маски потерянных данных. 184 | """ 185 | if session is None: 186 | session = self.session 187 | ret_code, answer_obj, missed_data_mask = cl_cmd_request( 188 | session.get_id(), session.get_inf_id(), 189 | request, session.session_obj, 190 | self.connection_string, self.time_out, self.pack_data_flag, 191 | ) 192 | if ret_code: 193 | raise DPClientException(ret_code) 194 | answer = Answer(answer_obj) 195 | return answer, missed_data_mask 196 | 197 | @staticmethod 198 | def is_success(missed_data_mask: int) -> bool: 199 | """ 200 | Проверка на успешность передачи. 201 | Args: 202 | missed_data_mask: маска потерянных данных. 203 | Returns: 204 | True, если данные не потеряны, иначе False. 205 | """ 206 | return not missed_data_mask 207 | 208 | @staticmethod 209 | def is_session_missed(missed_data_mask: int) -> bool: 210 | """ 211 | Проверка на потерю данных сессии при передаче. 212 | Args: 213 | missed_data_mask: маска потерянных данных. 214 | Returns: 215 | True, если сессия потеряна, иначе False. 216 | """ 217 | return bool(missed_data_mask & 0x02) 218 | 219 | @staticmethod 220 | def is_inf_missed(missed_data_mask: int) -> bool: 221 | """ 222 | Проверка на потерю данных инфа при передаче. 223 | Args: 224 | missed_data_mask: маска потерянных данных. 225 | Returns: 226 | True, если данные инфа потеряны, иначе False. 227 | """ 228 | return bool(missed_data_mask & 0x01) 229 | 230 | def process_missed( 231 | self, 232 | missed_data_mask: int, 233 | session_id: Optional[int] = None, 234 | inf_id: Optional[int] = None, 235 | ) -> int: 236 | """ 237 | Переотправка потерянных данных до бесконечности, если потребуется. 238 | Если идентификаторы сессии или инфа не указаны, то берутся 239 | идентификаторы связанных объектов. 240 | Args: 241 | missed_data_mask: маска потерянных данных. 242 | session_id: идентификатор сессии. 243 | inf_id: идентификатор инфа. 244 | Returns: 245 | флаг потерянных данных. 246 | """ 247 | if session_id is None: 248 | session_id = self.session.get_id() 249 | if inf_id is None: 250 | inf_id = self.inf.get_id() 251 | if self.is_session_missed(missed_data_mask): 252 | self.send_session(self.session) 253 | if self.is_inf_missed(missed_data_mask): 254 | self.send_inf(self.inf) 255 | return self.initialize(session_id, inf_id) 256 | 257 | @staticmethod 258 | def string_postprocessing(s: str) -> str: 259 | """ 260 | Постобработка строки 261 | Args: 262 | s: исходня строка 263 | Returns: 264 | Результирующая строка 265 | """ 266 | # Убираем лишние пробелы по краям 267 | s = s.strip() 268 | # Заменяем ; на ; 269 | s = s.replace(";", ';') 270 | # Убираем пробелы перед знаком пунктуации 271 | pat = r"\s+([,.!?;)]+)" 272 | s = re.sub(r"\s{2,}", " ", re.sub(pat, r"\1", s)) 273 | # Убираем пробелы после ( 274 | s = s.replace("( ", '(') 275 | # Убираем пробелы в кавычках 276 | pat = r'\"\s+([^"]+)\s+\"' 277 | s = re.sub(pat, r'"' + r'\1' + r'"', s) 278 | # Ставим пробел перед ( 279 | s = re.sub(r"([^:=\s])(\()", r"\1 \2", s) 280 | # Ставим пробел перед смайликом 281 | s = re.sub(r"(\S?)([:=][(|)])", r"\1 \2", s) 282 | return s 283 | 284 | def process_answer(self, answer: Answer) -> dict: 285 | """ 286 | Обрабатывает ответ и возвращает его в удобном виде. 287 | Args: 288 | answer: объект ответа. 289 | Returns: 290 | кортеж из двух элементов - строки текстового ответа и словаря-контекста. 291 | """ 292 | result = { 293 | "text": '', 294 | "vars": dict(), 295 | } 296 | end_of_list = '' 297 | for i in range(answer.get_size()): 298 | msg_type = answer.get_type(i)[0] 299 | if msg_type == 1: # Текст 300 | text = answer.get_text(i) 301 | result["text"] += ' ' + text 302 | elif msg_type == 2: # Тег инфа 303 | value, request = answer.get_tag_inf(i) 304 | request_part = f' data-request="{request}"' if request else '' 305 | inf_tag = f'{value}' 306 | result["text"] += ' ' + inf_tag 307 | elif msg_type == 3: # Тег
308 | br_tag = "
" 309 | result["text"] += ' ' + br_tag 310 | elif msg_type == 4: # Тег href 311 | url, target, link = answer.get_tag_href(i) 312 | target = target or "_blank" 313 | href = f'{link}' 314 | href = href.replace("&", '&') 315 | result["text"] += ' ' + href 316 | elif msg_type == 5: # Инструкция по изменению сессии 317 | key, val = answer.get_instruct(i) 318 | result["vars"][key] = val 319 | # Тип 6 и 7 - не используются 320 | elif msg_type == 8: # AnswerItemTypeStartUList 321 | start_of_ulist = "
  • " 322 | end_of_list = "
" 323 | result["text"] += ' ' + start_of_ulist 324 | elif msg_type == 9: # AnswerItemTypeStartOList 325 | start_of_olist = "
  1. " 326 | end_of_list = "
" 327 | result["text"] += ' ' + start_of_olist 328 | elif msg_type == 10: # AnswerItemTypeListItem 329 | li_part = "
  • " 330 | result["text"] += ' ' + li_part 331 | elif msg_type == 11: # AnswerItemTypeEndList 332 | list_ending = "
  • " + end_of_list 333 | result["text"] += ' ' + list_ending 334 | result["text"] = self.string_postprocessing(result["text"]) 335 | return result 336 | 337 | def easy_request( 338 | self, 339 | request: str, 340 | session_id: int, 341 | session_context: dict, 342 | bot_id: int, 343 | bot_context: dict, 344 | ) -> dict: 345 | """ 346 | Запрос данных с сервера. 347 | Args: 348 | request: текст запроса. 349 | session_id: идентификатор сессии. 350 | session_context: контекст сессии. 351 | bot_id: идентификатор бота. 352 | bot_context: контекст бота. 353 | Returns: 354 | кортеж из двух элементов - строки текстового ответа и словаря-контекста. 355 | """ 356 | self.inf = Inf(inf_id=bot_id, inf_context=bot_context) 357 | self.session = Session( 358 | session_id=session_id, 359 | inf_id=bot_id, 360 | session_context=session_context, 361 | ) 362 | answer, missed_mask = self.request(request=request) 363 | if not self.is_success(missed_mask): 364 | self.process_missed(missed_mask) 365 | answer, missed_mask = self.request(request=request) 366 | return self.process_answer(answer) 367 | 368 | def easy_update( 369 | self, 370 | session_id: int, 371 | bot_id: int, 372 | session_context: dict, 373 | ) -> None: 374 | """ 375 | Обновление данных сессии на сервере. 376 | Args: 377 | session_id: идентификатор сессии. 378 | bot_id: идентификатор связанного с сессией инфа. 379 | session_context: контекст сессии. 380 | """ 381 | self.session = Session( 382 | session_id=session_id, 383 | inf_id=bot_id, 384 | session_context=session_context, 385 | ) 386 | self.update_session(self.session) 387 | return 388 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/conftest.py: -------------------------------------------------------------------------------- 1 | def pytest_addoption(parser): 2 | parser.addoption( 3 | "--conn_str", action="store", default='', help="Address of InfServer", 4 | ) 5 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/exceptions.py: -------------------------------------------------------------------------------- 1 | from .others import return_code_string 2 | 3 | 4 | class DPClientException(Exception): 5 | """ 6 | Класс-исключение. 7 | """ 8 | 9 | def __init__(self, ret_code: int): 10 | """ 11 | Определяет текстовое описание ислючения по его коду и форматирует 12 | соответствующее сообщение. 13 | Args: 14 | ret_code: т.н. "код возврата", который возвращет большинство 15 | Си-функций в результате своей работы. 16 | """ 17 | error = return_code_string(ret_code) 18 | super().__init__(f"Error: {error}") 19 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/inf.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Optional, List 2 | from .exceptions import DPClientException 3 | from pydpclient import InfDataPointerType, cl_inf_create, cl_inf_free,\ 4 | cl_inf_set_id, cl_inf_set_templates, cl_inf_get_vars_cnt,\ 5 | cl_inf_get_dicts_cnt, cl_inf_resize, cl_inf_set_var, cl_inf_set_dict,\ 6 | cl_inf_get_var, cl_inf_get_dict 7 | 8 | 9 | class Inf: 10 | """ 11 | Класс для работы с объектами инфов (которые являются структурами в Си). 12 | Сами объекты типа InfDataPointerType являются указателями на структуры в Си. 13 | """ 14 | 15 | inf_id = None 16 | 17 | def __init__( 18 | self, 19 | inf_obj: Optional[InfDataPointerType] = None, 20 | inf_id: Optional[int] = None, 21 | inf_context: Optional[dict] = None, 22 | ): 23 | """ 24 | Инициализация объекта инфа. Си-структура будет создана, 25 | если не был передан объект типа InfDataPointerType. 26 | Args: 27 | inf_obj: объект-указатель на структуру InfData. 28 | """ 29 | self.inf_obj = inf_obj if inf_obj is not None else cl_inf_create() 30 | if inf_id is not None: 31 | self.set_id(inf_id) 32 | if inf_context is not None: 33 | for key, value in inf_context.items(): 34 | self.append_var(key, value) 35 | 36 | def __del__(self): 37 | """ 38 | Высвобождение занятой объектом памяти (как объектом-указателем, 39 | так и самой стрктурой, расположенной по этому указателю). 40 | """ 41 | ret_code = cl_inf_free(self.inf_obj) 42 | del self.inf_obj 43 | if ret_code: 44 | raise DPClientException(ret_code) 45 | 46 | # Базовые функции 47 | 48 | def set_id(self, inf_id: int) -> None: 49 | """ 50 | Установка идентификтора инфа. 51 | Args: 52 | inf_id: идентификатор инфа. 53 | """ 54 | if inf_id < 0: 55 | raise DPClientException(-1) 56 | self.inf_id = inf_id 57 | cl_inf_set_id(self.inf_obj, inf_id) 58 | return 59 | 60 | def get_id(self): 61 | """ 62 | Получение идентификатора инфа. 63 | Returns: 64 | идентификатор инфа. 65 | """ 66 | return self.inf_id 67 | 68 | def set_template(self, template: str) -> None: 69 | """ 70 | Установка шаблона инфа. 71 | Args: 72 | template: шаблон инфа. 73 | """ 74 | cl_inf_set_templates(self.inf_obj, template) 75 | return 76 | 77 | def get_vars_number(self) -> int: 78 | """ 79 | Получение числа переменных инфа. 80 | Returns: 81 | число переменных инфа. 82 | """ 83 | return cl_inf_get_vars_cnt(self.inf_obj) 84 | 85 | def get_dicts_number(self) -> int: 86 | """ 87 | Получение числа словарей инфа. 88 | Returns: 89 | число словарей инфа. 90 | """ 91 | return cl_inf_get_dicts_cnt(self.inf_obj) 92 | 93 | def resize( 94 | self, 95 | new_vars_cnt: Optional[int], 96 | new_dicts_cnt: Optional[int], 97 | ) -> None: 98 | """ 99 | Изменение объема памяти, отведенного под переменные и словари инфа. 100 | Старые переменные и словари при этом стираются. 101 | Args: 102 | new_vars_cnt: новое число переменных инфа. 103 | new_dicts_cnt: новое число словарей инфа. 104 | """ 105 | if new_vars_cnt is None: 106 | new_vars_cnt = self.get_vars_number() 107 | if new_dicts_cnt is None: 108 | new_dicts_cnt = self.get_dicts_number() 109 | if new_vars_cnt < 0 or new_dicts_cnt < 0: 110 | raise DPClientException(-1) 111 | ret_val = cl_inf_resize(self.inf_obj, new_vars_cnt, new_dicts_cnt) 112 | if ret_val: 113 | raise DPClientException(ret_val) 114 | return 115 | 116 | def set_var(self, pos: int, var_name: str, var_value: str) -> None: 117 | """ 118 | Установить переменную инфа по ее индексу. 119 | Args: 120 | pos: индекс переменной. 121 | var_name: имя переменной. 122 | var_value: знаение переменной. 123 | """ 124 | if pos < 0 or pos >= self.get_vars_number(): 125 | raise DPClientException(-1) 126 | cl_inf_set_var(self.inf_obj, pos, var_name, var_value) 127 | return 128 | 129 | def set_dict(self, pos: int, dict_name: str, dict_value: str) -> None: 130 | """ 131 | Установка словаря инфа по его индексу. 132 | Args: 133 | pos: индекс словаря. 134 | dict_name: имя словаря. 135 | dict_value: значение словаря. 136 | """ 137 | if pos < 0 or pos >= self.get_dicts_number(): 138 | raise DPClientException(-1) 139 | cl_inf_set_dict(self.inf_obj, pos, dict_name, dict_value) 140 | return 141 | 142 | def get_var(self, pos: int) -> Tuple[str, str]: 143 | """ 144 | Получить имя и значение переменной по ее индексу. 145 | Args: 146 | pos: индекс переменной. 147 | Returns: 148 | кортеж из двух строк - имени и значения переменной. 149 | """ 150 | if pos < 0 or pos >= self.get_vars_number(): 151 | raise DPClientException(-1) 152 | ret_code, var_name, var_value = cl_inf_get_var(self.inf_obj, pos) 153 | if ret_code: 154 | raise DPClientException(ret_code) 155 | return var_name, var_value 156 | 157 | def get_dict(self, pos: int) -> Tuple[str, str]: 158 | """ 159 | Получение словаря инфа по его индексу. 160 | Args: 161 | pos: индекс словаря инфа. 162 | Returns: 163 | кортеж из двух строк - имени и значения словаря. 164 | """ 165 | if pos < 0: 166 | raise DPClientException(-1) 167 | ret_code, dict_name, dict_value = cl_inf_get_dict(self.inf_obj, pos) 168 | if ret_code: 169 | raise DPClientException(ret_code) 170 | return dict_name, dict_value 171 | 172 | # Расширенные методы 173 | 174 | def get_vars(self) -> List[Tuple[str, str]]: 175 | """ 176 | Получене всех переменных инфа. 177 | Returns: 178 | список кортежей, состоящих из двух строк - 179 | имени и значения переменной. 180 | """ 181 | vars_number = self.get_vars_number() 182 | current_variables = list() 183 | for n in range(vars_number): 184 | current_variables.append(self.get_var(n)) 185 | return current_variables 186 | 187 | def get_dicts(self) -> List[Tuple[str, str]]: 188 | """ 189 | Получение всех словарей инфа. 190 | Returns: 191 | список кортежей, состоящих из двух строк - 192 | имени и значения словаря. 193 | """ 194 | dicts_number = self.get_dicts_number() 195 | current_dicts = list() 196 | for n in range(dicts_number): 197 | current_dicts.append(self.get_dict(n)) 198 | return current_dicts 199 | 200 | def append_var(self, var_name: str, var_value: str) -> None: 201 | """ 202 | Добавить новую переменную в конец. При этом старые переменные 203 | и словари перезапишутся, т.к. операция изменения места под словари 204 | и переменные удаляет их. 205 | Args: 206 | var_name: имя переменной. 207 | var_value: значение переменной. 208 | """ 209 | size_vars = self.get_vars_number() 210 | size_dicts = self.get_dicts_number() 211 | current_vars = self.get_vars() 212 | current_vars.append((var_name, var_value)) 213 | current_dicts = self.get_dicts() 214 | self.resize(size_vars+1, size_dicts) 215 | for n in range(size_vars+1): 216 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 217 | for n in range(size_dicts): 218 | self.set_dict(n, current_dicts[n][0], current_dicts[n][1]) 219 | return 220 | 221 | def append_dict(self, dict_name: str, dict_value: str) -> None: 222 | """ 223 | Добавить словарь в конец. Переменные и словари при этом перезапишутся, 224 | т.к. операция изменения места под переменные и словари удаляет их. 225 | Args: 226 | dict_name: имя словаря. 227 | dict_value: значение словаря. 228 | """ 229 | size_dicts = self.get_dicts_number() 230 | size_vars = self.get_vars_number() 231 | current_dicts = self.get_dicts() 232 | current_dicts.append((dict_name, dict_value)) 233 | current_vars = self.get_vars() 234 | self.resize(size_vars, size_dicts+1) 235 | for n in range(size_dicts+1): 236 | self.set_dict(n, current_dicts[n][0], current_dicts[n][1]) 237 | for n in range(size_vars): 238 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 239 | return 240 | 241 | def pop_value(self, index: Optional[int] = None) -> Tuple[str, str]: 242 | """ 243 | Удалить и вернуть переменную по ее индексу. 244 | Если индекс не указан, то вернется и удалится последняя переменная. 245 | Args: 246 | index: индекс переменной. 247 | Returns: 248 | кортеж из двух строк - имени и значения переменной. 249 | """ 250 | size_vars = self.get_vars_number() 251 | index = index if index is not None else size_vars - 1 252 | if not size_vars or index >= size_vars or index < 0: 253 | raise DPClientException(-1) 254 | size_dicts = self.get_dicts_number() 255 | current_vars = self.get_vars() 256 | var_name, var_value = current_vars.pop(index) 257 | current_dicts = self.get_dicts() 258 | self.resize(size_vars-1, size_dicts) 259 | for n in range(size_vars-1): 260 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 261 | for n in range(size_dicts): 262 | self.set_dict(n, current_dicts[n][0], current_dicts[n][1]) 263 | return var_name, var_value 264 | 265 | def pop_dict(self, index: Optional[int] = None) -> Tuple[str, str]: 266 | """ 267 | Удалить и вернуть словарь инфа по его индексу. 268 | Если индекс не указан, то удалится и вернется последний элемент. 269 | Args: 270 | index: индекс словаря инфа. 271 | Returns: 272 | кортеж из двух строк - имени и значения словаря. 273 | """ 274 | size_dicts = self.get_dicts_number() 275 | index = index if index is not None else size_dicts - 1 276 | if not size_dicts or index >= size_dicts or index < 0: 277 | raise DPClientException(-1) 278 | size_vars = self.get_vars_number() 279 | current_dicts = self.get_dicts() 280 | dict_name, dict_value = current_dicts.pop(index) 281 | current_vars = self.get_vars() 282 | self.resize(size_vars, size_dicts-1) 283 | for n in range(size_dicts-1): 284 | self.set_dict(n, current_dicts[n][0], current_dicts[n][1]) 285 | for n in range(size_vars): 286 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 287 | return dict_name, dict_value 288 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/others.py: -------------------------------------------------------------------------------- 1 | from pydpclient import get_protocol_version, get_allocated_memory_size,\ 2 | code_to_string 3 | 4 | 5 | def protocol_version() -> int: 6 | """ 7 | Возвращает версию протокола. 8 | Returns: 9 | версия протокола. 10 | """ 11 | return get_protocol_version() 12 | 13 | 14 | def allocated_memory() -> int: 15 | """ 16 | Возвращает размер памяти, аллоцированной под работу библиотеки. 17 | Returns: 18 | число байт занятой памяти. 19 | """ 20 | return get_allocated_memory_size() 21 | 22 | 23 | def return_code_string(ret_code: int) -> str: 24 | """ 25 | Возвращает текстовое описание ошибки. 26 | Args: 27 | ret_code: код ошибки. 28 | Returns: 29 | текстовое описание ошибки. 30 | """ 31 | if 0 < ret_code < -11: 32 | return '' 33 | return code_to_string(ret_code) 34 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/session.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List, Optional 2 | from .exceptions import DPClientException 3 | from pydpclient import SessionDataPointerType, cl_session_create,\ 4 | cl_session_free, cl_session_set_id, cl_session_set_inf_id,\ 5 | cl_session_get_size, cl_session_resize, cl_session_set_var, cl_session_get 6 | 7 | 8 | class Session: 9 | """ 10 | Класс для работы с объектами сессий (которые являются структурами в Си). 11 | Сами объекты типа SessionDataPointerType являются 12 | указателями на структуры в Си. 13 | """ 14 | 15 | session_id = None 16 | inf_id = None 17 | 18 | def __init__( 19 | self, 20 | session_obj: Optional[SessionDataPointerType] = None, 21 | session_id: Optional[int] = None, 22 | inf_id: Optional[int] = None, 23 | session_context: Optional[dict] = None, 24 | ): 25 | """ 26 | Инициализация объекта сессии. Си-структура будет создана, 27 | если не был передан объект типа SessionDataPointerType. 28 | Args: 29 | session_obj: объект-указатель на структуру SessionData. 30 | """ 31 | self.session_obj = session_obj if session_obj is not None \ 32 | else cl_session_create() 33 | if session_id is not None: 34 | self.set_id(session_id) 35 | if inf_id is not None: 36 | self.set_inf_id(inf_id) 37 | if session_context is not None: 38 | for key, value in session_context.items(): 39 | self.append_var(key, value) 40 | 41 | def __del__(self): 42 | """ 43 | Высвобождение занятой объектом памяти (как объектом-указателем, 44 | так и самой стрктурой, расположенной по этому указателю). 45 | """ 46 | ret_code: int = cl_session_free(self.session_obj) 47 | del self.session_obj 48 | if ret_code: 49 | raise DPClientException(ret_code) 50 | 51 | # Базовые функции 52 | 53 | def set_id(self, session_id: int) -> None: 54 | """ 55 | Установка идентификатора сессии. 56 | Args: 57 | session_id: идентификатор сессии 58 | """ 59 | if session_id < 0: 60 | raise DPClientException(-1) 61 | self.session_id = session_id 62 | cl_session_set_id(self.session_obj, session_id) 63 | return 64 | 65 | def get_id(self): 66 | """ 67 | Получение идентификатора сессии. 68 | Returns: 69 | идентификатор сессии. 70 | """ 71 | return self.session_id 72 | 73 | def set_inf_id(self, inf_id: int) -> None: 74 | """ 75 | Установка идентификатора инфа. 76 | Args: 77 | inf_id: идентификатор инфа. 78 | """ 79 | if inf_id < 0: 80 | raise DPClientException(-1) 81 | self.inf_id = inf_id 82 | cl_session_set_inf_id(self.session_obj, inf_id) 83 | return 84 | 85 | def get_inf_id(self): 86 | """ 87 | Получение идентификатора инфа 88 | Returns: 89 | идентификатор инфа. 90 | """ 91 | return self.inf_id 92 | 93 | def get_size(self) -> int: 94 | """ 95 | Получение числа переменных, записанных в объекте сессии. 96 | Returns: 97 | число переменных. 98 | """ 99 | return cl_session_get_size(self.session_obj) 100 | 101 | def resize(self, new_size: int) -> None: 102 | """ 103 | Изменение числа переменных сессии. 104 | При этом старые переменные будут удалены. 105 | Args: 106 | new_size: новое количество переменных. 107 | """ 108 | if new_size < 0: 109 | raise DPClientException(-1) 110 | ret_code = cl_session_resize(self.session_obj, new_size) 111 | if ret_code: 112 | raise DPClientException(ret_code) 113 | return 114 | 115 | def set_var(self, pos: int, var_name: str, var_value: str) -> None: 116 | """ 117 | Установка имени и значения переменной по ее индексу (нумерация с нуля). 118 | Args: 119 | pos: индекс переменной. 120 | var_name: имя переменной. 121 | var_value: значение переменной. 122 | """ 123 | if pos < 0 or pos >= self.get_size(): 124 | raise DPClientException(-1) 125 | cl_session_set_var(self.session_obj, pos, var_name, var_value) 126 | return 127 | 128 | def get_var(self, pos: int) -> Tuple[str, str]: 129 | """ 130 | Получение имени и значения переменной по ее индексу (нумерация с нуля). 131 | Args: 132 | pos: индекс переменной. 133 | Returns: 134 | Кортеж, состоящий из двух строк - имени и значения переменной. 135 | Либо исплючение, если переменная не существует. 136 | """ 137 | if pos < 0 or pos >= self.get_size(): 138 | raise DPClientException(-1) 139 | ret_code, var_name, var_value = cl_session_get(self.session_obj, pos) 140 | if ret_code: 141 | raise DPClientException(ret_code) 142 | return var_name, var_value 143 | 144 | # Расширенные методы 145 | 146 | def get_vars(self) -> List[Tuple[str, str]]: 147 | """ 148 | Получение всех переменных, содержащихся в сессии. 149 | Returns: 150 | Список кортежей, состоящих из двух строк - 151 | имени и значения переменной. 152 | """ 153 | current_vars = list() 154 | size = self.get_size() 155 | for n in range(size): 156 | current_vars.append(self.get_var(n)) 157 | return current_vars 158 | 159 | def append_var(self, var_name: str, var_value: str) -> None: 160 | """ 161 | Добавить переменную в конец с расширением места, отведенного под 162 | переменные сессии. 163 | Args: 164 | var_name: имя переменной. 165 | var_value: значение переменной. 166 | """ 167 | size = self.get_size() 168 | current_vars = self.get_vars() 169 | current_vars.append((var_name, var_value)) 170 | self.resize(size+1) 171 | for n in range(size+1): 172 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 173 | return 174 | 175 | def pop(self, index: Optional[int] = None) -> Tuple[str, str]: 176 | """ 177 | Удалить и вернуть переменную из сессии по ее индексу. 178 | Если не указан индекс - удаление и возврат происходит с конца. 179 | Args: 180 | index: индекс переменной сессии. 181 | Returns: 182 | Кортеж, состоящий из двух строк - имени и значения переменной. 183 | """ 184 | size = self.get_size() 185 | index = index if index is not None else size-1 186 | if not size or index >= size: 187 | raise DPClientException(-1) 188 | current_vars = self.get_vars() 189 | var_name, var_value = current_vars.pop(index) 190 | self.resize(size-1) 191 | for n in range(size-1): 192 | self.set_var(n, current_vars[n][0], current_vars[n][1]) 193 | return var_name, var_value 194 | -------------------------------------------------------------------------------- /client-lib-py/dp_client/test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from .session import Session 3 | from .inf import Inf 4 | from .client import Client 5 | from pydpclient import get_protocol_version, code_to_string,\ 6 | get_allocated_memory_size, cl_session_create, cl_session_set_id,\ 7 | cl_session_set_inf_id, cl_session_get_size, cl_session_resize,\ 8 | cl_session_set_var, cl_session_get, cl_session_free, cl_inf_create,\ 9 | cl_inf_set_id, cl_inf_set_templates, cl_inf_get_vars_cnt,\ 10 | cl_inf_get_dicts_cnt, cl_inf_resize, cl_inf_set_var, cl_inf_get_var,\ 11 | cl_inf_set_dict, cl_inf_get_dict, cl_inf_free, cl_cmd_purge_session,\ 12 | cl_cmd_purge_inf, cl_cmd_send_inf, cl_cmd_init, cl_cmd_send_session,\ 13 | cl_cmd_request, cl_answer_get_size, cl_answer_free 14 | 15 | 16 | @pytest.fixture 17 | def conn_str(request): 18 | return request.config.getoption("--conn_str") 19 | 20 | 21 | class TestOthers: 22 | 23 | def test_protocol_version(self): 24 | assert get_protocol_version() == 6 25 | 26 | def test_code_to_strong(self): 27 | assert code_to_string(1) == '' 28 | assert code_to_string(0) == 'Success' 29 | assert code_to_string(-1) == 'Invalid arguments' 30 | 31 | def test_allocated_memory(self): 32 | assert get_allocated_memory_size() == 0 33 | 34 | 35 | class TestSession: 36 | 37 | session = None 38 | _var_name_session_1 = "variable_name" 39 | _var_name_session_2 = "имя_переменной" 40 | _var_value_session_1 = "variable_value" 41 | _var_value_session_2 = "значение переменной" 42 | 43 | def setup_class(self): 44 | self.session = cl_session_create() 45 | cl_session_set_id(self.session, 1) 46 | cl_session_set_inf_id(self.session, 2) 47 | 48 | def test_resize(self): 49 | assert cl_session_get_size(self.session) == 0 50 | cl_session_resize(self.session, 2) 51 | assert cl_session_get_size(self.session) == 2 52 | 53 | def test_variables(self): 54 | cl_session_set_var( 55 | self.session, 0, 56 | self._var_name_session_1, 57 | self._var_value_session_1, 58 | ) 59 | assert cl_session_get(self.session, 0) == ( 60 | 0, self._var_name_session_1, self._var_value_session_1, 61 | ) 62 | cl_session_set_var( 63 | self.session, 1, 64 | self._var_name_session_2, 65 | self._var_value_session_2, 66 | ) 67 | assert cl_session_get(self.session, 1) == ( 68 | 0, self._var_name_session_2, self._var_value_session_2, 69 | ) 70 | 71 | def teardown_class(self): 72 | assert cl_session_free(self.session) == 0 73 | del self.session 74 | 75 | 76 | class TestInf: 77 | 78 | inf = None 79 | _var_name_inf_1 = "inf_var_name" 80 | _var_name_inf_2 = "имя переменной инфа" 81 | _var_value_inf_1 = "inf_var_value" 82 | _var_value_inf_2 = "значение переменной инфа" 83 | _dict_name_inf_1 = "inf_dict_name" 84 | _dict_name_inf_2 = "имя словаря инфа" 85 | _dict_value_inf_1 = "inf_dict_value" 86 | _dict_value_inf_2 = "значение словаря инфа" 87 | 88 | def setup_class(self): 89 | self.inf = cl_inf_create() 90 | cl_inf_set_id(self.inf, 2) 91 | cl_inf_set_templates(self.inf, "foo") 92 | 93 | def test_resize(self): 94 | assert cl_inf_get_vars_cnt(self.inf) == 0 95 | assert cl_inf_get_dicts_cnt(self.inf) == 0 96 | assert cl_inf_resize(self.inf, 2, 2) == 0 97 | assert cl_inf_get_vars_cnt(self.inf) == 2 98 | assert cl_inf_get_dicts_cnt(self.inf) == 2 99 | 100 | def test_variables(self): 101 | cl_inf_set_var(self.inf, 0, self._var_name_inf_1, self._var_value_inf_1) 102 | cl_inf_set_var(self.inf, 1, self._var_name_inf_2, self._var_value_inf_2) 103 | assert cl_inf_get_var(self.inf, 0) == ( 104 | 0, self._var_name_inf_1, self._var_value_inf_1, 105 | ) 106 | assert cl_inf_get_var(self.inf, 1) == ( 107 | 0, self._var_name_inf_2, self._var_value_inf_2, 108 | ) 109 | 110 | def test_dicts(self): 111 | cl_inf_set_dict( 112 | self.inf, 0, self._dict_name_inf_1, self._dict_value_inf_1, 113 | ) 114 | cl_inf_set_dict( 115 | self.inf, 1, self._dict_name_inf_2, self._dict_value_inf_2, 116 | ) 117 | assert cl_inf_get_dict(self.inf, 0) == ( 118 | 0, self._dict_name_inf_1, self._dict_value_inf_1, 119 | ) 120 | assert cl_inf_get_dict(self.inf, 1) == ( 121 | 0, self._dict_name_inf_2, self._dict_value_inf_2, 122 | ) 123 | 124 | def teardown_class(self): 125 | assert cl_inf_free(self.inf) == 0 126 | del self.inf 127 | 128 | 129 | class TestServer: 130 | 131 | timeout = 1000 132 | pack_flag = 1 133 | 134 | session_id = 1 135 | inf_id = 1 136 | 137 | answer = None 138 | session = None 139 | inf = None 140 | 141 | def setup_class(self): 142 | self.inf = cl_inf_create() 143 | cl_inf_resize(self.inf, 1, 0) 144 | cl_inf_set_id(self.inf, self.inf_id) 145 | cl_inf_set_var(self.inf, 0, "INF_PERSON", "demo") 146 | self.session = cl_session_create() 147 | cl_session_set_id(self.session, self.session_id) 148 | cl_session_set_inf_id(self.session, self.inf_id) 149 | cl_session_resize(self.session, 0) 150 | 151 | def test_cleanup_server(self, conn_str): 152 | if not conn_str: 153 | pytest.skip("No connection string passed") 154 | assert cl_cmd_purge_session( 155 | self.session_id, conn_str, self.timeout, self.pack_flag, 156 | ) == 0 157 | assert cl_cmd_purge_inf( 158 | self.inf_id, conn_str, self.timeout, self.pack_flag, 159 | ) == 0 160 | 161 | def test_send_inf(self, conn_str): 162 | if not conn_str: 163 | pytest.skip("No connection string passed") 164 | assert cl_cmd_send_inf( 165 | self.inf, conn_str, self.timeout, self.pack_flag, 166 | ) == 0 167 | 168 | def test_init_communication(self, conn_str): 169 | if not conn_str: 170 | pytest.skip("No connection string passed") 171 | assert cl_cmd_init( 172 | self.session_id, self.inf_id, 173 | conn_str, self.timeout, self.pack_flag, 174 | ) == (0, 0) 175 | 176 | def test_send_session(self, conn_str): 177 | if not conn_str: 178 | pytest.skip("No connection string passed") 179 | assert cl_cmd_send_session( 180 | self.session, conn_str, self.timeout, self.pack_flag, 181 | ) == 0 182 | 183 | def test_request(self, conn_str): 184 | if not conn_str: 185 | pytest.skip("No connection string passed") 186 | code, self.answer, missed_data_mask = cl_cmd_request( 187 | self.session_id, self.inf_id, "покажи юзерлинк", self.session, 188 | conn_str, self.timeout, self.pack_flag, 189 | ) 190 | assert code == 0 191 | assert self.answer is not None 192 | 193 | def test_answer(self, conn_str): 194 | if not conn_str: 195 | pytest.skip("No connection string passed") 196 | items = cl_answer_get_size(self.answer) 197 | assert items > 0 198 | 199 | def teardown_class(self): 200 | assert cl_session_free(self.session) == 0 201 | del self.session 202 | assert cl_inf_free(self.inf) == 0 203 | del self.inf 204 | if self.answer is not None: 205 | assert cl_answer_free(self.answer) == 0 206 | del self.answer 207 | 208 | 209 | class TestSessionClass: 210 | 211 | session = None 212 | test_var_1 = ("test1", "test2") 213 | test_var_2 = ("test3", "test4") 214 | 215 | def setup_class(self): 216 | self.session = Session() 217 | self.session.set_id(1) 218 | self.session.set_inf_id(1) 219 | 220 | def test_append(self): 221 | assert self.session.get_size() == 0 222 | self.session.append_var(*self.test_var_1) 223 | assert self.session.get_size() == 1 224 | assert self.session.get_var(0) == self.test_var_1 225 | 226 | def test_get_vars(self): 227 | self.session.append_var(*self.test_var_2) 228 | assert self.session.get_vars() == [self.test_var_1, self.test_var_2] 229 | 230 | def test_pop(self): 231 | assert self.session.pop() == self.test_var_2 232 | assert self.session.get_size() == 1 233 | 234 | def test_pop_index(self): 235 | assert self.session.pop(0) == self.test_var_1 236 | assert self.session.get_size() == 0 237 | 238 | def teardown_class(self): 239 | del self.session 240 | 241 | 242 | class TestInfClass: 243 | 244 | inf = None 245 | test_var_1 = ("var1", "var2") 246 | test_var_2 = ("var3", "var4") 247 | test_dict_1 = ("dict1", "dict2") 248 | test_dict_2 = ("dict3", "dict4") 249 | 250 | def setup_class(self): 251 | self.inf = Inf() 252 | self.inf.set_id(1) 253 | 254 | def test_append_var(self): 255 | assert self.inf.get_vars_number() == 0 256 | self.inf.append_var(*self.test_var_1) 257 | assert self.inf.get_vars_number() == 1 258 | assert self.inf.get_var(0) == self.test_var_1 259 | 260 | def test_get_vars(self): 261 | self.inf.append_var(*self.test_var_2) 262 | assert self.inf.get_vars() == [self.test_var_1, self.test_var_2] 263 | 264 | def test_pop_var(self): 265 | assert self.inf.pop_value() == self.test_var_2 266 | assert self.inf.get_vars_number() == 1 267 | 268 | def test_pop_var_index(self): 269 | assert self.inf.pop_value(0) == self.test_var_1 270 | assert self.inf.get_vars_number() == 0 271 | 272 | def test_append_dict(self): 273 | assert self.inf.get_dicts_number() == 0 274 | self.inf.append_dict(*self.test_dict_1) 275 | assert self.inf.get_dicts_number() == 1 276 | assert self.inf.get_dict(0) == self.test_dict_1 277 | 278 | def test_get_dicts(self): 279 | self.inf.append_dict(*self.test_dict_2) 280 | assert self.inf.get_dicts() == [self.test_dict_1, self.test_dict_2] 281 | 282 | def test_pop_dict(self): 283 | assert self.inf.pop_dict() == self.test_dict_2 284 | assert self.inf.get_dicts_number() == 1 285 | 286 | def test_pop_dict_index(self): 287 | assert self.inf.pop_dict(0) == self.test_dict_1 288 | assert self.inf.get_dicts_number() == 0 289 | 290 | def teardown_class(self): 291 | del self.inf 292 | 293 | 294 | class TestConnection: 295 | 296 | session = None 297 | inf = None 298 | client = None 299 | answer = None 300 | 301 | def setup_class(self): 302 | self.session = Session() 303 | self.session.set_id(1) 304 | self.session.set_inf_id(1) 305 | self.inf = Inf() 306 | self.inf.set_id(1) 307 | 308 | def test_cleanup_server(self, conn_str): 309 | self.client = Client(conn_str) 310 | if not conn_str: 311 | pytest.skip("No connection string passed!") 312 | self.client.purge_inf(1) 313 | self.client.purge_session(1) 314 | 315 | def test_send_session(self, conn_str): 316 | if not conn_str: 317 | pytest.skip("No connection string passed!") 318 | Client(conn_str).send_session(self.session) 319 | 320 | def test_send_inf(self, conn_str): 321 | if not conn_str: 322 | pytest.skip("No connection string passed!") 323 | client = Client(conn_str) 324 | client.send_inf(self.inf) 325 | 326 | def test_init(self, conn_str): 327 | if not conn_str: 328 | pytest.skip("No connection string passed!") 329 | client = Client(conn_str) 330 | client.initialize(1, 1) 331 | 332 | def test_request(self, conn_str): 333 | if not conn_str: 334 | pytest.skip("No connection string passed!") 335 | client = Client(conn_str) 336 | self.answer, missed_data_mask = client.request( 337 | self.session, "привет", 338 | ) 339 | assert client.is_success(missed_data_mask) 340 | assert self.answer.get_size() > 0 341 | 342 | def teardown_class(self): 343 | del self.session 344 | del self.inf 345 | del self.client 346 | 347 | 348 | class TestEasy: 349 | 350 | SID = 2 351 | SC = dict() 352 | BID = 1 353 | BC = { 354 | "inf_person": "demo", 355 | "inf_name": '', 356 | } 357 | RQ = "1" 358 | 359 | def test_easy_request(self, conn_str): 360 | if not conn_str: 361 | pytest.skip("No connection string passed!") 362 | self.client = Client(connection_string=conn_str) 363 | ans = self.client.easy_request(self.RQ, self.SID, self.SC, self.BID, self.BC) 364 | assert len(ans["text"]) > 0 365 | 366 | def test_string_postprocessing(self): 367 | test_string = ' Hello , world named " Terra " ! ;( This is test ) .=|:):( ' 368 | check_string = 'Hello, world named "Terra"!; (This is test). =| :) :(' 369 | client = Client() 370 | assert client.string_postprocessing(test_string) == check_string 371 | 372 | def test_easy_update(self, conn_str): 373 | if not conn_str: 374 | pytest.skip("No connection string passed!") 375 | self.client = Client(connection_string=conn_str) 376 | self.client.easy_update(self.SID, self.BID, self.SC) 377 | -------------------------------------------------------------------------------- /client-lib-py/rebuild.sh: -------------------------------------------------------------------------------- 1 | cd client-lib-cpp 2 | make clean 3 | cmake . 4 | cd ClientLib 5 | make 6 | cd ../.. 7 | python3 setup.py build_ext -i 8 | cp *.so dp_client/ 9 | rm *.so -------------------------------------------------------------------------------- /client-lib-py/requirements.txt: -------------------------------------------------------------------------------- 1 | pytest==6.0.1 2 | -------------------------------------------------------------------------------- /client-lib-py/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | pyClientLib_module = Extension( 4 | 'pydpclient', 5 | sources=['pyClientLib.c'], 6 | include_dirs=['client-lib-cpp'], 7 | libraries=[ 8 | "ClientLib", 9 | "stdc++", 10 | ], 11 | library_dirs=["client-lib-cpp/lib"], 12 | ) 13 | 14 | setup( 15 | name='dp_client', 16 | author="Andrey Bibea", 17 | author_email="bibea@nanosemantics.ai", 18 | version='1.0', 19 | ext_modules=[ 20 | pyClientLib_module, 21 | ], 22 | packages=["dp_client"], 23 | ) 24 | -------------------------------------------------------------------------------- /command.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import argparse 3 | import nest_asyncio 4 | 5 | import tortoise 6 | import uuid 7 | 8 | import config 9 | from kernel.tools import get_extension_models 10 | from external_modules.context.models import Infs 11 | from dp_client.client import Client 12 | 13 | 14 | async def show_bots(): 15 | await tortoise.Tortoise.init( 16 | db_url=config.NLAB_SOVA_DB_DSN, 17 | modules={ 18 | 'models': await get_extension_models() 19 | } 20 | ) 21 | # Generate the schema 22 | await tortoise.Tortoise.generate_schemas() 23 | 24 | infs = await Infs.all() 25 | for inf in infs: 26 | print(f"{inf.uuid_str}\t{inf.inf_profile}") 27 | await tortoise.Tortoise.close_connections() 28 | 29 | 30 | async def create(args): 31 | await tortoise.Tortoise.init( 32 | db_url=config.NLAB_SOVA_DB_DSN, 33 | modules={ 34 | 'models': await get_extension_models() 35 | } 36 | ) 37 | # Generate the schema 38 | await tortoise.Tortoise.generate_schemas() 39 | 40 | u = uuid.UUID(args.buid).hex 41 | try: 42 | await Infs.get(uuid=args.buid) 43 | print(f"Бот с идентификатором {args.buid} уже существует") 44 | except tortoise.exceptions.DoesNotExist as err: 45 | inf = Infs(uuid=u, inf_profile=args.profile) 46 | await inf.save() 47 | print(f"Бот успешно создан") 48 | except tortoise.exceptions.BaseORMException as err: 49 | print(f"При создании бота произошла ошибка: {err}") 50 | await tortoise.Tortoise.close_connections() 51 | 52 | 53 | async def change(args): 54 | await tortoise.Tortoise.init( 55 | db_url=config.NLAB_SOVA_DB_DSN, 56 | modules={ 57 | 'models': await get_extension_models() 58 | } 59 | ) 60 | # Generate the schema 61 | await tortoise.Tortoise.generate_schemas() 62 | 63 | try: 64 | inf = await Infs.get(uuid=args.buid) 65 | inf.inf_profile = args.profile 66 | await inf.save() 67 | dp_client = Client(connection_string=config.NLAB_SOVA_ENGINE_HOST) 68 | dp_client.purge_inf(inf_id=inf.id) 69 | print(f"Изменения бота {args.buid} успешно сохранены") 70 | 71 | except tortoise.exceptions.DoesNotExist as err: 72 | print(f"Бот {args.buid} отсутствует") 73 | await tortoise.Tortoise.close_connections() 74 | 75 | 76 | def run_change(args): 77 | nest_asyncio.apply() 78 | asyncio.run(change(args)) 79 | 80 | 81 | def run_create(args): 82 | nest_asyncio.apply() 83 | asyncio.run(create(args)) 84 | 85 | 86 | def run_list(args): 87 | nest_asyncio.apply() 88 | asyncio.run(show_bots()) 89 | 90 | 91 | parser = argparse.ArgumentParser(description='Утилита для управления ботами') 92 | parser.set_defaults(func=run_list) 93 | 94 | subparsers = parser.add_subparsers() 95 | parser_create = subparsers.add_parser('bot:create', help='Создание бота') 96 | parser_change = subparsers.add_parser("bot:change", help='Редактирование бота') 97 | parser_list = subparsers.add_parser("bot:list", help='Список ботов') 98 | 99 | parser_create.add_argument( 100 | '--buid', 101 | default="6944d0b0-ca59-4007-97bf-867d6c4385a9", 102 | type=str, 103 | help="uid бота (по умолчанию '6944d0b0-ca59-4007-97bf-867d6c4385a9')", 104 | ) 105 | parser_create.add_argument( 106 | "--profile", 107 | default='default', 108 | type=str, 109 | help='профиль бота (по умолчанию "default")' 110 | ) 111 | parser_create.set_defaults(func=run_create) 112 | parser_change.add_argument( 113 | '--buid', 114 | default="6944d0b0-ca59-4007-97bf-867d6c4385a9", 115 | type=str, 116 | help="uid бота (по умолчанию '6944d0b0-ca59-4007-97bf-867d6c4385a9')" 117 | ) 118 | parser_change.add_argument( 119 | "--profile", 120 | default='default', 121 | type=str, 122 | help='профиль бота (по умолчанию "default")' 123 | ) 124 | parser_change.set_defaults(func=run_change) 125 | parser_list.set_defaults(func=run_list) 126 | 127 | args = parser.parse_args() 128 | args.func(args) 129 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # Версия 4 | NLAB_SOVA_VERSION = os.getenv('NLAB_SOVA_VERSION') 5 | 6 | # Подключение к Sentry 7 | NLAB_SOVA_SENTRY_DSN = os.getenv('NLAB_SOVA_SENTRY_DSN') 8 | 9 | # Подключение отладки 10 | NLAB_SOVA_DEBUG = os.getenv('NLAB_SOVA_DEBUG', False) 11 | 12 | # Адрес диалогового процессора 13 | NLAB_SOVA_ENGINE_HOST = os.getenv('NLAB_SOVA_ENGINE_HOST', 'tcp:engine:2255') 14 | 15 | # DSN соединения с базой данных 16 | NLAB_SOVA_DB_DSN = os.getenv('NLAB_SOVA_DB_DSN', 'sqlite://var/db/db.sqlite3') 17 | 18 | # Подключенные расширения 19 | NLAB_EXTENSION_PRIORITY = { 20 | "context": { 21 | "context": 0 22 | }, 23 | "context.store": { 24 | "context": 0 25 | }, 26 | "preprocessor": { 27 | "preprocessor": 0, 28 | }, 29 | "postprocessor": { 30 | "postprocessor": 0 31 | }, 32 | "journal": { 33 | "journal": 0 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /external_modules/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sovaai/sova-bls-http-api/9da627d6cb7586eb2bb59528d6e4411a9bbfe7fc/external_modules/__init__.py -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | import sentry_sdk 3 | from sentry_sdk.integrations.aiohttp import AioHttpIntegration 4 | from routes import routes 5 | import config 6 | from tortoise import Tortoise 7 | import logging 8 | from kernel.tools import get_extension_models 9 | 10 | 11 | if config.NLAB_SOVA_DEBUG: 12 | logging.basicConfig(level=logging.DEBUG) 13 | else: 14 | logging.basicConfig(level=logging.INFO) 15 | sentry_sdk.init( 16 | dsn=config.NLAB_SOVA_SENTRY_DSN, 17 | integrations=[AioHttpIntegration()], 18 | release=config.NLAB_SOVA_VERSION 19 | ) 20 | 21 | 22 | async def main_start(): 23 | """ 24 | 1. запуск приложения 25 | :return: 26 | """ 27 | await Tortoise.init( 28 | db_url=config.NLAB_SOVA_DB_DSN, 29 | modules={ 30 | 'models': await get_extension_models() 31 | } 32 | ) 33 | # Generate the schema 34 | await Tortoise.generate_schemas() 35 | app = web.Application(middlewares=[]) 36 | app.add_routes(routes) 37 | return app 38 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aioamqp==0.14.0 2 | aiohttp==3.6.2 3 | async-timeout==3.0.1 4 | asyncpg==0.20.1 5 | attrs==19.3.0 6 | chardet==3.0.4 7 | gunicorn==20.0.4 8 | idna==2.9 9 | importlib-metadata==1.6.0 10 | more-itertools==8.3.0 11 | multidict==4.7.5 12 | packaging==20.3 13 | pamqp==2.3.0 14 | pluggy==0.13.1 15 | py==1.8.2 16 | pyparsing==2.4.7 17 | PyPika==0.37.6 18 | six==1.14.0 19 | tortoise-orm==0.16.10 20 | typing-extensions==3.7.4.2 21 | wcwidth==0.1.9 22 | yarl==1.4.2 23 | zipp==3.1.0 24 | pytest-aiohttp==0.3.0 25 | nest_asyncio==1.3.3 26 | asynctest==0.13.0 27 | sentry-sdk==0.14.1 28 | pytest-mock==3.1.1 29 | pytz -------------------------------------------------------------------------------- /routes.py: -------------------------------------------------------------------------------- 1 | from api import ( 2 | ChatRequest, ChatInit, ChatEvent, CreateInfHelper, CreateChatHelper 3 | ) 4 | from aiohttp import web 5 | 6 | 7 | routes = [ 8 | web.post('/api/Chat.init', ChatInit, name='chat_init'), 9 | web.post('/api/Chat.request', ChatRequest, name='chat_request'), 10 | web.post('/api/Chat.event', ChatEvent, name='chat_event'), 11 | #TODO Вспомогательные методы. Удалить после разработки сервиса 12 | web.post('/api/create_inf', CreateInfHelper, name='create_inf'), 13 | web.post('/api/create_chat', CreateChatHelper, name='create_chat'), 14 | ] 15 | 16 | -------------------------------------------------------------------------------- /run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | until gunicorn main:main_start --reload --bind 0.0.0.0:8080 --worker-class aiohttp.worker.GunicornWebWorker 2>/dev/null; do 3 | echo "Database is unavailable - sleeping (10s)" 4 | sleep 10 5 | done -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from .test_init import TestInitEndpoint 2 | from .test_request import TestRequestEndpoint -------------------------------------------------------------------------------- /tests/test_init.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | import nest_asyncio 3 | from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop 4 | from tortoise.contrib.test import initializer, finalizer 5 | from external_modules.context.models import (Infs, Chat) 6 | from routes import routes 7 | from uuid import uuid4 8 | from kernel.tools import get_extension_models 9 | 10 | 11 | class TestInitEndpoint(AioHTTPTestCase): 12 | """ 13 | 14 | """ 15 | async def setUpAsync(self) -> None: 16 | # db_url=config.DB_TEST_URL, 17 | initializer(await get_extension_models(), loop=self.loop) 18 | 19 | async def tearDownAsync(self) -> None: 20 | finalizer() 21 | 22 | async def get_application(self): 23 | nest_asyncio.apply() 24 | app = web.Application() 25 | app.add_routes(routes) 26 | return app 27 | 28 | @unittest_run_loop 29 | async def test_init_withoid_ciud_uuid_not_exist(self): 30 | """ 31 | Проверяем эндпоинт когда не передается cuid и нет передаваемого uuid 32 | в базе данных 33 | :return: 34 | """ 35 | resp = await self.client.post( 36 | '/api/Chat.init', 37 | json={ 38 | "uuid": "c8054942-933c-4cc7-9327-2e7774735971", 39 | "context": {} 40 | } 41 | ) 42 | self.assertEqual(resp.status, 400) 43 | 44 | @unittest_run_loop 45 | async def test_init_withoid_ciud_with_exist_uuid(self): 46 | """ 47 | Проверяем эндпоинт когда не передается cuid и в базе данных uuid есть 48 | :return: 49 | """ 50 | inf = Infs(uuid=uuid4(), inf_profile='test') 51 | await inf.save() 52 | 53 | resp = await self.client.post( 54 | '/api/Chat.init', 55 | json={ 56 | "uuid": inf.uuid_str, 57 | "context": {} 58 | } 59 | ) 60 | self.assertEqual(resp.status, 200) 61 | 62 | @unittest_run_loop 63 | async def test_init_with_ciud_and_uuid(self): 64 | """ 65 | Проверяем эндпоинт когда передается cuid и в базе данных uuid есть 66 | :return: 67 | """ 68 | inf = Infs(uuid=uuid4(), inf_profile='test') 69 | await inf.save() 70 | cuid = uuid4().__str__() 71 | 72 | resp = await self.client.post( 73 | '/api/Chat.init', 74 | json={ 75 | "cuid": cuid, 76 | "uuid": inf.uuid_str, 77 | "context": {} 78 | } 79 | ) 80 | self.assertEqual(resp.status, 400) 81 | 82 | @unittest_run_loop 83 | async def test_init_with_ciud_and_uuid_exist(self): 84 | """ 85 | Проверяем эндпоинт когда передается cuid и в базе данных uuid, cuid есть 86 | :return: 87 | """ 88 | inf = Infs(uuid=uuid4(), inf_profile='test') 89 | await inf.save() 90 | 91 | chat = Chat(inf=inf) 92 | await chat.save() 93 | 94 | resp = await self.client.post( 95 | '/api/Chat.init', 96 | json={ 97 | "cuid": chat.cuid.__str__(), 98 | "uuid": inf.uuid_str, 99 | "context": {} 100 | } 101 | ) 102 | self.assertEqual(resp.status, 200) -------------------------------------------------------------------------------- /tests/test_request.py: -------------------------------------------------------------------------------- 1 | from aiohttp import web 2 | import nest_asyncio 3 | from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop 4 | from tortoise.contrib.test import initializer, finalizer 5 | from external_modules.context.models import (Infs, Chat) 6 | from routes import routes 7 | from kernel.tools import get_extension_models 8 | 9 | 10 | class TestRequestEndpoint(AioHTTPTestCase): 11 | """ 12 | 13 | """ 14 | async def setUpAsync(self) -> None: 15 | # db_url=config.DB_TEST_URL, 16 | initializer(await get_extension_models(), loop=self.loop) 17 | 18 | async def tearDownAsync(self) -> None: 19 | finalizer() 20 | 21 | async def get_application(self): 22 | nest_asyncio.apply() 23 | app = web.Application() 24 | app.add_routes(routes) 25 | return app 26 | 27 | @unittest_run_loop 28 | async def test_request_point_cuid_not_exist(self): 29 | """ 30 | Для не существующего чата 31 | :return: 32 | """ 33 | resp = await self.client.post( 34 | '/api/Chat.request', 35 | json={ 36 | "cuid": "5d446bf7-1b32-4d2a-ad1f-d746c609ecc9", 37 | "text": "\u041d\u0435\u0442", 38 | "context": { 39 | "isDevice": False, 40 | "sys.rid": "0f0fd80d-c017-4ea6-a738-595ad7420012" 41 | } 42 | } 43 | ) 44 | self.assertEqual(resp.status, 400) 45 | 46 | @unittest_run_loop 47 | async def test_request_point_cuid_exist(self): 48 | """ 49 | Для существующего чата. 50 | :return: 51 | """ 52 | inf = Infs(inf_profile='test') 53 | await inf.save() 54 | chat = Chat(inf=inf) 55 | await chat.save() 56 | resp = await self.client.post( 57 | '/api/Chat.request', 58 | json={ 59 | "cuid": chat.cuid_str, 60 | "text": "\u041d\u0435\u0442", 61 | "context": { 62 | "isDevice": False, 63 | "sys.rid": "0f0fd80d-c017-4ea6-a738-595ad7420012" 64 | } 65 | } 66 | ) 67 | self.assertEqual(resp.status, 200) --------------------------------------------------------------------------------