├── .gitignore ├── tasks ├── oscript.cfg └── test.os ├── docs ├── error.jpg └── http.jpg ├── features ├── nssm64_oproxy.exe └── ПроверкиПроксиСервера_Пример.os ├── src ├── Классы │ ├── ЛогАннотация.os │ ├── cli_ЗапускДемона.os │ ├── cli_ОстановкаДемона.os │ ├── cli_ПерезапускДемона.os │ ├── cli_УдалитьДемона.os │ ├── cli_ПроверкаФайла.os │ ├── cli_ЗапускСервера.os │ ├── cli_СозданиеДемона.os │ ├── cli_ОписаниеПриложения.os │ ├── cli_Инициализация.os │ ├── ЗапускательСервера.os │ └── ОбработчикСоединений.os ├── main.os ├── ОтладкаСервера.os └── Модули │ ├── РаботаСФайломПроверок.os │ ├── РаботаСДемоном.os │ └── ОбработкаДанных.os ├── tests ├── ДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище.dat ├── ДвоичныеДанныеЗапросаКонфигуратораНаИзменениеВерсииВХранилище.dat └── Тесты.os ├── .github └── workflows │ ├── release.yml │ └── test.yml ├── packagedef ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | 3 | .vscode 4 | *.ospx 5 | -------------------------------------------------------------------------------- /tasks/oscript.cfg: -------------------------------------------------------------------------------- 1 | lib.additional=../oscript_modules -------------------------------------------------------------------------------- /docs/error.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscript-library/oproxy/HEAD/docs/error.jpg -------------------------------------------------------------------------------- /docs/http.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscript-library/oproxy/HEAD/docs/http.jpg -------------------------------------------------------------------------------- /features/nssm64_oproxy.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscript-library/oproxy/HEAD/features/nssm64_oproxy.exe -------------------------------------------------------------------------------- /src/Классы/ЛогАннотация.os: -------------------------------------------------------------------------------- 1 | &Аннотация("ЛогОпрокси") 2 | &Лог("oscript.lib.oproxy") 3 | Процедура ПриСозданииОбъекта() 4 | 5 | КонецПроцедуры -------------------------------------------------------------------------------- /tests/ДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oscript-library/oproxy/HEAD/tests/ДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище.dat -------------------------------------------------------------------------------- /src/main.os: -------------------------------------------------------------------------------- 1 | #Использовать autumn 2 | #Использовать autumn-cli 3 | #Использовать autumn-logos 4 | #Использовать ".." 5 | 6 | Поделка = Новый Поделка; 7 | КаталогМодуля = ОбъединитьПути(ТекущийСценарий().Каталог, "Классы"); 8 | Поделка.ПросканироватьКаталог(КаталогМодуля); 9 | Поделка.ЗапуститьПриложение(); -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Публикация релиза 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | workflow_dispatch: 8 | 9 | jobs: 10 | release: 11 | uses: autumn-library/workflows/.github/workflows/release.yml@main 12 | with: 13 | package_mask: "oproxy-*.ospx" 14 | secrets: 15 | PUSH_TOKEN: ${{ secrets.PUSH_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Тестирование 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | test: 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | oscript_version: ['default'] 14 | uses: autumn-library/workflows/.github/workflows/test.yml@main 15 | with: 16 | oscript_version: ${{ matrix.oscript_version }} 17 | -------------------------------------------------------------------------------- /src/ОтладкаСервера.os: -------------------------------------------------------------------------------- 1 | #Использовать autumn 2 | #Использовать ".." 3 | 4 | ТестовыйКаталог = "D:\oprtcat"; 5 | УстановитьТекущийКаталог(ТестовыйКаталог); 6 | 7 | Поделка = Новый Поделка; 8 | КаталогМодуля = ОбъединитьПути(ТекущийСценарий().Каталог, "Классы"); 9 | Поделка.ПросканироватьКаталог(КаталогМодуля); 10 | Поделка.ЗапуститьПриложение(); 11 | 12 | Запускатель = Поделка.НайтиЖелудь("ЗапускательСервера"); 13 | Запускатель.ПортПрокси = 2555; 14 | Запускатель.АдресСервера = "1cpresent"; 15 | Запускатель.ПортСервера = 2544; 16 | Запускатель.Запустить(); -------------------------------------------------------------------------------- /src/Классы/cli_ЗапускДемона.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "dn daemon-name", Описание = "(необязательный) кастомное имя демона, в случае когда надо настроить несколько демонов. По умолчанию OproxyDaemon.") 2 | &ТСтрока 3 | Перем ИмяДемона Экспорт; 4 | 5 | &КомандаПриложения(Имя = "start-daemon", Описание = "Запуск службы Windows под названием OproxyDaemon (или кастомным), созданной с помощью команды create-daemon") 6 | Процедура ПриСозданииОбъекта() 7 | КонецПроцедуры 8 | 9 | &ВыполнениеКоманды 10 | Процедура ЗапуститьДемона() Экспорт 11 | РаботаСДемоном.ИмяДемона = ИмяДемона; 12 | РаботаСДемоном.Запустить(); 13 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/cli_ОстановкаДемона.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "dn daemon-name", Описание = "(необязательный) кастомное имя демона, в случае когда надо настроить несколько демонов. По умолчанию OproxyDaemon.") 2 | &ТСтрока 3 | Перем ИмяДемона Экспорт; 4 | 5 | &КомандаПриложения(Имя = "stop-daemon", Описание = "Остановка службы Windows под названием OproxyDaemon (или кастомным), созданной с помощью команды create-daemon") 6 | Процедура ПриСозданииОбъекта() 7 | КонецПроцедуры 8 | 9 | &ВыполнениеКоманды 10 | Процедура ОстановитьДемона() Экспорт 11 | РаботаСДемоном.ИмяДемона = ИмяДемона; 12 | РаботаСДемоном.Остановить(); 13 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/cli_ПерезапускДемона.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "dn daemon-name", Описание = "(необязательный) кастомное имя демона, в случае когда надо настроить несколько демонов. По умолчанию OproxyDaemon.") 2 | &ТСтрока 3 | Перем ИмяДемона Экспорт; 4 | 5 | &КомандаПриложения(Имя = "restart-daemon", Описание = "Перезапуск службы Windows под названием OproxyDaemon (или кастомным), созданной с помощью команды create-daemon") 6 | Процедура ПриСозданииОбъекта() 7 | КонецПроцедуры 8 | 9 | &ВыполнениеКоманды 10 | Процедура ПерезапуститьДемона() Экспорт 11 | РаботаСДемоном.ИмяДемона = ИмяДемона; 12 | РаботаСДемоном.Перезапустить(); 13 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/cli_УдалитьДемона.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "dn daemon-name", Описание = "(необязательный) кастомное имя демона, в случае когда надо настроить несколько демонов. По умолчанию OproxyDaemon.") 2 | &ТСтрока 3 | Перем ИмяДемона Экспорт; 4 | 5 | &КомандаПриложения(Имя = "rd remove-daemon", Описание = "Остановка и удаление службы Windows под названием OproxyDaemon (или кастомным), созданной с помощью команды create-daemon") 6 | Процедура ПриСозданииОбъекта() 7 | КонецПроцедуры 8 | 9 | &ВыполнениеКоманды 10 | Процедура УдалитьДемона() Экспорт 11 | РаботаСДемоном.ИмяДемона = ИмяДемона; 12 | РаботаСДемоном.Удалить(); 13 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/cli_ПроверкаФайла.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "file", Описание = "(необязательный) Путь к файлу с проверками. По умолчанию ищется файл 'ПроверкиПроксиСервера.os' в текущем каталоге, но вы можете указать собственный путь к файлу") 2 | &ТСтрока 3 | Перем ПутьКФайлуПроверок Экспорт; 4 | 5 | &КомандаПриложения(Имя = "check-file", Описание = "Проверка файла проверок") 6 | Процедура ПриСозданииОбъекта() 7 | КонецПроцедуры 8 | 9 | &ВыполнениеКоманды 10 | Процедура ПроверитьФайл() Экспорт 11 | Если РаботаСФайломПроверок.Подключить(ПутьКФайлуПроверок) <> Неопределено Тогда 12 | Сообщить(СтрШаблон("Файл в порядке, все ОК: %1", ПутьКФайлуПроверок)); 13 | КонецЕсли; 14 | КонецПроцедуры -------------------------------------------------------------------------------- /packagedef: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////// 2 | // Описание пакета для сборки и установки 3 | // Полную документацию см. на hub.oscript.io/packaging 4 | // 5 | 6 | 7 | Описание.Имя("oproxy") 8 | .Версия("0.0.7") 9 | .Автор("Юрий Камисов") 10 | .АдресАвтора("https://github.com/infina15") 11 | .Описание("TCP прокси-сервер хранилища конфигураций 1С") 12 | .ВерсияСреды("1.9.2") 13 | .ВключитьФайл("src") 14 | .ВключитьФайл("tests") 15 | .ВключитьФайл("tasks") 16 | .ВключитьФайл("features") 17 | .ВключитьФайл("packagedef") 18 | .ЗависитОт("autumn", "4.0.0") 19 | .ЗависитОт("autumn-cli", "1.0.6") 20 | .ЗависитОт("autumn-logos", "1.2.0") 21 | .ЗависитОт("asserts", "1.4.0") 22 | .ЗависитОт("1commands", "1.5.0") 23 | .РазработкаЗависитОт("1testrunner") 24 | .ИсполняемыйФайл("src/main.os", "oproxy") 25 | ; 26 | -------------------------------------------------------------------------------- /tasks/test.os: -------------------------------------------------------------------------------- 1 | #Использовать 1testrunner 2 | #Использовать fs 3 | 4 | Функция ПрогнатьТесты() 5 | 6 | Тестер = Новый Тестер; 7 | Тестер.УстановитьФорматЛогФайла(Тестер.ФорматыЛогФайла().GenericExec); 8 | 9 | ПутьКТестам = "tests"; 10 | ПутьКОтчетуJUnit = "out"; 11 | 12 | ФС.ОбеспечитьПустойКаталог(ПутьКОтчетуJUnit); 13 | 14 | РезультатТестирования = Тестер.ТестироватьКаталог( 15 | Новый Файл(ПутьКТестам), 16 | Новый Файл(ПутьКОтчетуJUnit) 17 | ); 18 | 19 | Успешно = РезультатТестирования = 0; 20 | 21 | Возврат Успешно; 22 | КонецФункции // ПрогнатьТесты() 23 | 24 | // основной код 25 | 26 | ТекКаталог = ТекущийКаталог(); 27 | 28 | Попытка 29 | ТестыПрошли = ПрогнатьТесты(); 30 | Исключение 31 | ТестыПрошли = Ложь; 32 | Сообщить(СтрШаблон("Тесты через 1testrunner выполнены неудачно 33 | |%1", ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()))); 34 | КонецПопытки; 35 | 36 | УстановитьТекущийКаталог(ТекКаталог); 37 | 38 | Если Не ТестыПрошли Тогда 39 | ВызватьИсключение "Тестирование завершилось неудачно!"; 40 | Иначе 41 | Сообщить(СтрШаблон("Результат прогона тестов <%1> 42 | |", ТестыПрошли)); 43 | КонецЕсли; -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 infina15 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Классы/cli_ЗапускСервера.os: -------------------------------------------------------------------------------- 1 | &Пластилин 2 | //Запускатель сервера 3 | Перем ЗапускательСервера; 4 | 5 | &Опция(Имя = "proxy-port", Описание = "Порт, который будет слушать прокси-сервер. К этому порту будет подключаться конфигуратор. Порт должен быть открыт в фаерволе, если вы подключаетесь к хранилищу по сети") 6 | &ТЧисло 7 | &Обязательный 8 | Перем ПортПрокси Экспорт; 9 | 10 | &Опция(Имя = "storage-server", Описание = "Адрес вашего сервера хранилища без tcp:// и прочих слешей и портов (порт - следующий параметр). Если сервер располагается на той же машине, на которой запущен прокси-сервер, укажите localhost или 127.0.0.1") 11 | &ТСтрока 12 | &Обязательный 13 | Перем АдресСервера Экспорт; 14 | 15 | &Опция(Имя = "storage-port", Описание = "Порт вашего сервера хранилища, указанного в предыдущем параметре. Например 1542") 16 | &ТЧисло 17 | &Обязательный 18 | Перем ПортСервера Экспорт; 19 | 20 | &Опция(Имя = "check-file", Описание = "(необязательный) Путь к файлу с проверками. По умолчанию ищется файл 'ПроверкиПроксиСервера.os' в текущем каталоге, но вы можете указать собственный путь к файлу") 21 | &ТСтрока 22 | Перем ПутьКФайлуПроверок Экспорт; 23 | 24 | 25 | &КомандаПриложения(Имя = "s start", Описание = "Запуск сервера") 26 | Процедура ПриСозданииОбъекта() 27 | КонецПроцедуры 28 | 29 | &ВыполнениеКоманды 30 | Процедура Запустить() Экспорт 31 | Сообщить("Запуск TCP прокси-сервера хранилища 1С"); 32 | Сообщить("Для остановки прокси-сервера нажмите Ctrl+C"); 33 | ЗапускательСервера.ПортПрокси = ПортПрокси; 34 | ЗапускательСервера.АдресСервера = АдресСервера; 35 | ЗапускательСервера.ПортСервера = ПортСервера; 36 | ЗапускательСервера.ПутьКФайлуПроверок = ПутьКФайлуПроверок; 37 | ЗапускательСервера.Запустить(); 38 | КонецПроцедуры -------------------------------------------------------------------------------- /tests/ДвоичныеДанныеЗапросаКонфигуратораНаИзменениеВерсииВХранилище.dat: -------------------------------------------------------------------------------- 1 | POST HTTP/1.1 2 | Content-Length: 1768 3 | Content-Type: application/xml 4 | Accept: application/xml 5 | 6 | 121комментарий был121121Комментарий стал121Комментарий меткиfS�� -------------------------------------------------------------------------------- /src/Классы/cli_СозданиеДемона.os: -------------------------------------------------------------------------------- 1 | #Использовать 1commands 2 | &Опция(Имя = "proxy-port", Описание = "Порт, который будет слушать прокси-сервер. К этому порту будет подключаться конфигуратор. Порт должен быть открыт в фаерволе, если вы подключаетесь к хранилищу по сети") 3 | &ТЧисло 4 | &Обязательный 5 | Перем ПортПрокси Экспорт; 6 | 7 | &Опция(Имя = "storage-server", Описание = "Адрес вашего сервера хранилища без tcp:// и прочих слешей и портов (порт - следующий параметр). Если сервер располагается на той же машине, на которой запущен прокси-сервер, укажите localhost или 127.0.0.1") 8 | &ТСтрока 9 | &Обязательный 10 | Перем АдресСервера Экспорт; 11 | 12 | &Опция(Имя = "storage-port", Описание = "Порт вашего сервера хранилища, указанного в предыдущем параметре. Например 1542") 13 | &ТЧисло 14 | &Обязательный 15 | Перем ПортСервера Экспорт; 16 | 17 | &Опция(Имя = "check-file", Описание = "Полный путь к файлу с проверками") 18 | &ТСтрока 19 | &Обязательный 20 | Перем ПутьКФайлуПроверок Экспорт; 21 | 22 | &Опция(Имя = "dn daemon-name", Описание = "(необязательный) кастомное имя демона, в случае когда надо настроить несколько демонов. По умолчанию OproxyDaemon.") 23 | &ТСтрока 24 | Перем ИмяДемона Экспорт; 25 | 26 | &КомандаПриложения(Имя = "cd create-daemon", Описание = "Создание и запуск службы Windows под названием OproxyDaemon (или кастомным). Служба будет запускать прокси с заданными параметрами") 27 | Процедура ПриСозданииОбъекта() 28 | КонецПроцедуры 29 | 30 | &ВыполнениеКоманды 31 | Процедура СоздатьИЗапуститьДемона() Экспорт 32 | СтрокаПараметров = СтрШаблон("oproxy.bat start --proxy-port %1 --storage-server %2 --storage-port %3 --check-file %4", 33 | ПортПрокси, 34 | АдресСервера, 35 | ПортСервера, 36 | ПутьКФайлуПроверок); 37 | РаботаСДемоном.ИмяДемона = ИмяДемона; 38 | РаботаСДемоном.СоздатьИЗапустить(СтрокаПараметров); 39 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/cli_ОписаниеПриложения.os: -------------------------------------------------------------------------------- 1 | &Желудь("ОписаниеКонсольногоПриложения") 2 | &Верховный 3 | Процедура ПриСозданииОбъекта() 4 | КонецПроцедуры 5 | 6 | Функция ИмяПриложения() Экспорт 7 | Возврат "oproxy"; 8 | КонецФункции 9 | 10 | Функция ПолноеИмяПриложения() Экспорт 11 | Возврат 12 | " 13 | | TCP прокси сервер для хранилища 1С на чистом OneScript. 14 | | 15 | | Перехватывает общение конфигуратора и хранилища по протоколу TCP, 16 | | события хранилища о помещении и редактировании версии. 17 | | Имеется возможность написать свою логику на языке OneScript (1С). 18 | | Проверки комментариев, запреты, веб-хуки - все что угодно :) 19 | | 20 | | С чего начать: 21 | | 22 | | 1. Создайте новый каталог на диске или выберите существующий, 23 | | в котором будет храниться файл ПроверкиПроксиСервера.os для прокси-сервера с вашим 24 | | кодом 1С для проверок/веб-хуков/анекдотов. 25 | | 26 | | 2. В командной строке перейдите в этот каталог (cd C:\МойКаталогДляПрокси). 27 | | 28 | | 3. Воспользуйтесь командой oproxy init. Она создаст файл ""ПроверкиПроксиСервера.os"" 29 | | в текущем каталоге (если его не существует в каталоге). 30 | | 31 | | 4. Вы великолепны! Начиная с этого момента можно воспользоваться командой oproxy start 32 | | и запустить прокси-сервер! Обращаться из конфигуратора по порту прокси к своему хранилищу. 33 | | Только вызовы пока что перехватываются впустую, наших собственных проверок и веб-хуков еще нет. 34 | | 35 | | 5. Но мы здесь из-за проверок веб-хуков. Поэтому рекомендую зайти в ваш каталог из п.2 36 | | и посмотреть как устроен файл ПроверкиПроксиСервера.os. В нем вы можете написать 37 | | свои проверки/веб-хуки/вызовы/драмы. После редактирования файла перезапустите прокси-сервер, 38 | | если он запущен, для того чтобы правила начали работать. 39 | |"; 40 | КонецФункции 41 | 42 | Функция ВерсияПриложения() Экспорт 43 | Возврат "0.0.3"; 44 | КонецФункции -------------------------------------------------------------------------------- /src/Классы/cli_Инициализация.os: -------------------------------------------------------------------------------- 1 | &Опция(Имя = "f force", Описание = "(необязательный) перезаписывает существующий файл ПроверкиПроксиСервера") 2 | &ТБулево 3 | Перем Насильно Экспорт; 4 | 5 | &Опция(Имя = "fp file-path", Описание = "(необязательный) полный путь к файлу проверок, если не хотите создавать в текущем каталоге") 6 | &ТСтрока 7 | Перем ПутьКФайлуПользователя Экспорт; 8 | 9 | &КомандаПриложения(Имя = "i init", Описание = "Инициализация каталога. По умолчанию будет создан файл ""ПроверкиПроксиСервера.os"" в текущием каталоге (если файл отсутствует). Если файл существует, будет ошибка.") 10 | Процедура ПриСозданииОбъекта() 11 | КонецПроцедуры 12 | 13 | &ВыполнениеКоманды 14 | Процедура Инициализировать() Экспорт 15 | ИмяМодуля = "ПроверкиПроксиСервера"; 16 | ИмяФайла = СтрШаблон("%1.os", ИмяМодуля); 17 | ПутьКФайлу = ""; 18 | Если ЗначениеЗаполнено(ПутьКФайлуПользователя) Тогда 19 | ПутьКФайлу = ПутьКФайлуПользователя; 20 | Иначе 21 | ПутьКФайлу = ОбъединитьПути(ТекущийКаталог(), ИмяФайла); 22 | КонецЕсли; 23 | Файл = Новый Файл(ПутьКФайлу); 24 | Если Насильно <> Истина И Файл.Существует() Тогда 25 | ТекстОшибки = СтрШаблон("Невозможно добавить %1, так как он уже существует. 26 | |Чтобы не потерять ваши существующие правила, переместите его в другое место. 27 | |Сделайте бэкап, переименуйте, что угодно! 28 | |Для перезаписи существующего файла можно использовать параметр --force", ПутьКФайлу); 29 | Сообщить(ТекстОшибки); 30 | Возврат; 31 | КонецЕсли; 32 | ЧтоЗаменить = ОбъединитьПути("src", "Классы"); 33 | НаЧтоЗаменить = ОбъединитьПути("features", СтрШаблон("%1_Пример.os", ИмяМодуля)); 34 | Откуда = СтрЗаменить(ТекущийСценарий().Каталог, ЧтоЗаменить, НаЧтоЗаменить); 35 | Попытка 36 | КопироватьФайл(Откуда, ПутьКФайлу); 37 | Сообщить(СтрШаблон("Инициализация проведена! Открывайте файл %1 и вносите свои правила и веб-хуки!", ПутьКФайлу)); 38 | Исключение 39 | Сообщить(СтрШаблон("Не удалось скопировать файл из %1 в %2 по причине: %3", Откуда, ПутьКФайлу, ОписаниеОшибки())); 40 | КонецПопытки; 41 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/ЗапускательСервера.os: -------------------------------------------------------------------------------- 1 | &Пластилин Перем ОбработчикСоединений; 2 | //АдресСервера 3 | Перем АдресСервера Экспорт; 4 | //ПортСервера 5 | Перем ПортСервера Экспорт; 6 | //ПортПрокси 7 | Перем ПортПрокси Экспорт; 8 | //ПутьКФайлуПроверок 9 | Перем ПутьКФайлуПроверок Экспорт; 10 | 11 | &Желудь 12 | Процедура ПриСозданииОбъекта() 13 | КонецПроцедуры 14 | 15 | Процедура Запустить() Экспорт 16 | ОбъектПроверок = РаботаСФайломПроверок.Подключить(ПутьКФайлуПроверок); 17 | Если ОбъектПроверок = Неопределено Тогда 18 | Возврат; 19 | КонецЕсли; 20 | Попытка 21 | Сервер = Новый TCPСервер(ПортПрокси); 22 | Сервер.Запустить(); 23 | Шаблон = "Прокси-сервер запущен на порту %1 к хранилищу tcp://%2:%3"; 24 | Сообщить(СтрШаблон(Шаблон, ПортПрокси, АдресСервера, ПортСервера)); 25 | Исключение 26 | Шаблон = 27 | " 28 | |################################################################################### 29 | | >>> Ошибка запуска прокси-сервера на порту %1 к хранилищу tcp://%2:%3 30 | | >>> Возможно, порт %1 занят другой программой (или запущенным экземпляром этой) 31 | |################################################################################### 32 | | 33 | |%4"; 34 | Сообщить(СтрШаблон(Шаблон, ПортПрокси, АдресСервера, ПортСервера, ОписаниеОшибки())); 35 | КонецПопытки; 36 | ОбработчикСоединений.ПроверкиПроксиСервера = ОбъектПроверок; 37 | ОбработчикСоединений.АдресСервера = АдресСервера; 38 | ОбработчикСоединений.ПортСервера = ПортСервера; 39 | Пока Истина Цикл 40 | Если РаботаСФайломПроверок.ФайлПроверокИзменился(ПутьКФайлуПроверок) Тогда 41 | ОбъектПроверок = РаботаСФайломПроверок.Подключить(ПутьКФайлуПроверок); 42 | Если ОбъектПроверок = Неопределено Тогда 43 | Сообщить("Не удалось подключить измененный файл %1, прокси-сервер остановлен."); 44 | Сервер.Остановить(); 45 | Возврат; 46 | Иначе 47 | ОбработчикСоединений.ПроверкиПроксиСервера = ОбъектПроверок; 48 | Сообщить(СтрШаблон("Сценарий файла проверок перезагружен так как был изменен: %1", ПутьКФайлуПроверок)); 49 | КонецЕсли; 50 | КонецЕсли; 51 | Соединение = Сервер.ОжидатьСоединения(); 52 | МассивПараметров = Новый Массив; 53 | МассивПараметров.Добавить(Соединение); 54 | ФоновыеЗадания.Выполнить(ОбработчикСоединений, "ОбработатьСоединение", МассивПараметров); 55 | КонецЦикла; 56 | КонецПроцедуры 57 | -------------------------------------------------------------------------------- /features/ПроверкиПроксиСервера_Пример.os: -------------------------------------------------------------------------------- 1 | //Этот файл можно изменять во время работы прокси-сервера. После записи/изменения он подгрузится в сервер автоматически 2 | //Это файл, в котором вы можете писать свои проверки при работе с хранилищем, веб-хуки, да и вообще что захотите. 3 | // 4 | //В этом модуле есть экспортные функции: 5 | // 6 | // ОбработкаПомещенияВХранилище() - работает в момент, когда пользователь в конфигураторе нажал "поместить в хранилище", 7 | // ввел комментарий (или не ввел), и нажал ОК. Если в переменной СообщениеОбОшибке вы установите непустую строку, 8 | // то эта строка вернется ошибкой в конфигуратор и помещения в хранилище не произойдет. 9 | // Если переменная СообщениеОбОшибке останется пустой строкой - будет произведено помещение в хранилище. 10 | // 11 | // ОбработкаИзмененияВерсииХранилища() - работает в момент, когда пользователь в конфигураторе открыл версию хранилища в истории хранилища, 12 | // ввел комментарий (или не ввел), и нажал ОК. Если в переменной СообщениеОбОшибке вы установите непустую строку, 13 | // то эта строка вернется ошибкой в конфигуратор и изменения версии не произойдет. 14 | // Если переменная СообщениеОбОшибке останется пустой строкой - будет произведено изменение в версии хранилища. 15 | // 16 | //ПРЕДУПРЕЖДЕНИЕ: все то, что написано между комментариями 17 | // СИСТЕМНЫЙ КОД +++ и //СИСТЕМНЫЙ КОД --- 18 | // Изменять строго не рекомендуется! Пишите свой код, вызовы, и прочее внутри функций. Создавайте свои функции и вызывайте из этих двух, 19 | // в зависимости от потребности. 20 | // Не удаляйте функции, не редактируйте их, их параметры - это приведет к ошибке работы приложения. 21 | // Изменять ЗНАЧЕНИЯ параметров функций можно (они прокси-серверу далее не нужны). Имена и расположение и свойства параметров менять нельзя. 22 | 23 | //СИСТЕМНЫЙ КОД +++ 24 | Функция ОбработкаПомещенияВХранилище(ПараметрыЗапроса) Экспорт 25 | СообщениеОбОшибке = ""; 26 | //СИСТЕМНЫЙ КОД --- 27 | 28 | //здесь можно написать свой код 29 | 30 | //СИСТЕМНЫЙ КОД +++ 31 | Возврат СообщениеОбОшибке; 32 | КонецФункции 33 | //СИСТЕМНЫЙ КОД --- 34 | 35 | //СИСТЕМНЫЙ КОД +++ 36 | Функция ОбработкаИзмененияВерсииХранилища(ПараметрыЗапроса) Экспорт 37 | СообщениеОбОшибке = ""; 38 | //СИСТЕМНЫЙ КОД --- 39 | 40 | //здесь можно написать свой код 41 | 42 | //СИСТЕМНЫЙ КОД +++ 43 | Возврат СообщениеОбОшибке; 44 | КонецФункции 45 | //СИСТЕМНЫЙ КОД --- 46 | 47 | //СИСТЕМНЫЙ КОД +++ 48 | Функция ПостОбработкаПомещенияВХранилище(ПараметрыЗапроса) Экспорт 49 | РезультатБулево = Истина; 50 | //СИСТЕМНЫЙ КОД --- 51 | 52 | //здесь можно написать свой код 53 | 54 | //СИСТЕМНЫЙ КОД +++ 55 | Возврат РезультатБулево; 56 | КонецФункции 57 | //СИСТЕМНЫЙ КОД --- 58 | 59 | //здесь можно написать свои функции, которые можно вызвать из предыдущих двух 60 | -------------------------------------------------------------------------------- /src/Модули/РаботаСФайломПроверок.os: -------------------------------------------------------------------------------- 1 | Перем ДатаИзмененияФайла; 2 | 3 | Функция ИмяТипаПоУмолчанию() Экспорт 4 | Возврат "ПроверкиПроксиСервера"; 5 | КонецФункции 6 | Функция ИмяФайлаПроверокПоУмолчанию() Экспорт 7 | Возврат СтрШаблон("%1.os", ИмяТипаПоУмолчанию()); 8 | КонецФункции 9 | Функция ФайлПроверокИзменился(ПутьКФайлуПроверок) Экспорт 10 | Файл = Новый Файл(ПутьКФайлуПроверок); 11 | Результат = Ложь; 12 | Если Файл.ПолучитьВремяИзменения() <> ДатаИзмененияФайла Тогда 13 | ДатаИзмененияФайла = Файл.ПолучитьВремяИзменения(); 14 | Файл = Неопределено; 15 | Результат = Истина; 16 | КонецЕсли; 17 | Возврат Результат; 18 | КонецФункции 19 | 20 | Функция ПроверитьФайл(ОбъектПроверок) Экспорт 21 | РефлекторОбъекта = Новый Рефлектор; 22 | МассивИменНужныхМетодов = Новый Массив; 23 | МассивИменНужныхМетодов.Добавить("ОбработкаПомещенияВХранилище"); 24 | МассивИменНужныхМетодов.Добавить("ОбработкаИзмененияВерсииХранилища"); 25 | МассивИменНужныхМетодов.Добавить("ПостОбработкаПомещенияВХранилище"); 26 | ЕстьОшибки = Ложь; 27 | ТаблицаМетодов = РефлекторОбъекта.ПолучитьТаблицуМетодов(ОбъектПроверок); 28 | Для каждого ИмяНужногоМетода из МассивИменНужныхМетодов Цикл 29 | НайденнаяСтрока = ТаблицаМетодов.Найти(ИмяНужногоМетода, "Имя"); 30 | Если НайденнаяСтрока = Неопределено Тогда 31 | ТекстОшибки = СтрШаблон("Не найден метод %1 в файле проверок", ИмяНужногоМетода); 32 | Сообщить(ТекстОшибки); 33 | ЕстьОшибки = Истина; 34 | ИначеЕсли НайденнаяСтрока.Экспорт = Ложь Тогда 35 | ТекстОшибки = СтрШаблон("Метод %1 в файле проверок должен быть экспортным", ИмяНужногоМетода); 36 | Сообщить(ТекстОшибки); 37 | ЕстьОшибки = Истина; 38 | КонецЕсли; 39 | КонецЦикла; 40 | Возврат НЕ ЕстьОшибки; 41 | КонецФункции 42 | 43 | Функция Подключить(ПутьКФайлуПроверок = Неопределено) Экспорт 44 | ИскомыйТип = ИмяТипаПоУмолчанию(); 45 | ИмяФайлаПодключения = ""; 46 | ТекущийКаталог = ТекущийКаталог(); 47 | ОбъектПроверок = Неопределено; 48 | Если ЗначениеЗаполнено(ПутьКФайлуПроверок) Тогда 49 | ИмяФайлаПодключения = ПутьКФайлуПроверок; 50 | Иначе 51 | ИскомыйФайл = СтрШаблон("%1.os", ИскомыйТип); 52 | Файлы = НайтиФайлы(ТекущийКаталог, ИскомыйФайл); 53 | Если ЗначениеЗаполнено(Файлы) Тогда 54 | Файл = Файлы[0]; 55 | ИмяФайлаПодключения = Файл.ПолноеИмя; 56 | КонецЕсли; 57 | КонецЕсли; 58 | Если ЗначениеЗаполнено(ИмяФайлаПодключения) Тогда 59 | Попытка 60 | ОбъектПроверок = ЗагрузитьСценарий(ИмяФайлаПодключения); 61 | Файл = Новый Файл(ИмяФайлаПодключения); 62 | ПутьКФайлуПроверок = ИмяФайлаПодключения; 63 | ДатаИзмененияФайла = Файл.ПолучитьВремяИзменения(); 64 | Исключение 65 | Сообщить(СтрШаблон("Не удалось подключить файл %1 как сценарий OneScript", ИмяФайлаПодключения)); 66 | Сообщить(ОписаниеОшибки()); 67 | Возврат Неопределено; 68 | КонецПопытки; 69 | Иначе 70 | ТекстОшибки = СтрШаблон(" 71 | |Не найден файл %1 72 | |Выполните команду oproxy init 73 | |", ОбъединитьПути(ТекущийКаталог, ИскомыйФайл)); 74 | Сообщить(ТекстОшибки); 75 | Возврат Неопределено; 76 | КонецЕсли; 77 | Если НЕ ПроверитьФайл(ОбъектПроверок) Тогда 78 | Возврат Неопределено; 79 | КонецЕсли; 80 | Возврат ОбъектПроверок; 81 | КонецФункции 82 | -------------------------------------------------------------------------------- /src/Модули/РаботаСДемоном.os: -------------------------------------------------------------------------------- 1 | #Использовать 1commands 2 | 3 | Перем ИмяДемона Экспорт; 4 | 5 | Функция ИмяДемона() Экспорт 6 | Результат = ""; 7 | Если ЗначениеЗаполнено(ИмяДемона) Тогда 8 | Результат = ИмяДемона; 9 | Иначе 10 | Результат = "OproxyDaemon"; 11 | ИмяДемона = Результат; 12 | КонецЕсли; 13 | Возврат Результат; 14 | КонецФункции 15 | 16 | Функция ПутьКСервисМенеджеру() Экспорт 17 | ЧтоЗаменить = ОбъединитьПути("src", "Модули"); 18 | НаЧтоЗаменить = ОбъединитьПути("features", "nssm64_oproxy.exe"); 19 | Возврат СтрЗаменить(ТекущийСценарий().Каталог, ЧтоЗаменить, НаЧтоЗаменить); 20 | КонецФункции 21 | 22 | Функция ЭтоWindows() Экспорт 23 | СИ = Новый СистемнаяИнформация(); 24 | Возврат СтрНайти(нрег(СИ.ИмяЯдра), "windows") > 0; 25 | КонецФункции 26 | 27 | Функция ДемонСуществует() Экспорт 28 | Если НЕ ЭтоWindows() Тогда 29 | Сообщить("Данная команда доступна только для Windows"); 30 | Возврат Ложь; 31 | КонецЕсли; 32 | Команда = Новый Команда(); 33 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру()); 34 | Команда.ДобавитьПараметр("status"); 35 | Команда.ДобавитьПараметр(ИмяДемона()); 36 | КодВозврата = Команда.Исполнить(); 37 | Возврат КодВозврата = 0; 38 | КонецФункции 39 | 40 | Функция СоздатьИЗапустить(ТекстКоманды) Экспорт 41 | Если НЕ ЭтоWindows() Тогда 42 | Сообщить("Данная команда доступна только для Windows"); 43 | Возврат Ложь; 44 | КонецЕсли; 45 | ИмяДемона = ИмяДемона(); 46 | ПутьКСервисМенеджеру = ПутьКСервисМенеджеру(); 47 | Если ДемонСуществует() Тогда 48 | Сообщить(СтрШаблон("Демон %1 уже существует", ИмяДемона)); 49 | Возврат Ложь; 50 | КонецЕсли; 51 | Команда = Новый Команда(); 52 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру); 53 | Команда.ДобавитьПараметр("install"); 54 | Команда.ДобавитьПараметр(ИмяДемона()); 55 | Команда.ДобавитьПараметр(ТекстКоманды); 56 | КодВозврата = Команда.Исполнить(); 57 | Если КодВозврата = 0 Тогда 58 | Сообщить(СтрШаблон("Служба %1 успешно зарегистрирована", ИмяДемона)); 59 | Иначе 60 | Сообщить("Ошибка регистрации службы:"); 61 | Сообщить(Команда.ПолучитьВывод()); 62 | Возврат Ложь; 63 | КонецЕсли; 64 | Если НЕ Запустить() Тогда 65 | Возврат Ложь; 66 | КонецЕсли; 67 | Возврат Истина; 68 | КонецФункции 69 | 70 | Функция Удалить() Экспорт 71 | Если НЕ ЭтоWindows() Тогда 72 | Сообщить("Данная команда доступна только для Windows"); 73 | КонецЕсли; 74 | ИмяДемона = ИмяДемона(); 75 | ПутьКСервисМенеджеру = ПутьКСервисМенеджеру(); 76 | Если НЕ ДемонСуществует() Тогда 77 | Сообщить(СтрШаблон("Демон %1 не найден, поэтому его нельзя удалить", ИмяДемона)); 78 | Возврат Ложь; 79 | КонецЕсли; 80 | Если НЕ Остановить() Тогда 81 | Возврат Ложь; 82 | КонецЕсли; 83 | Команда = Новый Команда(); 84 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру); 85 | Команда.ДобавитьПараметр("remove"); 86 | Команда.ДобавитьПараметр(ИмяДемона); 87 | Команда.ДобавитьПараметр("confirm"); 88 | КодВозврата = Команда.Исполнить(); 89 | Если КодВозврата = 0 Тогда 90 | Сообщить(СтрШаблон("Служба %1 успешно удалена", ИмяДемона)); 91 | Иначе 92 | Сообщить(СтрШаблон("Ошибка удаления службы %1:", ИмяДемона)); 93 | Сообщить(Команда.ПолучитьВывод()); 94 | Возврат Ложь; 95 | КонецЕсли; 96 | Возврат Истина; 97 | КонецФункции 98 | 99 | Функция ПолучитьПараметрыДемона() 100 | ИмяДемона = ИмяДемона(); 101 | ПутьКСервисМенеджеру = ПутьКСервисМенеджеру(); 102 | Команда = Новый Команда; 103 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру); 104 | Команда.ДобавитьПараметр("get"); 105 | Команда.ДобавитьПараметр(ИмяДемона); 106 | Команда.ДобавитьПараметр("AppParameters"); 107 | Команда.Исполнить(); 108 | Возврат Команда.ПолучитьВывод(); 109 | КонецФункции 110 | 111 | Функция Запустить() Экспорт 112 | Если НЕ ЭтоWindows() Тогда 113 | Сообщить("Данная команда доступна только для Windows"); 114 | Возврат Ложь; 115 | КонецЕсли; 116 | ИмяДемона = ИмяДемона(); 117 | ПутьКСервисМенеджеру = ПутьКСервисМенеджеру(); 118 | Если НЕ ДемонСуществует() Тогда 119 | Сообщить(СтрШаблон("Демон %1 не найден, поэтому его нельзя запустить", ИмяДемона)); 120 | Возврат Ложь; 121 | КонецЕсли; 122 | Команда = Новый Команда(); 123 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру); 124 | Команда.ДобавитьПараметр("start"); 125 | Команда.ДобавитьПараметр(ИмяДемона); 126 | КодВозврата = Команда.Исполнить(); 127 | Если КодВозврата = 0 Тогда 128 | Сообщить(СтрШаблон("Служба %1 успешно запущена", ИмяДемона)); 129 | Сообщить("Параметры запуска: " + ПолучитьПараметрыДемона()); 130 | Иначе 131 | Сообщить(СтрШаблон("Ошибка запуска службы %1:", ИмяДемона)); 132 | Сообщить(Команда.ПолучитьВывод()); 133 | Возврат Ложь; 134 | КонецЕсли; 135 | Возврат Истина; 136 | КонецФункции 137 | 138 | Функция Остановить() Экспорт 139 | Если НЕ ЭтоWindows() Тогда 140 | Сообщить("Данная команда доступна только для Windows"); 141 | Возврат Ложь; 142 | КонецЕсли; 143 | ИмяДемона = ИмяДемона(); 144 | ПутьКСервисМенеджеру = ПутьКСервисМенеджеру(); 145 | Если НЕ ДемонСуществует() Тогда 146 | Сообщить(СтрШаблон("Демон %1 не найден, поэтому его нельзя остановить", ИмяДемона)); 147 | Возврат Ложь; 148 | КонецЕсли; 149 | Команда = Новый Команда(); 150 | Команда.УстановитьКоманду(ПутьКСервисМенеджеру); 151 | Команда.ДобавитьПараметр("stop"); 152 | Команда.ДобавитьПараметр(ИмяДемона); 153 | КодВозврата = Команда.Исполнить(); 154 | Если КодВозврата = 0 Тогда 155 | Сообщить(СтрШаблон("Служба %1 успешно остановлена", ИмяДемона)); 156 | Иначе 157 | Сообщить(СтрШаблон("Ошибка остановки службы %1:", ИмяДемона)); 158 | Сообщить(Команда.ПолучитьВывод()); 159 | Возврат Ложь; 160 | КонецЕсли; 161 | Возврат Истина; 162 | КонецФункции 163 | 164 | Процедура Перезапустить() Экспорт 165 | Остановить(); 166 | Запустить(); 167 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Классы/ОбработчикСоединений.os: -------------------------------------------------------------------------------- 1 | Перем ПроверкиПроксиСервера Экспорт; 2 | Перем АдресСервера Экспорт; 3 | Перем ПортСервера Экспорт; 4 | Перем ПриветствиеХранилища; 5 | Перем ПустыеДД; 6 | 7 | &ЛогОпрокси 8 | Перем Лог; 9 | 10 | &Желудь 11 | Процедура ПриСозданииОбъекта() 12 | ПриветствиеХранилища = ПолучитьДвоичныеДанныеИзHexСтроки("53F5C61A7B"); 13 | ПустыеДД = ПолучитьДвоичныеДанныеИзHexСтроки(""); 14 | КонецПроцедуры 15 | 16 | Процедура ОбработатьСоединение(Соединение_Конфигуратор) Экспорт 17 | 18 | Соединение_Хранилище = Неопределено; 19 | Пока Соединение_Конфигуратор.Активно Цикл 20 | 21 | ПараметрыЗапросаПостОбработка = Неопределено; 22 | Если ИзКонфигуратораВХранилище(Соединение_Конфигуратор, Соединение_Хранилище, ПараметрыЗапросаПостОбработка) Тогда 23 | ИзХранилищаВКонфигуратор(Соединение_Конфигуратор, Соединение_Хранилище); 24 | КонецЕсли; 25 | 26 | Если ПараметрыЗапросаПостОбработка <> Неопределено Тогда 27 | ПостОбработкаПомещенияВХранилище(ПараметрыЗапросаПостОбработка); 28 | КонецЕсли; 29 | 30 | КонецЦикла; 31 | 32 | Соединение_Конфигуратор.Закрыть(); 33 | Соединение_Хранилище.Закрыть(); 34 | 35 | КонецПроцедуры 36 | 37 | Функция ИзКонфигуратораВХранилище(Соединение_Конфигуратор, Соединение_Хранилище, ПараметрыЗапросаПостОбработка) 38 | ДанныеСоединения = Неопределено; 39 | ЕстьПодключениеКХранилищу = Соединение_Хранилище <> Неопределено; 40 | Если НЕ ЕстьПодключениеКХранилищу Тогда 41 | ИнициализироватьСоединениеСХранилищем(Соединение_Конфигуратор, Соединение_Хранилище, ДанныеСоединения); 42 | КонецЕсли; 43 | ЭтоКонецСообщения = Ложь; 44 | ЭтоПинг = Ложь; 45 | Пока НЕ ЭтоКонецСообщения Цикл 46 | Если ЕстьПодключениеКХранилищу Тогда 47 | ДанныеСоединения = Соединение_Конфигуратор.ПрочитатьДвоичныеДанные(); 48 | Иначе 49 | ЕстьПодключениеКХранилищу = Истина; 50 | КонецЕсли; 51 | ЭтоПинг = ОбработкаДанных.ЭтоПинг(ДанныеСоединения); 52 | Если НЕ ЭтоПинг Тогда 53 | ПараметрыЗапроса = ОбработкаДанных.ПолучитьПараметрыЗапроса(ДанныеСоединения); 54 | Если ПараметрыЗапроса <> Неопределено 55 | И ПараметрыЗапроса.Проверять = Истина Тогда 56 | ПродолжитьСоединение = ОбработатьПроверяемыйЗапрос(Соединение_Конфигуратор, Соединение_Хранилище, 57 | ДанныеСоединения, ПараметрыЗапросаПостОбработка); 58 | Возврат ПродолжитьСоединение; 59 | КонецЕсли; 60 | КонецЕсли; 61 | Соединение_Хранилище.ОтправитьДвоичныеДанные(ДанныеСоединения); 62 | Если ЭтоПинг Тогда 63 | Соединение_Конфигуратор.ОтправитьДвоичныеДанные(ПустыеДД); 64 | ЭтоКонецСообщения = Истина; 65 | Иначе 66 | ЭтоКонецСообщения = ОбработкаДанных.ЕстьКонецСообщения(ДанныеСоединения); 67 | КонецЕсли; 68 | КонецЦикла; 69 | 70 | Возврат НЕ ЭтоПинг; 71 | 72 | КонецФункции 73 | 74 | Функция ОбработатьПроверяемыйЗапрос(Соединение_Конфигуратор, Соединение_Хранилище, 75 | ДанныеСоединения, ПараметрыЗапросаПостОбработка) 76 | МассивДДЗапроса = Новый Массив; 77 | МассивДДЗапроса.Добавить(ДанныеСоединения); 78 | Пока НЕ ОбработкаДанных.ЕстьКонецСообщения(ДанныеСоединения) Цикл 79 | ДанныеСоединения = Соединение_Конфигуратор.ПрочитатьДвоичныеДанные(); 80 | МассивДДЗапроса.Добавить(ДанныеСоединения); 81 | КонецЦикла; 82 | ДанныеСоединения = СоединитьДвоичныеДанные(МассивДДЗапроса); 83 | ПараметрыЗапроса = ОбработкаДанных.ПолучитьПараметрыЗапроса(ДанныеСоединения); 84 | ТекстОшибки = ""; 85 | Попытка 86 | Если ПараметрыЗапроса.ИмяМетода = "DevDepot_commitObjects" Тогда 87 | ТекстОшибки = ПроверкиПроксиСервера.ОбработкаПомещенияВХранилище(ПараметрыЗапроса); 88 | ПараметрыЗапросаПостОбработка = ПараметрыЗапроса; 89 | ИначеЕсли ПараметрыЗапроса.ИмяМетода = "DevDepot_changeVersion" Тогда 90 | ТекстОшибки = ПроверкиПроксиСервера.ОбработкаИзмененияВерсииХранилища(ПараметрыЗапроса); 91 | ПараметрыЗапросаПостОбработка = ПараметрыЗапроса; 92 | КонецЕсли; 93 | Исключение 94 | ТекстОшибки = СтрШаблон("Ошибка вызова функции в файле ""ПроверкиПроксиСервера.os"": %1", ОписаниеОшибки()); 95 | Лог.Ошибка(ТекстОшибки); 96 | КонецПопытки; 97 | ЕстьОшибка = НЕ ПустаяСтрока(ТекстОшибки); 98 | Если ЕстьОшибка Тогда 99 | ДД = ОбработкаДанных.ПолучитьДвоичныеДанныеОтветаОшибки(ТекстОшибки); 100 | Соединение_Конфигуратор.ОтправитьДвоичныеДанные(ДД); 101 | ПараметрыЗапросаПостОбработка = Неопределено; 102 | Возврат Ложь; 103 | Иначе 104 | Для Каждого ДанныеСоединения Из МассивДДЗапроса Цикл 105 | Соединение_Хранилище.ОтправитьДвоичныеДанные(ДанныеСоединения); 106 | КонецЦикла; 107 | КонецЕсли; 108 | 109 | Возврат НЕ ЕстьОшибка; 110 | 111 | КонецФункции 112 | 113 | Процедура ИзХранилищаВКонфигуратор(Соединение_Конфигуратор, Соединение_Хранилище) 114 | ЭтоКонецСообщения = Ложь; 115 | Пока НЕ ЭтоКонецСообщения Цикл 116 | ДанныеСоединения = Соединение_Хранилище.ПрочитатьДвоичныеДанные(); 117 | Соединение_Конфигуратор.ОтправитьДвоичныеДанные(ДанныеСоединения); 118 | ЭтоКонецСообщения = ОбработкаДанных.ЕстьКонецСообщения(ДанныеСоединения); 119 | КонецЦикла; 120 | КонецПроцедуры 121 | 122 | Процедура ИнициализироватьСоединениеСХранилищем(Соединение_Конфигуратор, Соединение_Хранилище, ДанныеПервогоЗапроса) 123 | Соединение_Конфигуратор.ОтправитьДвоичныеДанные(ПриветствиеХранилища); 124 | ДанныеПервогоЗапроса = Соединение_Конфигуратор.ПрочитатьДвоичныеДанные(); 125 | Соединение_Хранилище = Новый TCPСоединение(АдресСервера, ПортСервера); 126 | Соединение_Хранилище.ПрочитатьДвоичныеДанные(); 127 | КонецПроцедуры 128 | 129 | Процедура ПостОбработкаПомещенияВХранилище(ПараметрыЗапроса) 130 | 131 | Попытка 132 | РезультатБулево = ПроверкиПроксиСервера.ПостОбработкаПомещенияВХранилище(ПараметрыЗапроса); 133 | Исключение 134 | ТекстОшибки = СтрШаблон("Ошибка вызова функции пост обработки в файле ""ПроверкиПроксиСервера.os"": %1", ОписаниеОшибки()); 135 | Лог.Ошибка(ТекстОшибки); 136 | КонецПопытки; 137 | 138 | КонецПроцедуры -------------------------------------------------------------------------------- /tests/Тесты.os: -------------------------------------------------------------------------------- 1 | #Использовать 1commands 2 | #Использовать asserts 3 | #Использовать ".." 4 | 5 | Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт 6 | ВсеТесты = Новый Массив; 7 | ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоПравильноОпределяетсяПингКонфигуратора"); 8 | ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоПравильноОпределяетсяКонецСообщения"); 9 | ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоРаботаетРазборЗапросаКонфигуратораНаПомещениеВХранилище"); 10 | ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоРаботаетРазборЗапросаКонфигуратораНаИзменениеВерсииВХранилище"); 11 | ВсеТесты.Добавить("ТекстДолжен_ПроверитьЧтоФайлПроверокПодключается"); 12 | ВсеТесты.Добавить("ТестДолженПроверить_ЧтоСоздаетсяФайлИнициализации"); 13 | 14 | Возврат ВсеТесты; 15 | КонецФункции 16 | 17 | Процедура ТестовыйТест() Экспорт 18 | //Результат = ПростоМодуль.ПроверкаСвязи(); 19 | //Ожидаем.Что(Результат).Равно(1); 20 | КонецПроцедуры 21 | 22 | Функция СоздатьВременныйКаталог() 23 | УИД = Строка(Новый УникальныйИдентификатор()); 24 | КаталогФайлов = ОбъединитьПути(КаталогВременныхФайлов(), УИД); 25 | СоздатьКаталог(КаталогФайлов); 26 | Возврат КаталогФайлов; 27 | КонецФункции 28 | 29 | Процедура УдалитьВременныйКаталог(КаталогФайлов) 30 | УдалитьФайлы(КаталогФайлов, "*.*"); 31 | УдалитьФайлы(КаталогФайлов); 32 | КонецПроцедуры 33 | 34 | Процедура ТестДолженПроверить_ЧтоСоздаетсяФайлИнициализации() Экспорт 35 | КаталогФайлов = СоздатьВременныйКаталог(); 36 | Команда = Новый Команда(); 37 | Команда.УстановитьРабочийКаталог(КаталогФайлов); 38 | Путь = ОбъединитьПути(ТекущийКаталог(), "src", "main.os"); 39 | Команда.УстановитьКоманду("oscript"); 40 | Команда.ДобавитьПараметр(Путь); 41 | Команда.ДобавитьПараметр("init"); 42 | КодВозврата = Команда.Исполнить(); 43 | Ожидаем.Что(КодВозврата).Равно(0); 44 | 45 | МассивФайлов = НайтиФайлы(КаталогФайлов, "ПроверкиПроксиСервера.os"); 46 | Ожидаем.Что(МассивФайлов.Количество()).Равно(1); 47 | УдалитьВременныйКаталог(КаталогФайлов); 48 | КонецПроцедуры 49 | 50 | Процедура ТестДолжен_ПроверитьЧтоПравильноОпределяетсяПингКонфигуратора() Экспорт 51 | Обработчик = ОбработкаДанных; 52 | 53 | ДД_Пинг = ПолучитьДвоичныеДанныеИзHexСтроки("214754B3"); 54 | ЭтоПинг = Обработчик.ЭтоПинг(ДД_Пинг); 55 | Ожидаем.Что(ЭтоПинг, "проверка сигнатуры пинга").Равно(Истина); 56 | 57 | ДД_Пинг = ПолучитьДвоичныеДанныеИзHexСтроки("214754B3214754B3214754B3214754B3214754B3"); 58 | ЭтоПинг = Обработчик.ЭтоПинг(ДД_Пинг); 59 | Ожидаем.Что(ЭтоПинг, "проверка сигнатуры пинга несколько раз подряд").Равно(Истина); 60 | 61 | ДД_Пинг = ПолучитьДвоичныеДанныеИзHexСтроки(""); 62 | ЭтоПинг = Обработчик.ЭтоПинг(ДД_Пинг); 63 | Ожидаем.Что(ЭтоПинг, "проверка с пустыми двоичными данными").Равно(Истина); 64 | 65 | ДД_Пинг = ПолучитьДвоичныеДанныеИзHexСтроки("A3B4C5D6"); 66 | ЭтоПинг = Обработчик.ЭтоПинг(ДД_Пинг); 67 | Ожидаем.Что(ЭтоПинг, "проверка функции пинга случайными дд 1").Равно(Ложь); 68 | 69 | ДД_Пинг = ПолучитьДвоичныеДанныеИзHexСтроки("A3B4C5D6F7"); 70 | ЭтоПинг = Обработчик.ЭтоПинг(ДД_Пинг); 71 | Ожидаем.Что(ЭтоПинг, "проверка функции пинга случайными дд 2").Равно(Ложь); 72 | КонецПроцедуры 73 | 74 | Процедура ТестДолжен_ПроверитьЧтоПравильноОпределяетсяКонецСообщения() Экспорт 75 | Обработчик = ОбработкаДанных; 76 | 77 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки("6653B2A6"); 78 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 79 | Ожидаем.Что(ЕстьКонецСообщения, "сигнатура конца сообщения").Равно(Истина); 80 | 81 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки("6653B2A66653B2A66653B2A66653B2A66653B2A6"); 82 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 83 | Ожидаем.Что(ЕстьКонецСообщения, "сигнатура конца сообщения несколько раз").Равно(Истина); 84 | 85 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки(""); 86 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 87 | Ожидаем.Что(ЕстьКонецСообщения, "пустые ДД").Равно(Ложь); 88 | 89 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки("A3B4C5D6F7"); 90 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 91 | Ожидаем.Что(ЕстьКонецСообщения, "случайные ДД 4 байта").Равно(Ложь); 92 | 93 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки("6653B2A6A3B4C5D6F7"); 94 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 95 | Ожидаем.Что(ЕстьКонецСообщения, "первая часть - сигнатура конца, вторая - случайные").Равно(Ложь); 96 | 97 | ДД = ПолучитьДвоичныеДанныеИзHexСтроки("A3B4C5D6F76653B2A6A3B4C5D6F7"); 98 | ЕстьКонецСообщения = Обработчик.ЕстьКонецСообщения(ДД); 99 | Ожидаем.Что(ЕстьКонецСообщения, "сигнатура конца в середине между случайными").Равно(Ложь); 100 | КонецПроцедуры 101 | 102 | Функция ПолучитьДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище() 103 | Путь = ОбъединитьПути(ТекущийКаталог(), "tests", "ДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище.dat"); 104 | Возврат Новый ДвоичныеДанные(Путь); 105 | КонецФункции 106 | 107 | Функция ПолучитьДвоичныеДанныеЗапросаКонфигуратораНаИзменениеВерсииВХранилище() 108 | Путь = ОбъединитьПути(ТекущийКаталог(), "tests", "ДвоичныеДанныеЗапросаКонфигуратораНаИзменениеВерсииВХранилище.dat"); 109 | Возврат Новый ДвоичныеДанные(Путь); 110 | КонецФункции 111 | 112 | Процедура ТестДолжен_ПроверитьЧтоРаботаетРазборЗапросаКонфигуратораНаПомещениеВХранилище() Экспорт 113 | Обработчик = ОбработкаДанных; 114 | ДД = ПолучитьДвоичныеДанныеЗапросаКонфигуратораНаПомещениеДанныхВХранилище(); 115 | ПараметрыЗапроса = Обработчик.ПолучитьПараметрыЗапроса(ДД); 116 | Ожидаем.Что(ПараметрыЗапроса, "разбор завершится успешно").Существует().ИмеетТип("Структура"); 117 | Ожидаем.Что(ПараметрыЗапроса.Проверять, "проверка признака Проверять из файла").Равно(Истина); 118 | Ожидаем.Что(ПараметрыЗапроса.ИмяСистемы, "проверка признака ИмяСистемы из файла").Равно("p_buying_test"); 119 | Ожидаем.Что(ПараметрыЗапроса.ИмяМетода, "проверка признака ИмяМетода из файла").Равно("DevDepot_commitObjects"); 120 | Ожидаем.Что(ПараметрыЗапроса.ВерсияПлатформы, "проверка признака ВерсияПлатформы из файла").Равно("8.3.22.2143"); 121 | Ожидаем.Что(ПараметрыЗапроса.Комментарий, "проверка признака Комментарий из файла").Равно("тестовый комментарий"); 122 | Ожидаем.Что(ПараметрыЗапроса.ИмяПользователя, "проверка признака ИмяПользователя из файла").Равно("Administrator"); 123 | Ожидаем.Что(ПараметрыЗапроса.ВерсияКонфигурации, "проверка признака Версия конфигурации из файла").Равно("1.497"); 124 | 125 | ПараметрыЗапроса = Обработчик.ПолучитьПараметрыЗапроса(ПолучитьДвоичныеДанныеИзHexСтроки("")); 126 | Ожидаем.Что(ПараметрыЗапроса, "на пустых ДД выдаст неопределено").Равно(Неопределено); 127 | 128 | ПараметрыЗапроса = Обработчик.ПолучитьПараметрыЗапроса(ПолучитьДвоичныеДанныеИзHexСтроки("A3B4C5F6")); 129 | Ожидаем.Что(ПараметрыЗапроса, "на случайных ДД выдаст неопределено").Равно(Неопределено); 130 | КонецПроцедуры 131 | 132 | Процедура ТестДолжен_ПроверитьЧтоРаботаетРазборЗапросаКонфигуратораНаИзменениеВерсииВХранилище() Экспорт 133 | Обработчик = ОбработкаДанных; 134 | ДД = ПолучитьДвоичныеДанныеЗапросаКонфигуратораНаИзменениеВерсииВХранилище(); 135 | ПараметрыЗапроса = Обработчик.ПолучитьПараметрыЗапроса(ДД); 136 | Ожидаем.Что(ПараметрыЗапроса, "разбор завершится успешно").Существует().ИмеетТип("Структура"); 137 | Ожидаем.Что(ПараметрыЗапроса.Проверять, "проверка признака Проверять из файла").Равно(Истина); 138 | Ожидаем.Что(ПараметрыЗапроса.ИмяСистемы, "проверка признака ИмяСистемы из файла").Равно("test_master"); 139 | Ожидаем.Что(ПараметрыЗапроса.ИмяМетода, "проверка признака ИмяМетода из файла").Равно("DevDepot_changeVersion"); 140 | Ожидаем.Что(ПараметрыЗапроса.ВерсияПлатформы, "проверка признака ВерсияПлатформы из файла").Равно("8.3.22.2143"); 141 | Ожидаем.Что(ПараметрыЗапроса.Комментарий, "проверка признака Комментарий из файла").Равно("Комментарий стал"); 142 | Ожидаем.Что(ПараметрыЗапроса.КомментарийБыл, "проверка признака Комментарий предыдущий из файла").Равно("комментарий был"); 143 | Ожидаем.Что(ПараметрыЗапроса.ИмяПользователя, "проверка признака ИмяПользователя из файла").Равно("vrunner"); 144 | Ожидаем.Что(ПараметрыЗапроса.Метка, "проверка признака Метка из файла").Равно("Метка новая"); 145 | Ожидаем.Что(ПараметрыЗапроса.КомментарийМетки, "проверка признака Комментарий метки из файла").Равно("Комментарий метки"); 146 | Ожидаем.Что(ПараметрыЗапроса.ВерсияКонфигурации, "проверка признака Версия конфигурации из файла").Равно("1.2.3.4"); 147 | 148 | КонецПроцедуры 149 | 150 | Процедура ТекстДолжен_ПроверитьЧтоФайлПроверокПодключается() Экспорт 151 | ПутьКФайлуПроверок = ОбъединитьПути(ТекущийКаталог(), "features", "ПроверкиПроксиСервера_Пример.os"); 152 | лОбъект = РаботаСФайломПроверок.Подключить(ПутьКФайлуПроверок); 153 | Заполнен = лОбъект <> Неопределено; 154 | Ожидаем.Что(Заполнен).Равно(Истина); 155 | 156 | лОбъект = РаботаСФайломПроверок.Подключить(ПутьКФайлуПроверок); 157 | Заполнен = лОбъект <> Неопределено; 158 | Ожидаем.Что(Заполнен).Равно(Истина); 159 | КонецПроцедуры -------------------------------------------------------------------------------- /src/Модули/ОбработкаДанных.os: -------------------------------------------------------------------------------- 1 | //ДвоичныеДанные, по которым можно определить что очередной пакет является концом серии пакетов 2 | Перем СигнатураПоискаКонца; 3 | Перем РазмерСигнатурыКонца; 4 | //ДвоичныеДанные, по которым можно определить что очередной пакет является пакетом проверки связи 5 | Перем СигнатураПоискаПинга; 6 | Перем РазмерСигнатурыПинга; 7 | //ДвоичныеДанные, по которым можно определить что очередной пакет является началом сообщения (в начале слово POST) 8 | Перем СигнатураНачалаСообщения; 9 | Перем РазмерСигнатурыНачалаСообщения; 10 | 11 | //ДвоичныеДанные, по которым можно определить что в очередном пакете содержится начало XML данных 12 | Перем СигнатураНачалаXML; 13 | Перем РазмерСигнатурыНачалаXML; 14 | //массив имен методов хранилища, которые подлежат проверке 15 | Перем ПроверяемыеМетоды; 16 | 17 | Процедура ПриСозданииОбъекта() 18 | СигнатураПоискаКонца = ПолучитьДвоичныеДанныеИзHexСтроки("6653B2A6"); 19 | РазмерСигнатурыКонца = СигнатураПоискаКонца.Размер(); 20 | СигнатураПоискаПинга = ПолучитьДвоичныеДанныеИзHexСтроки("214754B3"); 21 | РазмерСигнатурыПинга = СигнатураПоискаПинга.Размер(); 22 | СигнатураНачалаСообщения = ПолучитьДвоичныеДанныеИзСтроки("POST"); 23 | РазмерСигнатурыНачалаСообщения = СигнатураНачалаСообщения.Размер(); 24 | СигнатураНачалаXML = ПолучитьДвоичныеДанныеИзСтроки(" 0 Тогда 41 | Поток.Закрыть(); 42 | Возврат Ложь; 43 | КонецЕсли; 44 | 45 | Нашли = Истина; 46 | 47 | Буфер = Новый БуферДвоичныхДанных(РазмерСигнатурыПинга); 48 | Пока Поток.ТекущаяПозиция() < Размер Цикл 49 | Поток.Прочитать(Буфер, 0, РазмерСигнатурыПинга); 50 | Если СигнатураПоискаПинга <> ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буфер) Тогда 51 | Нашли = Ложь; 52 | Прервать; 53 | КонецЕсли; 54 | КонецЦикла; 55 | Поток.Закрыть(); 56 | Возврат Нашли; 57 | КонецФункции 58 | 59 | Функция ЕстьКонецСообщения(ВходныеДанные) Экспорт 60 | Поток = ВходныеДанные.ОткрытьПотокДляЧтения(); 61 | Размер = Поток.Размер(); 62 | Если Размер < РазмерСигнатурыКонца Тогда 63 | Поток.Закрыть(); 64 | Возврат Ложь; 65 | КонецЕсли; 66 | Поток.Перейти(-РазмерСигнатурыКонца, ПозицияВПотоке.Конец); 67 | Буфер = Новый БуферДвоичныхДанных(РазмерСигнатурыКонца); 68 | Поток.Прочитать(Буфер, 0, РазмерСигнатурыКонца); 69 | 70 | Поток.Закрыть(); 71 | 72 | КонецДанныхРазмеромСигнатуры = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буфер); 73 | Результат = КонецДанныхРазмеромСигнатуры = СигнатураПоискаКонца; 74 | Возврат Результат; 75 | КонецФункции 76 | 77 | Функция ПолучитьПараметрыЗапроса(ДвоичныеДанныеЗапроса) Экспорт 78 | ТелоЗапроса = ПолучитьТекстХМЛ(ДвоичныеДанныеЗапроса); 79 | Если ПустаяСтрока(ТелоЗапроса) Тогда 80 | Возврат Неопределено; 81 | КонецЕсли; 82 | СтруктураОтвета = НовыйСтруктураОтвета(); 83 | Попытка 84 | Чтение = Новый ЧтениеXML; 85 | Чтение.УстановитьСтроку(ТелоЗапроса); //удалить BOM 86 | 87 | Пока Чтение.Прочитать() Цикл 88 | Если Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда 89 | Продолжить; 90 | КонецЕсли; 91 | Если Чтение.ЛокальноеИмя = "call" Тогда 92 | СтруктураОтвета.Вставить("ИмяСистемы", Нрег(Чтение.ЗначениеАтрибута("alias"))); 93 | СтруктураОтвета.Вставить("ВерсияПлатформы", Чтение.ЗначениеАтрибута("version")); 94 | СтруктураОтвета.Вставить("ИмяМетода", Чтение.ЗначениеАтрибута("name")); 95 | Если ПроверяемыеМетоды.Найти(СтруктураОтвета.ИмяМетода) = Неопределено Тогда 96 | Прервать; //если метод не нужно проверять, не надо дочитывать весь XML до конца 97 | КонецЕсли; 98 | СтруктураОтвета.Вставить("Проверять", Истина); 99 | Если СтруктураОтвета.ИмяМетода = "DevDepot_commitObjects" Тогда 100 | ПродолжитьРазборПомещениеДанныхВХранилище(Чтение, СтруктураОтвета); 101 | ИначеЕсли СтруктураОтвета.ИмяМетода = "DevDepot_changeVersion" Тогда 102 | ПродолжитьРазборИзменениеВерсииВХранилище(Чтение, СтруктураОтвета); 103 | Иначе 104 | ВызватьИсключение "не поддерживается разбор метода " + СтруктураОтвета.ИмяМетода; 105 | КонецЕсли; 106 | КонецЕсли; 107 | 108 | КонецЦикла; 109 | Чтение.Закрыть(); 110 | Чтение = Неопределено; 111 | Исключение 112 | Чтение.Закрыть(); 113 | Чтение = Неопределено; 114 | //конфигуратор и хранилище общаются пакетами, а не целыми сообщениями 115 | //при длинных сообщениях конфигуратор может отдать только часть XML 116 | КонецПопытки; 117 | Возврат СтруктураОтвета; 118 | КонецФункции 119 | 120 | Функция НовыйСтруктураОтвета() 121 | Перем результат; 122 | результат = Новый Структура; 123 | результат.Вставить("ИмяСистемы"); 124 | результат.Вставить("ИмяМетода"); 125 | результат.Вставить("ВерсияПлатформы"); 126 | результат.Вставить("Проверять"); 127 | результат.Вставить("ИмяПользователя"); 128 | результат.Вставить("ВерсияКонфигурации"); 129 | результат.Вставить("Комментарий"); 130 | результат.Вставить("КомментарийБыл"); 131 | результат.Вставить("Метка"); 132 | результат.Вставить("КомментарийМетки"); 133 | 134 | Возврат результат; 135 | КонецФункции 136 | 137 | Процедура ПродолжитьРазборПомещениеДанныхВХранилище(Чтение, СтруктураОтвета) 138 | Пока Чтение.Прочитать() Цикл 139 | Если Чтение.ТипУзла <> ТипУзлаXML.НачалоЭлемента Тогда 140 | Продолжить; 141 | КонецЕсли; 142 | Если Чтение.ЛокальноеИмя = "auth" Тогда 143 | СтруктураОтвета.Вставить("ИмяПользователя", Чтение.ЗначениеАтрибута("user")); 144 | ИначеЕсли Чтение.ЛокальноеИмя = "comment" Тогда 145 | Чтение.Прочитать(); 146 | СтруктураОтвета.Вставить("Комментарий", СокрЛП(Чтение.Значение)); 147 | ИначеЕсли Чтение.ЛокальноеИмя = "code" Тогда 148 | СтруктураОтвета.Вставить("ВерсияКонфигурации", Чтение.ЗначениеАтрибута("value")); 149 | КонецЕсли; 150 | КонецЦикла; 151 | КонецПроцедуры 152 | 153 | Процедура ПродолжитьРазборИзменениеВерсииВХранилище(Чтение, СтруктураОтвета) 154 | 155 | ЭтоНоваяВерсия = Ложь; 156 | ЭтоМетка = Ложь; 157 | ЭтоИнфо = Ложь; 158 | 159 | Пока Чтение.Прочитать() Цикл 160 | Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда 161 | Если Чтение.ЛокальноеИмя = "auth" Тогда 162 | СтруктураОтвета.Вставить("ИмяПользователя", Чтение.ЗначениеАтрибута("user")); 163 | ИначеЕсли Чтение.ЛокальноеИмя = "newVersion" Тогда 164 | ЭтоНоваяВерсия = Истина; 165 | ИначеЕсли Чтение.ЛокальноеИмя = "info" Тогда 166 | ЭтоИнфо = Истина; 167 | ИначеЕсли Чтение.ЛокальноеИмя = "label" Тогда 168 | ЭтоМетка = Истина; 169 | ИначеЕсли Чтение.ЛокальноеИмя = "comment" И ЭтоИнфо И ЭтоНоваяВерсия Тогда 170 | Чтение.Прочитать(); 171 | СтруктураОтвета.Вставить("Комментарий", СокрЛП(Чтение.Значение)); 172 | ИначеЕсли Чтение.ЛокальноеИмя = "comment" И ЭтоИнфо И НЕ ЭтоНоваяВерсия Тогда 173 | Чтение.Прочитать(); 174 | СтруктураОтвета.Вставить("КомментарийБыл", СокрЛП(Чтение.Значение)); 175 | ИначеЕсли Чтение.ЛокальноеИмя = "code" И ЭтоИнфо И ЭтоНоваяВерсия Тогда 176 | СтруктураОтвета.Вставить("ВерсияКонфигурации", Чтение.ЗначениеАтрибута("value")); 177 | ИначеЕсли Чтение.ЛокальноеИмя = "name" И ЭтоМетка И ЭтоНоваяВерсия Тогда 178 | СтруктураОтвета.Вставить("Метка", Чтение.ЗначениеАтрибута("value")); 179 | ИначеЕсли Чтение.ЛокальноеИмя = "comment" И ЭтоМетка И ЭтоНоваяВерсия Тогда 180 | Чтение.Прочитать(); 181 | СтруктураОтвета.Вставить("КомментарийМетки", СокрЛП(Чтение.Значение)); 182 | КонецЕсли; 183 | ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда 184 | Если Чтение.ЛокальноеИмя = "newVersion" Тогда 185 | ЭтоНоваяВерсия = Ложь; 186 | ИначеЕсли Чтение.ЛокальноеИмя = "info" Тогда 187 | ЭтоИнфо = Ложь; 188 | ИначеЕсли Чтение.ЛокальноеИмя = "label" Тогда 189 | ЭтоМетка = Ложь; 190 | КонецЕсли 191 | КонецЕсли; 192 | КонецЦикла; 193 | КонецПроцедуры 194 | 195 | Функция ПолучитьТекстХМЛ(ДвоичныеДанныеЗапроса) 196 | Результат = ""; 197 | ПотокЧтения = ДвоичныеДанныеЗапроса.ОткрытьПотокДляЧтения(); 198 | БуферПроверкиХМЛ = Новый БуферДвоичныхДанных(РазмерСигнатурыНачалаXML); 199 | 200 | БуферПроверкиНачала = Новый БуферДвоичныхДанных(РазмерСигнатурыНачалаСообщения); 201 | ПотокЧтения.Прочитать(БуферПроверкиНачала, 0, РазмерСигнатурыНачалаСообщения); 202 | Если ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(БуферПроверкиНачала) <> СигнатураНачалаСообщения Тогда 203 | ПотокЧтения.Закрыть(); 204 | Возврат Результат; 205 | КонецЕсли; 206 | 207 | НашлиХМЛ = Ложь; 208 | Пока НЕ НашлиХМЛ Цикл 209 | ПотокЧтения.Прочитать(БуферПроверкиХМЛ, 0, РазмерСигнатурыНачалаXML); 210 | Если ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(БуферПроверкиХМЛ) = СигнатураНачалаXML Тогда 211 | НашлиХМЛ = Истина; 212 | Прервать; 213 | КонецЕсли; 214 | ПотокЧтения.Перейти(1 - РазмерСигнатурыНачалаXML, ПозицияВПотоке.Текущая); 215 | КонецЦикла; 216 | 217 | Если НашлиХМЛ Тогда 218 | ПотокЧтения.Перейти(-РазмерСигнатурыНачалаXML, ПозицияВПотоке.Текущая); 219 | РазмерЧтения = ПотокЧтения.Размер() - ПотокЧтения.ТекущаяПозиция(); 220 | БуферХМЛ = Новый БуферДвоичныхДанных(РазмерЧтения); 221 | ПотокЧтения.Прочитать(БуферХМЛ, 0, РазмерЧтения); 222 | Результат = ПолучитьСтрокуИзБуфераДвоичныхДанных(БуферХМЛ); 223 | КонецЕсли; 224 | ПотокЧтения.Закрыть(); 225 | Возврат Результат; 226 | КонецФункции 227 | 228 | Функция ПолучитьДвоичныеДанныеОтветаОшибки(ТекстОшибки) Экспорт 229 | ТекстОшибки = СтрЗаменить(ТекстОшибки, """", "'"); 230 | СтрокаВнутрОшибки = СтрЗаменить( 231 | "{ 232 | |{3ccb2518-9616-4445-aaa7-20048fead174,""" + ТекстОшибки + """, 233 | |{00000000-0000-0000-0000-000000000000},""core83.dll:0x0000000000085BE8 crcore.dll:0x000000000003542A crcore.dll:0x000000000010E48C VCRUNTIME140.dll:0x0000000000001030 VCRUNTIME140.dll:0x00000000000032E8 unknown:0x0000000000000000 crcore.dll:0x00000000000C078F crserver.exe:0x0000000000009399 core83.dll:0x00000000002B256B core83.dll:0x00000000002B259C core83.dll:0x0000000000176F3E ucrtbase.dll:0x0000000000000000 KERNEL32.DLL:0x0000000000000000 unknown:0x0000000000000000 "",""0000000000000000000000"",00000000-0000-0000-0000-000000000000},4, 234 | |{""file://С:\folder\confstore"",0},""""}", 235 | Символы.ПС, Символы.ВК + Символы.ПС); 236 | ДвоичныеДанныеСтрокиВнутр = ПолучитьДвоичныеДанныеИзСтроки(СтрокаВнутрОшибки, "UTF-8", Истина); 237 | Base64СтрокаВнутр = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанныеСтрокиВнутр); 238 | ТекстХМЛ = СтрШаблон( 239 | "%1" 241 | , Base64СтрокаВнутр); 242 | ДД_БОМ = ПолучитьДвоичныеДанныеИзHexСтроки("EFBBBF"); 243 | РазмерХМЛ = ПолучитьДвоичныеДанныеИзСтроки(ТекстХМЛ).Размер() + ДД_БОМ.Размер(); 244 | ТекстОтвета = СтрЗаменить( 245 | "HTTP/1.1 200 OK 246 | |Content-Length: " + РазмерХМЛ + " 247 | |Content-Type: application/xml 248 | | 249 | |", 250 | Символы.ПС, Символы.ВК + Символы.ПС); 251 | ПотокВПамяти = Новый ПотокВПамяти; 252 | 253 | Запись = Новый ЗаписьДанных(ПотокВПамяти, "UTF-8", , ""); 254 | Запись.ЗаписатьСтроку(ТекстОтвета); 255 | Запись.Записать(ДД_БОМ); 256 | Запись.ЗаписатьСтроку(ТекстХМЛ); 257 | Запись.Записать(СигнатураПоискаКонца); 258 | 259 | ПотокВПамяти.Перейти(0, ПозицияВПотоке.Начало); 260 | ОтветДД = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные(); 261 | Запись.Закрыть(); 262 | 263 | Возврат ОтветДД; 264 | КонецФункции -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Тестирование](https://github.com/infina15/oproxy/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/infina15/oproxy/actions/workflows/test.yml) 2 | ## oproxy - TCP прокси-сервер хранилища конфигураций 1С 3 | 4 | Написан на [OneScript](https://github.com/EvilBeaver/OneScript). Вдохновлен [winow](https://github.com/autumn-library/winow) 5 | 6 | Для работы прокси-сервера необходимо установить и настроить [TCP сервер хранилищ 1С](https://wiseadvice-it.ru/o-kompanii/blog/articles/hranilishhe-konfiguracii-v-1s-8-3-ustanovka-i-nastroika/) 7 | 8 | Прокси-сервер: 9 | - Не работает с файловым вариантом хранилища 10 | - Не работает с хранилищем по HTTP, только TCP 11 | - Но нативная HTTP публикация может смотреть на порт прокси ([далее](#http_link)) 12 | 13 | Прокси-сервер позволяет перехватывать и обрабатывать некоторые события хранилища конфигурации (помещение версии в хранилище и изменение версии) и при необходимости возвращать нативную ошибку в конфигуратор. 14 | 15 | Например, при помещении версии в хранилище можно проверить комментарий на соответствие регулярному выражению в зависимости от имени системы, либо произвести вызов к Jira и проверить что задача с таким номером существует. Запретить помещать версии в определенные часы, вызвать старт пайплайна в GitLab или Jenkins, запустить GitSync, обратиться к API кофемашины, отправить случайный мем в Телеграме - все на что у вас хватит фантазии и скиллов в программировании на OneScript. 16 | 17 | ### Принцип работы 18 | Прокси сервер: 19 | - слушает указанный tcp-порт 20 | - получает пакеты данных от конфигуратора 21 | - анализирует их 22 | - отправляет пакеты tcp-серверу хранилища 23 | - может не отправлять данные серверу хранилища, а вернуть в конфигуратор ошибку (по условию написанному вами в коде) 24 | 25 | Чтобы не нарушить целостность хранилища 1С, прокси не изменяет данные, которые идут из конфигуратора в хранилище и обратно. Данные передаются в неизменном виде. Прокси может только прервать передачу данных в сторону хранилища и вернуть ошибку в конфигуратор. 26 | 27 | Есть 2 варианта установки ошибки: 28 | - при создании версии хранилища (Поместить в хранилище...) 29 | - при изменении версии хранилища (в истории хранилища) 30 | 31 | Прокси сервер запускается из отдельной папки, в которой функция инициализации создаст файл "ПроверкиПроксиСервера.os" для написания проверок/вызовов/веб-хуков. Так же допускается указание полного пути к файлу проверок. В этом файле изначально есть 2 функции для обработки 2 вариантов установки ошибки. Этот скрипт редактируется пользователем прокси-сервера и используется прокси-сервером. Скрипт "ПроверкиПроксиСервера.os" не является частью дистрибутива прокси-сервера, полностью отдан во владение пользователю, его можно редактировать во время работы прокси. Главное чтобы в нем были все необходимые (целых две) для прокси-сервера функции :) 32 | 33 | ### Установка 34 | В командной строке: 35 | ``` 36 | opm install oproxy 37 | ``` 38 | Либо [скачать файл .ospx из последнего релиза](https://github.com/infina15/oproxy/releases/latest), либо из хаба [hub.oscript.io](https://hub.oscript.io/package/oproxy) и (подставить нужное имя файла): 39 | ``` 40 | opm install --file oproxy-0.0.4.ospx 41 | ``` 42 | 43 | ### Инициализация 44 | После установки следует создать каталог, в котором будет располагаться файл с проверками/веб-хуками/вызовами пайплайнов/анекдотами. Например D:\oproxy_catalog. Перейти в этот каталог и вызвать функцию инициализации: 45 | ``` 46 | cd D:\oproxy_catalog 47 | oproxy init 48 | ``` 49 | В каталоге создастся файл ПроверкиПроксиСервера.os. Этот файл можно скопировать в любое другое место и потом при запуске указать к нему полный путь. 50 | 51 | Также файл можно найти в дистрибутиве библиотеки в каталоге features под названием ПроверкиПроксиСервера_Пример.os и скопировать руками куда хочется. 52 | 53 | В нем 3 функции: 54 | ```bsl 55 | Функция ОбработкаПомещенияВХранилище(ПараметрыЗапроса) Экспорт 56 | Функция ОбработкаИзмененияВерсииХранилища(ПараметрыЗапроса) Экспорт 57 | Функция ПостОбработкаПомещенияВХранилище() Экспорт 58 | ``` 59 | ПараметрыЗапроса - это структура, в которой всегда есть поля: 60 | - ИмяСистемы - Строка - название хранилища в нижнем регистре. Название такое же, как при подключении конфигуратора к хранилищу. Например для подключения tcp://server.local:1544/BAZA ИмяСистемы будет baza 61 | - ИмяМетода - Строка - DevDepot_commitObjects (для помещения в хранилище) или DevDepot_changeVersion (для изменения версии хранилища) 62 | - ВерсияПлатформы - Строка - версия платформы, с которой обращается конфигуратор, например 8.3.22.2143 63 | - Проверять - Булево - всегда Истина 64 | - ИмяПользователя - Строка - имя пользователя хранилища, под которым произошло обращение. В том регистре, в котором указано в настройках хранилища. 65 | - ВерсияКонфигурации - Строка - значение поля "Версия конфигурации" в истории хранилища 66 | - Комментарий - Строка - текст, который пользователь указал при помещении или изменении версии хранилища в поле "Комментарий" (может быть пустым, даже если комментарий не был изменен) 67 | - КомментарийБыл - Строка - текст, который был указан при изменении версии хранилища в поле "Комментарий" (заполнен только для изменения версии хранилища) 68 | - Метка - Строка - метка, указываемая при изменении версии хранилища 69 | - КомментарийМетки - Строка - комментарий метки при изменении версии хранилища 70 | 71 | В этом файле можно написать свои проверки и вызовы. Например файл может быть такой: 72 | ```bsl 73 | Функция ОбработкаПомещенияВХранилище(ПараметрыЗапроса) Экспорт 74 | СообщениеОбОшибке = ""; 75 | Если ПараметрыЗапроса.ИмяСистемы = "baza1" Тогда 76 | Если НЕ СтрНачинаетсяС(ПараметрыЗапроса.Комментарий, "ERP-") Тогда 77 | СообщениеОбОшибке = "Комментарий должен начинаться с ""ERP-""!"; 78 | Иначе 79 | //... 80 | КонецЕсли; 81 | КонецЕсли; 82 | Если НЕ ПустаяСтрока(СообщениеОбОшибке) Тогда 83 | ОтправитьДоносНачальникуВТелеграм(ПараметрыЗапроса.ИмяПользователя, ПараметрыЗапроса.Комментарий); 84 | Иначе 85 | ОтправитьКомандуЗаваркиКофе_В_АПИ_КофеМашины(); 86 | КонецЕсли; 87 | Возврат СообщениеОбОшибке; 88 | КонецФункции 89 | Функция ОбработкаИзмененияВерсииХранилища(ПараметрыЗапроса) Экспорт 90 | СообщениеОбОшибке = ""; 91 | Если ДеньНедели() = 5 Тогда 92 | СообщениеОбОшибке = "По пятницам комментарии не меняем"; 93 | Иначе 94 | ОткатитьГитДоВерсииИПерезапуститьГитСинк(); 95 | КонецЕсли; 96 | Возврат СообщениеОбОшибке; 97 | КонецФункции 98 | Функция ПостОбработкаПомещенияВХранилище() Экспорт 99 | Если ЗдесьМыТочноУжеЗнаемЧтоВсеПоместилосьВХранилище Тогда 100 | ВызватьЗапускПайплайна(); 101 | СбегатьЗаПивом(); 102 | КонецЕсли; 103 | КонецФункции 104 | ``` 105 | А там уж на что у вас фантазии хватит. 106 | ### Запуск сервера в режиме службы (только для Windows) 107 | В дистрибутиве есть менеджер служб [NSSM](https://nssm.cc/) под 64-битную Windows. Располагается в features\nssm64_oproxy.exe. На него настроены команды создания/удаления/прочие действия со службой прокси-сервера. 108 | 109 | ### Параметр --daemon-name 110 | 111 | Все команды по работе с демоном имеют параметр необязательный параметр --daemon-name (по умолчанию OproxyDaemon). С помощью него можно указать свое имя демона, отличное от значения по умолчанию. Данный параметр используется, когда нужно запустить несколько служб одновременно (например на разные версии хранилища). 112 | 113 | Команда 114 | ``` 115 | oproxy create-daemon 116 | ``` 117 | Создает и запускает службу Windows под названием OproxyDeamon, если такой службы нет. 118 | 119 | Если писать так как ниже, то при запуске сервера службой будет попытка поиска файла ПроверкиПроксиСервера.os в текущем каталоге: 120 | 121 | ``` 122 | oproxy create-daemon --proxy-port 2555 --storage-server localhost --storage-port 2544 123 | ``` 124 | Или вот так, с указанием полного имени к файлу проверок (текущий каталог не важен): 125 | ``` 126 | oproxy create-daemon --proxy-port 2555 --storage-server server.local --storage-port 2544 --check-file D:\oproxy_folder\Проверки.os 127 | ``` 128 | В данных примерах: 129 | - --proxy-port - Число - номер порта, по которому прокси будет слушать соединения (и который надо будет указывать в конфигураторе) 130 | - --storage-server - Строка - имя сервера, на котором развернут tcp сервер хранилища 1С. Пишется без "tcp://", без номера порта, просто имя сервера. Если прокси запускается на той же машине, где развернут сервер хранилища, можно указать localhost или 127.0.0.1 131 | - --storage-port - Число - порт развернутого tcp хранилища 1С 132 | - --check-file - Строка - (необязательный) полный путь на диске к файлу с проверками 133 | 134 | Для приведенного выше примера, если у нас сервер называется server.local, а имя базы в хранилище baza1, в конфигураторе надо будет писать адрес tcp://server.local:2555/baza1 135 | 136 | Также есть команды: 137 | ``` 138 | oproxy start-daemon &:: запускает остановленную службу 139 | ``` 140 | ``` 141 | oproxy check-file &:: проверяет файл ПроверкиПроксиСервера.os в текущией папке (либо указанный файл в параметре) на предмет того, что он может быть использован прокси-сервером 142 | ``` 143 | ``` 144 | oproxy stop-daemon &::останавливает запущенную службу 145 | ``` 146 | ``` 147 | oproxy restart-daemon &::перезапускает существующую службу 148 | ``` 149 | ``` 150 | oproxy remove-daemon &:: останавливает и удаляет существующую службу 151 | ``` 152 | 153 | Не забудьте в фаерволе операционной системы и/или роутеров открыть порт, указанный в --proxy-port, иначе никто из сети не сможет обращаться к прокси-серверу. 154 | 155 | По умолчанию NSSM использует системного пользователя. Если вам это не подходит и вы хотите осуществить более тонкую настройку службы - можно настраивать NSSM вручную (информация на сайте [NSSM](https://nssm.cc/)) c [помощью ручных команд запуска](#manual_link). 156 | 157 | Важно: чтобы NSSM запустил oproxy, надо писать в строке запуска не: 158 | ``` 159 | oproxy start <параметры> 160 | ``` 161 | А: 162 | ``` 163 | oproxy.bat start <параметры> 164 | ``` 165 | Потому что NSSM умеет смотреть в переменную PATH, но не находит файлы по имени без расширения. 166 | 167 | ### Запуск сервера вручную 168 | Запускать прокси-сервер необходимо из того каталога, где лежит файл ПроверкиПроксиСервера.os, т.к. прокси будет искать файл именно в каталоге запуска. 169 | ``` 170 | oproxy start --proxy-port 2555 --storage-server localhost --storage-port 2544 171 | ``` 172 | Либо можно использовать необязательный параметр указания файла той же команды: 173 | ``` 174 | oproxy start --proxy-port 2555 --storage-server localhost --storage-port 2544 --check-file D:\oproxy_folder\Проверки.os 175 | ``` 176 | 177 | ### Файл проверок можно редактировать во время работы сервера 178 | При новом очередном TCP-соединении конфигуратора и хранилища (конфигуратор постоянно подключается и отключается) прокси-сервер увидит, что момент изменения файла проверок стал новым, и переподключит сценарий заново. Новое соединение произойдет, например, при обновлении истории хранилища. Заново загруженный сценарий начнет работать сразу для всех соединений. 179 | 180 | Если в файле проверок будет допущена ошибка, прокси-сервер не будет останавливаться, а при проверочных событиях (помещение и изменение версии) в конфигуратор будет возвращаться ванскриптовая ошибка. 181 | 182 | Файл можно отредактировать "на лету" и исправить ошибку. В новом соединении файл снова перезагрузится. Но лучше все же писать тесты! 183 | 184 | ### Пример отображения ошибки в конфигураторе 185 | 186 | ![error](docs/error.jpg) 187 | 188 | ### Подключение по HTTP 189 | Если вы хотите подключаться к прокси по HTTP, необходимо для начала настроить обычное подключение к хранилищу по HTTP. Далее в файле *.1ccr публикации нужно указать порт прокси-сервера: 190 | 191 | ![error](docs/http.jpg) 192 | 193 | HTTPS - тоже не забота прокси, настраивается в веб-сервере. 194 | 195 | ### Кроссплатформенность и производительность 196 | Протестировано на Windows Server с 1С 8.3.22.2143 и OneScript 1.9.0. Потребление ОЗУ ~50-100 МБ, иногда может вырастать чуть больше на тяжелых операциях, но вскоре сборщик мусора эту память освободит. ERP и бухгалтерия работают с той же скоростью, как и напрямую по tcp. Проверено создание хранилища, подключение, отключение, сравнение версий в разных вариациях, выгрузка файла CF из версии хранилища, захват и помещение объектов конфигурации, в том числе и глобальные, и прочее-прочее-прочее... 197 | 198 | Про Linux и MacOS не знаю - буду рад отзывам! 199 | 200 | ### Приятного использования! 201 | Если вы нашли ошибку работы в прокси или хотите в него добавить какой-то функционал, что-то обсудить или спросить - пожалуйста, напишите в [issues](https://github.com/infina15/oproxy/issues). Если у вас есть желание доработать/отрефакторить/улучшить прокси или адаптировать лучше под Linux и MacOS - ждем ваших [pull requests](https://github.com/infina15/oproxy/pulls) <3 202 | --------------------------------------------------------------------------------