Опыт передачи файлов большого объема по защищенному протоколу из 1С на сайт

от автора


Во время создания очередной 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:

Вывод: данная реализация позволяет передавать файлы из 1С: Предприятие 8.2. большого размера по защищенному протоколу SFTP. Плюс появляется возможность переносить часть функционала из 1С во внешнюю компоненту, что защищает написанный код и позволяет реализовывать дополнительный, не доступный 1С функционал.

ссылка на оригинал статьи http://habrahabr.ru/company/Centrobit/blog/165441/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *