Компания, в которой я в данный момент работаю, решила активно пользоваться расширениями, начиная с 8.3.8 для облегчения обновления 1С Розница, вынеся в расширения большую часть интерфейсных и не только модификаций. До недавнего времени, вся наша филиальная сеть магазинов работала напрямую через веб-сервер, но из-за того что покрытие интернетом не везде хорошее, стали постепенно задумываться о разворачивании РИБ узлов в таких проблемных магазинах и тут же встал вопрос, "Что делать с расширением?" и так как мы сделали обмен через веб-сервис, решили "А почему бы не передавать расширение узлу через веб-сервис?".
Теперь я хочу представить вам то, как мы решили эту проблему.
В нашем веб-сервисе мы добавили функцию "GetExtandedConfig" с параметрами:
- Name, Направление передачи: Входящий, Тип: string - Имя расширения
- Hash, Направление передачи: Входящий, Тип: string - Хеш установленного расширения либо Неопределено если не установлено
- Result, Направление передачи: Выходной, Тип: boolean - Результат операции
- Data, Направление передачи: Выходной, Тип: ValueStorage (http://v8.1c.ru/8.1/data/core) - Двоичные данные установленного расширения центральной базы (если изменений расширения нет, то Неопределено)
- Функция возвращает тип: string - Описание проблемы, если таковая возникла
В коде функции мы написали это:
// Соответствует операции GetExtandedConfig
Функция ПолучитьРасширениеКонфигурации(ИмяРасширения, ХешСумма, Результат, ИсхДанные)
УстановитьПривилегированныйРежим(Истина); // Пользователь вебсервиса не полноправный пользователь, компенсируем это
Если ПустаяСтрока(ИмяРасширения) Тогда
Результат = Ложь;
Возврат "Не указано имя расширения!";
КонецЕсли;
Расширения = РасширенияКонфигурации.Получить(Новый Структура("Имя", ИмяРасширения)); // Ищем расширение по полученному имени
Если Расширения.Количество() <= 0 Тогда
Результат = Ложь;
Возврат "Расширение по указанному имени не найдено!";
КонецЕсли;
ТребуемоеРасширение = Расширения[0];
Если ПустаяСтрока(ХешСумма) или ХешСумма <> Base64Строка(ТребуемоеРасширение.ХешСумма) Тогда // Либо первое получение, либо расширение изменилось
Результат = Истина;
ИсхДанные = Новый ХранилищеЗначения(ТребуемоеРасширение.ПолучитьДанные()); // Сжимать смысла нет, только ресурсы тратить
Возврат "Доступно обновление расширения";
КонецЕсли;
Результат = Истина;
Возврат "Нет обновлений расширения";
КонецФункции // ПолучитьРасширениеКонфигурации()
На "клиентской" стороне, после обмена данными через веб-сервис, проверяем, есть ли изменения в расширении и код выглядит так:
Функция ДоступнаЗащитаОтОпасныхДействий() Экспорт
СисИнфо = Новый СистемнаяИнформация;
Возврат ОбщегоНазначенияКлиентСервер.СравнитьВерсии(СисИнфо.ВерсияПриложения, "8.3.9.2033") >= 0;
КонецФункции // ДоступнаЗащитаОтОпасныхДействий()
Процедура ПроверитьИОбновитьРасширениеКонфигурации(ПроцессорОбмена) Экспорт
// ПроцессорОбмена - WS-ссылка с установленным соединением
ПоддержкаЗащитыОтОпасныхДействий = ДоступнаЗащитаОтОпасныхДействий(); // Проверим, поддерживает ли платформа защиту от опасных действий
Попытка
МассивОбновляемыхРасширений = Новый Массив;
Расширения = РасширенияКонфигурации.Получить(); // Получаем список установленных расширений
Для Каждого Расширение из Расширения Цикл
МассивОбновляемыхРасширений.Добавить(Новый Структура("Имя, УникальныйИдентификатор, ХешСумма", Расширение.Имя, Расширение.УникальныйИдентификатор, Расширение.ХешСумма));
КонецЦикла;
Если МассивОбновляемыхРасширений.Количество() <= 0 Тогда // Если расширений в базе нет, добавляем в список "предопределенное" расширение, наше основное
МассивОбновляемыхРасширений.Добавить(Новый Структура("Имя, УникальныйИдентификатор, ХешСумма", "Экстра", Неопределено, Неопределено));
ИначеЕсли ОбменДаннымиСервер.ТребуетсяУстановкаОбновления() Тогда
// Расширение уже есть, но сейчас требуется обновление конфигурации, по этому не будем пока обновлять расширение.
// Сделано так, чтоб при первом запуске из начального образа базы, даже если есть изменения конфигурации,
// расширение бы скачалось и установилось, а если расширение есть, то не качаем его пока не применим изменения.
КонецЕсли;
Для Каждого Расширение из МассивОбновляемыхРасширений Цикл
Результат = Неопределено;
ВходящиеДанные = Неопределено;
// Делаем запрос к веб-сервису
СообщениеОбмена = ПроцессорОбмена.GetExtandedConfig(Расширение.Имя, Base64Строка(Расширение.ХешСумма), Результат, ВходящиеДанные);
Если Результат и Не ПустаяСтрока(СообщениеОбмена) Тогда
// Получили положительный ответ и что не было сообщений, а так-же проверим, получили ли мы сами данные
Если ВходящиеДанные = Неопределено Тогда
Продолжить;
КонецЕсли;
Иначе
Сообщить("При получении обновления расширения: " + Расширение.Имя + " была получена ошибка: " + СообщениеОбмена);
Продолжить;
КонецЕсли;
ДанныеРасширения = ВходящиеДанные.Получить(); // Получаем двоичные данные из хранилища значения
// Получены данные расширения, обработаем
Если Расширение.УникальныйИдентификатор = Неопределено Тогда // Расширение ещё не установлено
РасширениеВБазе = РасширенияКонфигурации.Создать(); // Создаем новое расширение
РасширениеВБазе.БезопасныйРежим = Ложь;
Если ПоддержкаЗащитыОтОпасныхДействий Тогда
РасширениеВБазе.ЗащитаОтОпасныхДействий.ПредупреждатьОбОпасныхДействиях = Ложь; // Отключаем защиту от опасных действий если поддерживается
КонецЕсли;
Иначе // Получаем уже установленное расширинение старой версии
Раширения = РасширенияКонфигурации.Получить(Новый Структура("УникальныйИдентификатор", Расширение.УникальныйИдентификатор));
Если Расширения.Количество() > 0 Тогда
РасширениеВБазе = Расширения[0];
КонецЕсли;
КонецЕсли;
Если РасширениеВБазе = Неопределено Тогда
Сообщить("При обновлении раширения произошла ошибка, не удалось получить расширение: " + Расширение.Имя);
Продолжить;
КонецЕсли;
// Проверим, можно ли без ошибок применить расширение
ОшибкиВРасширении = РасширениеВБазе.ПроверитьВозможностьПрименения(ДанныеРасширения); // Возвращает ИнформацияОПроблемеПримененияРасширенияКонфигурации
Если ОшибкиВРасширении.Количество() > 0 Тогда
Сообщить("При проверке расширения " + Расширение.Имя + ", возникли ошибки:");
// Покажем полный список ошибок
Для Каждого Ошибка из ОшибкиВРасширении Цикл
Сообщить("(" + Ошибка.Важность + ") " + Расширение.Имя + ": " + Ошибка.Описание);
КонецЦикла;
// Не будем его устанавливать
Продолжить;
КонецЕсли;
// Всё хорошо! Обновляем расширение!
РасширениеВБазе.Записать(ДанныеРасширения);
Сообщить("Успешно обновлено расширение: " + Расширение.Имя + ", получена версия: " + РасширениеВБазе.Версия);
КонецЦикла;
Исключение
Сообщить("Ошибка в процедуре обновления расширения: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Вот и всё! Но, как и в каждой бочке, и тут есть ложка дёгтя, о чем и хотелось отдельно упомянуть.
Проблемы механизма
Одна из главных проблем механизма, это то что он не связан тесно с передачей изменений конфигурации, а работает параллельно с ним и в связи с чем может возникнуть ситуация когда к примеру ещё не передан новый предопределенный элемент (Справочника, ПВХ и пр.), а обновленное расширение к нему уже обращается, и контроль "применимости" расширения не видит этой проблемы. Но я думаю, что это не существенная проблема, учитывая, сколько данный механизм решает проблем, да и после получения узлом недостающих данных, проблема уходит.
Заключение
Данный механизм не претендует на какую-либо уникальность, скорей желание показать, что и такую задачу можно разрешить достаточно простым способом. Также я хотел бы сказать, что этот механизм был сделан в спешке из-за наступления дедлайна на пятки и стоило добавить контроль минимальной версии конфигурации для того чтобы не возникло ситуации описанной выше да и качество кода оставляет желать лучшего.
Будут вопросы, обращайтесь!
PS: Если вы используете обмен через файлы (в той или иной вариации), то вы можете при отправке данных центральной базе, добавлять информацию о хеше установленного расширения, а центральной проверять эту добавку и по мимо полезных данных обмена, выгружать расширение актуальной версии. Практически так-же как и БСП добавляет свои данные в сообщение обмена. Ознакомится с примерами дополнения сообщения обмена своими данными, можно ознакомится в статье: https://its.1c.ru/db/metod8dev#content:2278:hdoc Кстати, 8.3.12 делает именно так, она передает полностью расширение, а не изменившуюся часть.