В платформе 8.3.11 наконец были добавлены функции создания обработчиков оповещений при получении сообщений от сервера взаимодействий. Здесь мы не будем рассматривать вопросы установки или настройки самого сервера взаимодействий, регистрацию базы на нем и т.п. - это все описано в этой статье.
Для знакомства с новыми функциями создадим новую пустую конфигурацию, в которой добавим общий универсальный обработчик сообщений от сервера. Таким образом, у нас сообщения будут обрабатываться независимо от того, какие формы открыты.
Итак, начинаем с модуля управляемого приложения. При начале работы системы:
- Проверяем, что база зарегистрирована на сервере взаимодействия.
- Получаем из константы значение уникального идентификатора обсуждения для наших универсальных сообщений севера.
- Проверяем существование обсуждения с таким идентификатором.
- Если обсуждение не существует, то создаем его c полученным из константы идентификатором.
- Добавляем текущего пользователя в участники обсуждения.
- Создаем два оповещения: одно оповещение успешного подключения обработчика новых сообщений, второе оповещение о получении нового сообщения.
- Подключаем оповещение о новых сообщениях функцией НачатьПодключениеОбработчикаНовыхСообщений.
Модуль управляемого приложения
Процедура ПриНачалеРаботыСистемы()
ПодключениеСистемыВзаимодействия();
КонецПроцедуры
Процедура ПодключениеСистемыВзаимодействия()
Если НЕ СистемаВзаимодействия.ИнформационнаяБазаЗарегистрирована() Тогда
Возврат;
КонецЕсли;
ИдентификаторОбсужденияСтрока = СерверВзаимодействияПривилегированный.ПолучитьЗначениеКонстанты("ИдентификторОбсужденияСерверныхСообщенийБезКонтекста");
Если ЗначениеЗаполнено(ИдентификаторОбсужденияСтрока) Тогда
ИдентификаторОбсуждения = Новый ИдентификаторОбсужденияСистемыВзаимодействия(ИдентификаторОбсужденияСтрока);
Если НЕ СерверВзаимодействияПривилегированный.ОбсуждениеСуществует(ИдентификаторОбсуждения) Тогда
ИдентификаторОбсуждения = СерверВзаимодействияПривилегированный.СоздатьОбсуждениеБезКонтекста();
КонецЕсли;
СерверВзаимодействияПривилегированный.ДобавитьТекущегоПользователяВОбсуждение(ИдентификаторОбсуждения);
ОписаниеОповещенияПодключенияОбработчика = Новый ОписаниеОповещения("ОбработкаОповещенияПодключенияСерверныхСообщенийБезКонтекста", КлиентскиеФункции,);
ОписаниеОповещенияСерверныхСообщенийБезКонтекста = Новый ОписаниеОповещения("ОбработкаОповещенияСерверныхСообщенийБезКонтекста", КлиентскиеФункции,);
СистемаВзаимодействия.НачатьПодключениеОбработчикаНовыхСообщений(ОписаниеОповещенияПодключенияОбработчика, ИдентификаторОбсуждения, ОписаниеОповещенияСерверныхСообщенийБезКонтекста);
КонецЕсли;
КонецПроцедуры
Оповещение об успешном подключении обработчика может пригодиться, если у вас в логике конфигурации на этих оповещениях будет многое завязано и без подключенного обработчика логика будет страдать. Не стоит забывать что сервер взаимодействия это отдельная служба, база данных которой лежит на Postgre со всеми связанными с эти рисками.
Теперь рассмотрим служебный модуль работы с функциями системы уведомления. Модуль привилегированный.
Модуль "СерверВзаимодействияПривилегированный"
Функция ПолучитьЗначениеКонстанты(ИмяКонстанты) Экспорт
Возврат Константы[ИмяКонстанты].Получить();
КонецФункции
Функция СоздатьОбсуждениеБезКонтекста() Экспорт
НовоеОбсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
НовоеОбсуждение.Отображаемое = ЛОЖЬ;
НовоеОбсуждение.Ключ = Строка(Новый УникальныйИдентификатор);
НовоеОбсуждение.Записать();
Константы.ИдентификторОбсужденияСерверныхСообщенийБезКонтекста.Установить(Строка(НовоеОбсуждение.Идентификатор));
Возврат НовоеОбсуждение.Идентификатор;
КонецФункции
Функция ОбсуждениеСуществует(ИдентификаторОбсуждения) Экспорт
Возврат СистемаВзаимодействия.ПолучитьОбсуждение(ИдентификаторОбсуждения) <> неопределено;
КонецФункции
Процедура ДобавитьТекущегоПользователяВОбсуждение(ИдентификаторОбсуждения) Экспорт
Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение(ИдентификаторОбсуждения);
Если Обсуждение.Участники.Содержит(СистемаВзаимодействия.ИдентификаторТекущегоПользователя()) Тогда
Возврат;
КонецЕсли;
Обсуждение.Участники.Добавить(СистемаВзаимодействия.ИдентификаторТекущегоПользователя());
Обсуждение.Записать();
КонецПроцедуры
Функция ПолучитьИдентификаторТекущегоПользователя() Экспорт
Возврат СистемаВзаимодействия.ИдентификаторТекущегоПользователя();
КонецФункции
Процедура СоздатьСообщение(Параметры) Экспорт
Если СистемаВзаимодействия.ИнформационнаяБазаЗарегистрирована() Тогда
ИдентификаторОбсужденияСтрока = Константы.ИдентификторОбсужденияСерверныхСообщенийБезКонтекста.Получить();
ИдентификаторОбсуждения = Новый ИдентификаторОбсужденияСистемыВзаимодействия(ИдентификаторОбсужденияСтрока);
Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение(ИдентификаторОбсуждения);
ОтветственныйПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(Строка(Параметры.Ответственный));
ИдентификаторПользователяСВ = СистемаВзаимодействия.ПолучитьИдентификаторПользователя(ОтветственныйПользовательИБ.УникальныйИдентификатор);
НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(ИдентификаторОбсуждения);
НовоеСообщение.Данные = Параметры.Ссылка;
НовоеСообщение.Получатели.Добавить(ИдентификаторПользователяСВ);
НовоеСообщение.Дата = ТекущаяДата();
НовоеСообщение.Текст = "Записан документ " + Параметры.Ссылка;
НовоеСообщение.Записать();
КонецЕсли;
КонецПроцедуры
Функция СоздатьОбсуждениеБезКонтекста: создает новое обсуждение, признак "Отображаемое" выставляем в ЛОЖЬ, чтобы обсуждение не появилось в стандартном интерфейсе уведомлений пользователей. После записи идентификатора записываем в константу. Функция вызывается только один раз (вопросы возможного одновременного создания обсуждений несколькими пользователями не будем тут рассматривать)
Функция ОбсуждениеСуществует проверяет существование обсуждения по его идентификатору.
Функция ДобавитьТекущегоПользователяВОбсуждение добавляет идентификатор текущего пользователя в обсуждение, если он туда еще не добавлен.
Функция ПолучитьИдентификаторТекущегоПользователя получает идентификатор текущего пользователя.
Функция СоздатьСообщение создает новое сообщение в обсуждения с переданными параметрами (Ищет пользователя по представлению параметра "Ответственный", в текст сообщения вставляет ссылку на документ)
В модуле документа "СчетНаОплату" в обработчике ПриЗаписи добавим код.
Модуль документа "Счет на оплату"
Процедура ПриЗаписи(Отказ)
СерверВзаимодействияПривилегированный.СоздатьСообщение(Новый Структура("Ссылка, Ответственный", Ссылка, Ответственный));
КонецПроцедуры
В результат при записи документа (на сервере) ответственному из счета на оплату будет отправляться сообщение том, что документ был записан.
Модуль "КлиентскиеФункции"
Процедура ОбработкаОповещенияПодключенияСерверныхСообщенийБезКонтекста(ДополнительныеПараметры) Экспорт
//Тут обработка ошибок подключения обработчика
Сообщить("Обработчик подключен.");
КонецПроцедуры
Процедура ОбработкаОповещенияСерверныхСообщенийБезКонтекста(Сообщение, ДополнительныеПараметры) ЭКспорт
//Тут обработка присланного сообщения
Если Сообщение.Получатели.Содержит(СерверВзаимодействияПривилегированный.ПолучитьИдентификаторТекущегоПользователя()) Тогда
Сообщить(Сообщение.Текст);
КонецЕсли;
КонецПроцедуры
В модуле КлиентскиеФункции описаны функции оповещения подключения обработчика и самого обработчика сообщений. В обработчике сообщения проверяется, что текущий пользователь входит в число получателей сообщения, и выводится сообщение о записи документа. В качестве данных сообщения передается ссылка на записанный документ.
В статье не были затронуты вопросы оптимизации, используемых функций. Бесспорно, функцию создания сообщения часто имеет смысл выносить в фоновое задание. Возможно, при большом количестве пользователей имеет смысл создать каждому пользователю свое обсуждение, чтобы клиентские сеансы не тратили свое время на проверку получателей заведомо ненужных сообщений (т.к. сервер знает получателей, находит обсуждения этих пользователей и отсылает сообщения только им). Также стоит учитывать, что очередь сообщений сохраняется на сервере взаимодействия, и при первом входе в 1С пользователь получит их все.
Но даже в такой реализации мы избавляем клиентские сеансы от постоянных обращений к серверу из обработчиков ожидания.