Во время создания очередной B2B-системы на этапе интеграции 1С: Предприятие 8.2 с web — интерфейсом возникла необходимость безопасной передачи файлов больших размеров из 1С в web.
Для решения этой задачи был выбран протокол SFTP, как надежный и не имеющий ограничений по размеру передаваемого файла.
Во встроенном языке 1С: Предприятие 8.2 отсутствуют функции для передачи данных через SFTP, поэтому пришлось искать прикладные средства. На интернет-ресурсах, посвященных программированию 1С, есть примеры удачного использования freeware утилит типа WinSCP. Для использования данного способа необходимо из встроенного языка 1С выполнить запуск утилиты с параметрами командной строки.
Пример запуска утилиты WinCSP из 1С:
КомандаВыгрузки = Символ(34)+Строка(ПутьКПапкеХранилищаФТПФайлов)+"\"+ "WinSCP.com"+Символ(34)+"/script="+Символ(34)+Строка(ПутьКПапкеХранилищаФТПФайлов)+Символ(34)+"\script.txt "+"/parameter "+Символ(34)+Адрес+Символ(34)+" "+
Символ(34)+Ключ+Символ(34)+" "+Символ(34) + Подпапка + Символ(34) + " " +
Символ(34) + ИмяФайлаОтправки + Символ(34);
Минусом такого решения является отсутствие возможности контроля ошибок запуска и выполнения из встроенного языка 1С. В связи с этим было принято решение написать внешнюю DLL компоненту для 1С: Предприятие 8.2.
Платформа 1С: Предприятие поддерживает две технологии создания внешних компонент Native API и COM. Выбор пал на Native API, так как компоненты, созданные по этой технологии работают как на клиенте, так и на сервере 1С. Используя материалы диска ИТС о технологии создания внешних компонент и open source библиотеки С++, был создан файл SftpExtension.dll (Скачать исходники можно тут).
Создание компоненты DLL
1. Для использования в компоненте протокола SFTP мы использовали две библиотеки.
— libssh http://www.libssh2.org/ (Скачиваем “git clone git://git.libssh2.org/libssh2.git”)
— openssl http://www.openssl.org/ (Скачиваем архив openssl-1.0.1c.tar.gz от сюда)
Подключаем библиотеки к проекту.
2. Каждый объект компоненты должен наследоваться от абстрактного класса IcomponentBase и IlanguageInterface.
- IcomponentBase — реализует основные методы компоненты.
- IlanguageInterface — служит для локализации методов и свойств 1С и С++ через определения массивов соответствий и методов акцессоров GetMethodName, GetPropName.
Часть кода компоненты описывающая возможность вызова функций С++ из 1С на русском языке:
При этом можно использовать другие языки.
static wchar_t *g_MethodNames[] = { L"SendFile",L"StartSession", L"EndSession", L"IsSessionStart",L"SetSshHost",L"SetSshLogin",L"SetSshPass",L"SetSftpPath",L"SetLocalPath"};
static wchar_t *g_MethodNamesRu[] = {
L"ПослатьФайл",L"НачатьСессию",L"ЗакончитьСессию",L"ЕслиСессияНачата",
L"УстановитьХост",L"УстановитьЛогин",L"УстановитьПароль", L"УстановитьУдаленныйПуть",L"УстановитьЛокальныйПуть"};
const WCHAR_T* SftpExtension::GetMethodName(const long lMethodNum, const long lMethodAlias)
{
if (lMethodNum >= eMethLast)
return NULL;
wchar_t *wsCurrentName = NULL;
WCHAR_T *wsMethodName = NULL;
int iActualSize = 0;
switch(lMethodAlias)
{
case 0: // First language
wsCurrentName = g_MethodNames[lMethodNum];
break;
case 1: // Second language
wsCurrentName = g_MethodNamesRu[lMethodNum];
break;
default:
return 0;
}
iActualSize = wcslen(wsCurrentName)+1;
if (m_iMemory && wsCurrentName)
{
if(m_iMemory->AllocMemory((void**)&wsMethodName, iActualSize * sizeof(WCHAR_T)))
::convToShortWchar(&wsMethodName, wsCurrentName, iActualSize);
}
return wsMethodName;
}
3. Для вызова необходимой функции из компоненты используется метод CallAsFunc из интерфейса IcomponentBase. При вызове методов из компоненты 1С, вызывается этот С++ метод.
В качестве параметров метода используются:
- lMethodNum – номер метода в массиве соответствий.
- pvarRetValue – указатель на выходные параметры.
- paParams — параметры из метода в 1С.
- lSizeArray – размер массива, если входной параметр массив.
bool SftpExtension::CallAsFunc(const long lMethodNum,
tVariant* pvarRetValue,tVariant* paParams, const long lSizeArray){
switch(lMethodNum){
case eMethSendFile:
{
if (!lSizeArray || !paParams)
return false;
this->local_path = toChar(paParams);
WriteToServer(status, this->local_path); //
pvarRetValue->pstrVal = status; //status
pvarRetValue->strLen = strlen(pvarRetValue->pstrVal);
TV_VT(pvarRetValue) = VTYPE_PSTR;
ret = true;
break;
} }
return ret;
}
4. В нашем примере из 1С можно выполнять 4 метода, которым соответствуют С++ методы в DLL компоненте.
1С (методы) | С++ методы |
---|---|
НачатьСессию() Предварительно нужно определить параметры авторизации(хост, связку логин, пароль – либо rsa ключи, путь на удалённом сервере). Поэтому функция НачатьСессию обрастает свойствами: Хост, Логин, Пароль, УдаленныйПуть |
StartSSHSession(status,this->ssh_host,this->ssh_login,this->ssh_pass); StartSftpSession(status,this->sftp_path) |
ПослатьФайл(“Путь и имя файла на клиентской машине”) |
WriteToServer(const char * &status, const char *loclfile) |
ЕслиСессияНачата() | isSessionStart() |
ЗакончитьСессию() | endSession() – завершает SFTP сеанс и SSH сеанс |
5. В С++ нужно определить параметры доступа(чтение/запись) к созданным свойствам за это отвечают два метода IsPropReadable и IsPropWritable.
bool SftpExtension::IsPropReadable(const long lPropNum)
{
switch(lPropNum)
{
case ePropSshHost:
return true;
default:
return false;
}
return false;}
Таблица соотношений свойств 1С и С++
1С(свойства) | С++ свойства |
---|---|
Хост | ssh_host |
Логин | ssh_login |
Пароль | ssh_pass |
УдаленныйПуть | Sftp_path |
Готовую библиотеку можно скачать тут.
Работа с компонентой во встроенном языке 1С
1. Выполняем подключение и создаем объект внешней компоненты, с помощью стандартных команд встроенного языка 1С.
ПодключитьВнешнююКомпоненту("C:\SftpExtension\SftpExtension.dll","Компонента",ТипВнешнейКомпоненты.Native);
Компонента = Новый("AddIn.Компонента.SftpExtension");
2. Заполняем 4 свойства объекта компоненты Хост, Логин, Пароль, УдаленныйПуть.
Компонента.Хост = "192.168.0.1";
Компонента.Логин = "root";
Компонента.Пароль = "123";
Компонента.УдаленныйПуть = "/var/www/company/data/www/import/data.xml";
3. Открываем сессию соединения
Компонента.НачатьСессию();
4. Отправляем файл
Компонента.ПослатьФайл("C:\data.xml");
5. Отправляем следующий файл, с проверкой открыта ли сессия соединения.
Если Компонента.СессияНачата() Тогда
Компонента.ПослатьФайл("C:\data2.xml");
Иначе
Компонента.НачатьСессию();
Компонента.ПослатьФайл("C:\data2.xml");
КонецЕсли;
6. После отправки файлов закрываем сессию
Компонента.ЗакончитьСессию();
В результате выполнения успешно был передан файл с C:\data2.xml в /var/www/company/data/www/import/data.xml.
Используемые материалы
Литература:
Мануал по созданию компоненты
Библиотеки для работы по SFTP:
- libssh http://www.libssh2.org/
- openssl http://www.openssl.org/
Вывод: данная реализация позволяет передавать файлы из 1С: Предприятие 8.2. большого размера по защищенному протоколу SFTP. Плюс появляется возможность переносить часть функционала из 1С во внешнюю компоненту, что защищает написанный код и позволяет реализовывать дополнительный, не доступный 1С функционал.