Все мы заметили, как перед новым годом фирма 1С активировалась и выпустила сразу две версии платформы 8.3.27 и 8.5.
У меня сложилось впечатление, что 8.5 это был отвлекающий маневр.
Посудите сами…
Сколько раз люди писали, что нужны WebSocket’ы?
На зазеркалье в плане задач 8.3.25 впервые мы увидели их в планах, потом они переносились и вновь на зазеркалье был анонс про 8.3.27 и их реализацию.
А новый воздушный интерфейс я не видел, чтобы просили. Думали, что появится новая платформа версии 9 и там все это будет, потом думали, что 1С: Элемент это и есть 9-ка. Но вдруг перед новым годом пошли анонсы, и стало ясно, что интерфейсу быть в 8.3.27.
Выходит 8.3.27, где появились WebSocket’ы, а интерфейса нет.
И в анонсе интерфейса волшебным образом пропало упоминание платформы 8.3.27. Потом, бац и 8.5 с интерфейсом…
Сколько людей писали про WebSocket’ы с момента их появления в 8.3.27?
Я не нашел свежих обзоров и снял небольшое видео в праздники.
Посмотреть можно тут -> Пример с WebSocket (В видео я подымаю WebSocket-сервер на NodeJS, подключаюсь к нему с веб-страничек, postman’а и 1С. Шлю сообщения в реальном времени.)
А сколько писанины, видосиков, постов, приколов про новый интерфейс?
Знаю только одного человека, который про это не знал…
Я собеседовал соискателя через пару дней, как вышла 8.5, и спросил:
- Что из нашумевших новинок в мире 1С сейчас у всех на слуху?
Он сказал, что не следит за новинками и не в курсе, так как у него нет времени на это…
По большому счету, достаточно было уделить 10-30 минут, чтобы быть в курсе и понять, что в новом интерфейсе «продумана каждая деталь», но не сам интерфейс, и забыть, как страшный сон, до следующих релизов.
Искренне надеюсь, что 8.5 не постигнет участь 8.4.
Кто не в курсе, 8.4 выходила в бете и в ней упоминалась модульность, но так и не вышла в релиз. Хотя я слышал, что кто-то даже внедрял у себя 8.4.
Интересно получилось... Появился механизм, про который стоит поговорить и пощупать, так как он сулит нам большие возможности, но про него тишина.
«То, что ждали, растворилось в хайпе того, что не ждали»
Давайте поговорим наконец о важном, но все по порядку.
Ранее мы имели возможность создавать и цепляться к http-сервисам и это удобно.
По сути http-сервис — это запрос-ответ. Клиент просит у сервера информацию, запускается сессия, во время которой сервер возвращает запрошенные данные.
Это удобно до той поры, пока вам не нужно организовать данные в реальном времени.
Вы, конечно, можете в цикле постоянно опрашивать о изменениях, но это похоже на DDoS-атаку своими силами.
Также вам может понадобиться двухсторонний обмен.
Можно, конечно, поднять два веб-сервера или использовать КД, но что делать, если у вас клиентами выступают: вебсайты, телефоны и прочие клиенты?
И вот тут начинают появляться различные прокладки…
Представьте: Вы сидите за длинным столом и вам захотелось салат с другого края стола. Вы просите у соседа, чтобы он попросил салат. Он просит у соседа и так до тех пор, пока запрос не дойдет до человека, сидящего рядом с салатом. И вот салатница идет по рукам и каждый может попросить себе пару ложечек. А до вас уже может и пустая салатница доехать (наверное, все хоть раз сталкивались с проблемой остатков).
Но наконец то и на улице 1С платформы праздник, на сцену выходят WebSocket’ы.
В отличии от HTTP-сервисов, WebSocket’ы позволяют создать соединение и держать его постоянно открытым, организуя двухсторонний обмен. Клиенты могут слать сообщения на сервер, сервер клиентам и все это практически онлайн.
Представьте: Мальчик подходит к ребятам, играющим в футбол, и спрашивает:
-Можно с вами?
В ответ:
-Да.
И вот они уже играют в футбол все вместе.
Кто-то уходит, кто-то приходит. Игра идет до тех пор, пока есть желающие играть и есть футбольное поле.
Фиксируем:
Протокол для обмена сообщениями между клиентом и сервером, используя постоянное соединение.
Преимущества протокола в том, что после установления соединения клиент и сервер могут начинать двунаправленный обмен сообщениями.
Что схожего у HTTP-Сервисов и WebSocket?
- Оба протокола имеют возможность шифровать трафик (http[S], ws[S])
- Протоколы имеют схожие параметры в том числе и заголовки.
- Оба кроссплатформенные. Простите меня, но не мог не плюнуть в COM.
- У HTTP протокола есть коды ответов, которые хранят в себе информацию по ошибкам или удачном выполнении запроса. У WebSocket есть коды ошибок и коды закрытия.
Например, при закрытии коды:
1000 - нормальное закрытие
1005 - ошибка не указана
- Оба с данного момента поддерживает 1С Платформа
Что же сулят нам WebSocket’ы?
У нас появилась возможность подымать свои WebSocket-серверы и цепляться к ним при помощи платформы 1С, из коробки.
Мы можем цепляться к брокерам и прочим сервисам по данному протоколу.
У нас открываются огромные возможности для интеграций, при этом нам наконец то не нужны внешние компоненты, «поле HTML документа» и прочие прокладки.
Это не значит, что http-сервисы пора выкидывать на помойку. Нет, это значит, что те задачи, которые мы решали при помощи костылей, можно теперь решать по-людски.
Изменения в платформе, связанные с WebSocket-клиентом
- У нас появилась возможность создавать WebSocket-клиенты на стороне клиентской части и на стороне кластера серверов. Сделано это специально, так как на клиенте, либо на сервере по каким-то причинам может отсутствовать доступ к Web Socket соединению. И этого вполне достаточно для организации различных интеграций. Уже есть готовые WebSocket-серверы для различных сервисов, брокеров и другого программного обеспечения. Да и свой WebSocket-сервер поднять труда не составит, главное продумать логику. Я покажу простой вариант, как это сделать.
Тут я кстати вижу огромные плюсы для нас. У нас есть возможность покачать навыки в других языках создавая backend.
- В СУБД у нас появилась таблица [_WebSocketClients]:
Где:
[_ID] – идентификатор таблицы в СУБД.
[_WSCKey] – Web Socket Connect Key. Уникальный ключ, идентификатор соединения
[_MetadataID] – идентификатор в дереве метаданных
[_ServerURL] – сервер подключения к WebSocket. Адрес WebSocket-сервера
[_Predefined] – предопределенный или нет
[_ConnectionParameters] – дополнительные параметры используемые при подключении
[_IBUserName] – пользователь информационной базы, под которым запущено соединение
[_AutoConnect] – автоподключение. Указывает на необходимость автоматического подключения к серверу и восстановления подключения после разрыва соединения
- Мы можем создавать WebSocket-клиент как в конфигурации так и программно(в документации ИТС называют динамическое добавление). Клиенты созданные в дереве конфигурации, доступны только на стороне кластера серверов
В дереве метаданных появился пункт WebSocket-клиенты:
В расширении тоже появилась возможность добавлять WebSocket-клиенты:
В модуле WebSocket-клиента мы можем создать обработчики:
В предметах отладки появились WebSocket и WebSocket(файловый вариант):
Давайте добавим предопределенный WebSocket-клиент в конфигураторе и посмотрим, что изменится в СУБД.
Я специально не установил галочку «Подключаться автоматически»:
Данные в СУБД:
Обратите внимание на WSCKey. Когда мы добавляем WebSocket-клиент в конфигураторе и делаем клиент предопределенным, ключ заполняется автоматически.
- В платформе появилась служебная обработка «Управление WebSocket-клиентами». Она позволяет создавать, удалять и изменять WebSocket-клиенты. Рассказывать про нее нет смысла, моя цель разобрать как это все работает внутри.
Если данную обработку хотите забрать для исследований, тогда можно воспользоваться, например, вот этой обработкой:
На ИТС выделяют три способа создания WebSocket-клиентов:
- Динамические соединения на стороне клиентского приложения
- Динамические соединения на стороне кластера серверов
- WebSocket-клиенты на стороне кластера серверов
Схема работы с WebSocket (источник):
Эксперименты
Создаем WebSocket-сервер
Для демонстрации «WebSocket-клиентов на стороне кластера серверов» я подыму свой WebSocket-сервер на NodeJS.
Нам понадобятся:
- VSC. Качаем и устанавливаем: https://code.visualstudio.com/
- Nodejs. Качаем и устанавливаем: https://nodejs.org/
- Установщик пакетов npm.
- Библиотека ws и код WebSocket сервера.
- 1C 8.3.27 или 8.5
- Postman. Необязательно но желательно. Скачать можно тут -> https://www.postman.com/downloads/
Установка по порядку:
- 1 и 2 пункт качаем и устанавливаем по принципу «далее, далее».
- 3 пункт, инструкция тут -> https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
Команду установки npm можно выполнить в VSC.
Нужно лишь запустить терминал:
И выполнить команду: npm install -g npm
- 4 Пункт. Создаем папку у себя, в которой будет WebSocket-сервер.
В этой папке открываем VSC и запускаем терминал как в пункте 3.
Выполняем команду: npm i ws
После выполнения в папке появятся файлы с описанием библиотек и папка с библиотекой ws.
// Подключаем библиотеку ws
const WebSocket = require("ws");
// Запускаем WebSocket сервер локально на порту 3001
const server = new WebSocket.Server({
port: 3001,
});
// Создаем массив для хранения всех сообщений
const messages = [];
// Делаем обработчик для подключения
server.on("connection", (ws) => {
// Отправляем клиенту все сообщения в формате JSON, которые уже были отправлены
console.log("Client connected"); // информируем в консоли о новом подключении
ws.send(JSON.stringify(messages));
// Делаем обработчик отправки сообщения
ws.on("message", (message) => {
// Получаем сообщение в виде строки
message = message.toString();
// Добавляем сообщение в конец массива
messages.push(message);
// Отправляем все сообщения в формате JSON всем клиентам
server.clients.forEach((client) => {
client.send(JSON.stringify(messages));
});
});
// Делаем обработчик при закрытии сессии клиентом
ws.on("close", () => {
console.log("Client disconnected"); // информация в консоли о отключении клиента
// Отправляем всем клиентам что кто-то отключился
server.clients.forEach((client) => {
client.send("Client disconnected");
});
});
});
// Делаем обработчик ошибок
server.on("error", (error) => {
console.log(error); // Информация в консоли об ошибке
});
// Делаем обработчик закрытия сессии на сервере
server.on("close", () => {
// Отправляем всем информацию о закрытии сессии
server.clients.forEach((client) => {
client.send("Server closed");
});
console.log("Server closed"); //Информация в консоли о закрытии сессии
});
Выполняем команду запуска WebSocket сервера: node index.js
- 5 пункт. Я рассчитываю, что 1С вы сами скачали и установили. Я лично использую комьюнити версию.
- 6 пункт. Необязательный, но postman, по-моему, использует большинство. В нем есть возможность подключаться к WebSocket сессии, а значит мы без труда сможем проверить подключение.
Пункты 2,3,4 и 6 были показаны в видео Пример с WebSocket
Если вы все сделали верно, тогда в postman подключение произойдет без ошибок:
Адрес нашего локального сервера: ws://localhost:3001
Если у вас все получилось, тогда вы увидите следующую картину:
Создаем WebSocket-клиент на стороне кластера серверов
Добавляем WebSocket-клиент прямо в конфигураторе:
В модуле прописываем все обработчики.
Процедура ПередПодключением(Клиент)
ВебСокетыКлиентСервер.ПередПодключением(Клиент);
КонецПроцедуры
Процедура ПриОткрытииСоединения(Соединение)
ВебСокетыКлиентСервер.ПриОткрытииСоединения(Соединение);
КонецПроцедуры
Процедура ПриПолученииСообщения(Соединение, Сообщение)
ВебСокетыКлиентСервер.ПриПолученииСообщения(Соединение, Сообщение);
КонецПроцедуры
Процедура ПриОшибке(Соединение, КодОшибки, Описание)
ВебСокетыКлиентСервер.ПриОшибке(Соединение, КодОшибки, Описание);
КонецПроцедуры
Процедура ПриЗакрытииСоединения(Соединение, КодЗакрытия)
ВебСокетыКлиентСервер.ПриЗакрытииСоединения(Соединение, КодЗакрытия);
КонецПроцедуры
Добавляем модуль, в котором будет происходить общая обработка и запись в регистр с логами:
Процедура ПередПодключением(Клиент) Экспорт
Параметры = ПараметрыКлиента(Клиент);
ЗаписатьВЛог("ПередПодключением",Клиент.Ключ,Параметры);
КонецПроцедуры
Процедура ПриОткрытииСоединения(Соединение) Экспорт
Параметры = ПараметрыСоединения(Соединение);
ЗаписатьВЛог("ПриОткрытииСоединения",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ПриПолученииСообщения(Соединение, Сообщение) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Сообщение",Сообщение);
ЗаписатьВЛог("ПриПолученииСообщения",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ПриОшибке(Соединение, КодОшибки, Описание) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Код",КодОшибки);
Параметры.Вставить("Описание",Описание);
ЗаписатьВЛог("ПриОшибке",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ПриЗакрытииСоединения(Соединение, КодЗакрытия) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Код",КодЗакрытия);
ЗаписатьВЛог("ПриЗакрытииСоединения",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ОбработчикОткрытия(Соединение) Экспорт
Параметры = ПараметрыСоединения(Соединение);
ЗаписатьВЛог("ОбработчикОткрытия",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ОбработчикПолученияСообщения(Соединение, Сообщение) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Сообщение",Сообщение);
ЗаписатьВЛог("ОбработчикПолученияСообщения",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ОбработчикОшибки(Соединение, КодОшибки, Описание) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Код",КодОшибки);
Параметры.Вставить("Описание",Описание);
ЗаписатьВЛог("ОбработчикОшибки",Соединение.Ключ,Параметры);
КонецПроцедуры
Процедура ОбработчикЗакрытия(Соединение, КодЗакрытия) Экспорт
Параметры = ПараметрыСоединения(Соединение);
Параметры.Вставить("Код",КодЗакрытия);
ЗаписатьВЛог("ОбработчикЗакрытия",Соединение.Ключ,Параметры);
КонецПроцедуры
#Область СборПараметров
Функция ПараметрыКлиента(Клиент)
СтруктураКлиент = Новый Структура;
СтруктураКлиент.Вставить("URLСервера", Клиент.URLСервера);
СтруктураКлиент.Вставить("ИмяПользователяИнформационнойБазы", Клиент.ИмяПользователяИнформационнойБазы);
СтруктураКлиент.Вставить("Заголовки", Клиент.ПараметрыСоединения.Заголовки);
СтруктураКлиент.Вставить("МетаданныеИмя", Клиент.Метаданные.Имя);
//СтруктураКлиент.Вставить("МетаданныеЗаголовки", Клиент.Метаданные.Заголовки);
СтруктураКлиент.Вставить("МетаданныеURLСервера", Клиент.Метаданные.URLСервера);
КлиентJSON = ЗаписатьДанныеВJSON(,СтруктураКлиент).Результат;
Параметры = Новый Структура;
Параметры.Вставить("Клиент",КлиентJSON);
Возврат Параметры;
КонецФункции
Функция ПараметрыСоединения(Соединение)
СтруктураСоединение = Новый Структура;
СтруктураСоединение.Вставить("URLСервера", Соединение.URLСервера);
СтруктураСоединение.Вставить("ИмяПользователяИнформационнойБазы", Соединение.ИмяПользователяИнформационнойБазы);
СтруктураСоединение.Вставить("Модуль", Соединение.Обработчики.Модуль);
СтруктураСоединение.Вставить("ОбработчикЗакрытияСоединения", Соединение.Обработчики.ОбработчикЗакрытияСоединения);
СтруктураСоединение.Вставить("ОбработчикОткрытияСоединения", Соединение.Обработчики.ОбработчикОткрытияСоединения);
СтруктураСоединение.Вставить("ОбработчикОшибки", Соединение.Обработчики.ОбработчикОшибки);
СтруктураСоединение.Вставить("ОбработчикПолученияСообщения", Соединение.Обработчики.ОбработчикПолученияСообщения);
СтруктураСоединение.Вставить("Заголовки", Соединение.Параметры.Заголовки);
СоединениеJSON = ЗаписатьДанныеВJSON(,СтруктураСоединение).Результат;
Параметры = Новый Структура;
Параметры.Вставить("Соединение",СоединениеJSON);
Возврат Параметры;
КонецФункции
#КонецОбласти
Процедура ЗаписатьВЛог(Обработчик,Ключ,Параметры=Неопределено)
Дата = ТекущаяДатаСеанса();
Если Не ЗначениеЗаполнено(Параметры) Тогда
Параметры = Новый Структура;
КонецЕсли;
БылаОшибка = Ложь;
Попытка
НаборЗаписей = РегистрыСведений.СобытияВебСокеты.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Дата.Установить(Дата);
НаборЗаписей.Отбор.Обработчик.Установить(Обработчик);
НаборЗаписей.Отбор.Ключ.Установить(Ключ);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() = 0 Тогда
НоваяЗаписьРегистра = НаборЗаписей.Добавить();
НоваяЗаписьРегистра.Дата = Дата;
НоваяЗаписьРегистра.Обработчик = Обработчик;
НоваяЗаписьРегистра.Ключ = Ключ;
Иначе
НоваяЗаписьРегистра = НаборЗаписей[0];
КонецЕсли;
Для Каждого текПараметр Из Параметры Цикл
НоваяЗаписьРегистра[текПараметр.Ключ] = текПараметр.Значение;
КонецЦикла;
НаборЗаписей.Записать();
Исключение
БылаОшибка = Истина;
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Если БылаОшибка Тогда
ЗаписьЖурналаРегистрации("Ошибка",УровеньЖурналаРегистрации.Ошибка,,,ТекстОшибки);
КонецЕсли;
КонецПроцедуры
#Область СериализацияДесериализацияДанных
// Возвращает чаще всего используемые ПараметрыЗаписиJSON (JSONWriterSettings)
//
// Возвращаемое значение:
// Результат - Структура - Стандартное заполнение
//
Функция СтандартныеПараметрыJSON() Экспорт
Результат = Новый Структура;
Результат.Вставить("ПереносСтрок", ПереносСтрокJSON.Авто);
Результат.Вставить("СимволОтступа", " ");
Результат.Вставить("ИспользоватьДвойныеКавычки", Истина);
Результат.Вставить("ЭкранированиеСимволов", ЭкранированиеСимволовJSON.Нет);
Результат.Вставить("ЭкранироватьАмперсанд", Ложь);
Результат.Вставить("ЭкранироватьОдинарныеКавычки", Ложь);
Результат.Вставить("ЭкранироватьРазделителиСтрок", Ложь);
Результат.Вставить("ЭкранироватьУгловыеСкобки", Ложь);
Результат.Вставить("ЭкранироватьСлеш", Ложь);
Возврат Результат;
КонецФункции
// Преобразует данные в формат JSON
//
// Параметры:
// ВходящиеПараметры - Структура - Параметры формирование JSON
// ВходныеДанные - ЛюбоеЗначение - Данные которые нужно перевести в JSON
//
// Возвращаемое значение:
// Результат - Структура
// Отработал - Булево - Выполнено или нет
// ТекстОшибки - Строка - Текст ошибки если функция отработала с ошибкой
// Результат - Строка - JSON
//
Функция ЗаписатьДанныеВJSON(Знач ВходящиеПараметры = Неопределено, Знач ВходныеДанные = "") Экспорт
Результат = Новый Структура("Результат, Отработал, ТекстОшибки", "", Истина, "");
Если ВходящиеПараметры = Неопределено Тогда
ВходящиеПараметры = СтандартныеПараметрыJSON();
КонецЕсли;
ПараметрыJSON = Новый ПараметрыЗаписиJSON(ВходящиеПараметры.ПереносСтрок,
ВходящиеПараметры.СимволОтступа,
ВходящиеПараметры.ИспользоватьДвойныеКавычки,
ВходящиеПараметры.ЭкранированиеСимволов,
ВходящиеПараметры.ЭкранироватьУгловыеСкобки,
ВходящиеПараметры.ЭкранироватьРазделителиСтрок,
ВходящиеПараметры.ЭкранироватьАмперсанд,
ВходящиеПараметры.ЭкранироватьОдинарныеКавычки,
ВходящиеПараметры.ЭкранироватьСлеш);
Попытка
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ПроверятьСтруктуру = Истина;
ЗаписьJSON.УстановитьСтроку(ПараметрыJSON);
ЗаписатьJSON(ЗаписьJSON, ВходныеДанные,,"ФункцияПреобразованияЗаписи",ВебСокетыКлиентСервер);
Результат.Вставить("Результат", ЗаписьJSON.Закрыть());
Исключение
Результат.Отработал = Ложь;
Результат.ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Возврат Результат;
КонецФункции
Функция ФункцияПреобразованияЗаписи(Свойство, Значение, ДополнительныеПараметры, Отказ) Экспорт
Если ТипЗнч(Значение) = Тип("СписокЗначений") Тогда
МассивЗначений = Значение.ВыгрузитьЗначения();
Значение = МассивЗначений;
КонецЕсли;
КонецФункции
// Десериализует строку JSON в формат данных 1С
//
// Параметры:
// СтрокаJSON - Строка - JSON
//
// Возвращаемое значение:
// Результат - Структура
// Отработал - Булево - Выполнено или нет
// ТекстОшибки - Строка - Текст ошибки если функция отработала с ошибкой
// Результат - ЛюбоеЗначение - Данные в формате 1С
//
Функция ЧтениеДанныхИзJSON(Знач СтрокаJSON) Экспорт
Результат = Новый Структура("Отработал, ТекстОшибки", Истина, "");
Попытка
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
Результат.Вставить("Результат", ПрочитатьJSON(ЧтениеJSON));
Исключение
Результат.Отработал = Ложь;
Результат.ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Возврат Результат;
КонецФункции
// Десериализует поток JSON в формат данных 1С
//
// Параметры:
// ПотокJSON - Поток -
//
// Возвращаемое значение:
// Результат - Структура
// Отработал - Булево - Выполнено или нет
// ТекстОшибки - Строка - Текст ошибки если функция отработала с ошибкой
// Результат - ЛюбоеЗначение - Данные в формате 1С
//
Функция ЧтениеПотокаИзJSON(Знач ПотокJSON) Экспорт
Результат = Новый Структура("Отработал, ТекстОшибки", Истина, "");
Попытка
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.ОткрытьПоток(ПотокJSON);
Результат.Вставить("Результат", ПрочитатьJSON(ЧтениеJSON));
Исключение
Результат.Отработал = Ложь;
Результат.ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
Возврат Результат;
КонецФункции
#КонецОбласти
Еще я добавил регистр для логирования событий на всех обработчиках:
На этом подготовительные работы в 1С завершены, можно запускать пример.
Запускаем новую обработку из функций для технического специалиста и нажимаем «Подключить»:
Перед подключением запустился обработчик «ПередПодключением»
Параметры обработчика:
Клиент – тип WebSocketКлиент
В справке есть ошибка в примере, которая вводит в заблуждение:
Обработчик вызывается перед попыткой установить соединение. Позволяет изменить настройки соединенияWebSocketКлиента. Тут можно установить и переопределить настройки.
Что можно переопределить:
- URLСервера
- ИмяПользователяИнформационнойБазы
- ПодключатьАвтоматически
- ? Клиент.ПараметрыСоединения - В справке написано только чтение, но я добавлял заголовки. Ниже пример с доказательством.
Пример кода:
Процедура ПередПодключением(Клиент)
Клиент.URLСервера = "wss://ws.postman-echo.com/raw";
Клиент.ПараметрыСоединения.Заголовки.Вставить("Authorization","Bearer 123");
Клиент.ИмяПользователяИнформационнойБазы = "Администратор";
КонецПроцедуры
После того как установится соединение с сервером запускается обработчик «ПриОткрытииСоединения»
Параметры обработчика:
Соединение – тип WebSocketКлиентСоединение
По большому счету, тут можно уже получить ключ, по которому можно цепляться для отправки сообщений.
Обработчик «ПриПолученииСообщения»
Параметры обработчика:
Соединение – тип WebSocketКлиентСоединение
Сообщение – тип Строка, ДвоичныеДанные
Напоминаю наш WebSocket сервер при подключение присылает все накопленные отправленные ранее сообщения, поэтому мы зацепим еще и этот обработчик.
Сообщений пока не было, поэтому пришел пустой массив:
А вот теперь предлагаю отправить сообщение из postman’a:
В 1С прилетело сообщение:
Теперь давайте в обработке нажмем отключить сообщение:
Обработчик «ПриЗакрытииСоединения»
Соединение – тип WebSocketКлиентСоединение
КодЗакрытия – тип Строка
Мы попадаем в обработчик, в котором можем оценить по какой причине произошло закрытие, для этого у нас есть КодЗакрытия.
1005 – в нашем случае говорит о том, что ошибок не было.
А теперь самое интересное, мы же при закрытии сессии клиента сообщаем всем остальным клиентам, что кто-то покинул сессию.
Смотрим в postman:
Предлагаю еще раз подключится и отправить сообщение.
После подключения заглядываю в регистр логов, чтобы забрать ключ подключения к сессии и за одно посмотреть на историю:
&НаКлиенте
Процедура Команда1(Команда)
Команда1НаСервере();
КонецПроцедуры
Процедура Команда1НаСервере()
СоединенияПоКлючу = "9f442068-bee0-4472-9376-36896c5ed5fa WebSocketКлиентTest";
ВебСокет = WebSocketКлиентСоединения.ПолучитьСоединение(СоединенияПоКлючу);
Если ВебСокет <> Неопределено Тогда
ВебСокет.ОтправитьСообщение("Привет, постман! ПолучитьСоединениЕ по ключу");
КонецЕсли;
ВебСокетЫ = WebSocketКлиентСоединения.ПолучитьСоединения();
Для Каждого ВебСокет из ВебСокетЫ Цикл
Если ВебСокет <> Неопределено Тогда
ВебСокет.ОтправитьСообщение("Привет, постман! ПолучитьСоединениЯ");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
По сути, я попытаюсь найти соединение по ключу и, если найду отправлю сообщение "Привет, постман! ПолучитьСоединениЕ по ключу".
Далее я получу все соединения и отправлю из них сообщение "Привет, постман! ПолучитьСоединениЯ".
Если все пройдет хорошо, тогда postman получит минимум одно сообщение, и мы в 1С получим массив с этими сообщениями.
Первое есть:
Второе есть:
В postman тоже сообщения пришли:
За кадром остался еще один обработчик...
Обработчик «ПриОшибке»
Параметры обработчика:
Соединение – тип WebSocketКлиентСоединение
КодОшибки – тип Строка
Описание – тип Строка
Обработчик вызывается в том случае, если при работе соединения произошла какая-либо аварийная ситуация.
Вот, собственно, и все.
Итоги:
- В первой части мы с вами обсудили, что за зверь этот WebSoket.
- Обсудили подходы у HTTP запросов и у WebSoket’ов.
- Посмотрели на WebSoket’ы в СУБД.
- Посмотрели, как можно создать WebSoket’ы.
- Попользовались новой обработкой.
- Создали свой WebSoket сервер на NodeJS с использованием библиотеки ws.
- Подцепились к своему WebSoket серверу при помощи postman и 1С.
- Разобрали для чего нужны обработчики и нашли неточности в описании.
- Сделали сквозной пример.
Все материалы выложены в GitHub:
На этом завершаю первую часть разбора.
Высплюсь и буду готовить вторую ;)
Всем удачи и интересных проектов!
ТОП-5 ИНСТРУМЕНТОВ ДЛЯ РАЗРАБОТЧИКА 1С
Toolkit, DCT, OneDebugger, PrintWizard, DataFormWizard
со скидкой 20% при покупке от 2х решений!