├── .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)
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 | 
187 |
188 | ### Подключение по HTTP
189 | Если вы хотите подключаться к прокси по HTTP, необходимо для начала настроить обычное подключение к хранилищу по HTTP. Далее в файле *.1ccr публикации нужно указать порт прокси-сервера:
190 |
191 | 
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 |
--------------------------------------------------------------------------------