Веб-сервер: различия между версиями

Материал из CAMaaS preliminary wiki
Перейти к навигации Перейти к поиску
Строка 35: Строка 35:
                             //либо должна быть длины, равной значению cchFileName.
                             //либо должна быть длины, равной значению cchFileName.
   std::size_t cchFileName, //длина строки pszFileName, либо -1, если строка заканчивается терминальным символов
   std::size_t cchFileName, //длина строки pszFileName, либо -1, если строка заканчивается терминальным символов
   bool fEraseContent //флаг удаления содержимого файла, если файл уже существует. Если файл существует, дополнять его новыми данными
   bool fEraseContent //флаг удаления содержимого файла, если файл уже существует. Если файл существует, и флаг сброшен, сервер будет дополнять его новыми данными
);
);
</source>
</source>
Дабы сделать реализацию обработчика HTTP-запросов общей, нужно серверу предоставлять динамическую библиотеку, содержащую известную ему точку входа. Эта точка входа на основе переданного ей идентификатора (изначально указанного клиентом в HTTP запросе) выбирает конкретную функцию для выполнения, распаковывает соответствующим образом (т.е. в соответствии с интерфейсом функции) параметры и вызывает ее.
Пока набор конкретных функций можно не рассматривать, и задать лишь интерфейс обобщенной точки входа:


[[Файл:Web-server-interface.jpg|500px|thumb|интерфейсы]]
[[Файл:Web-server-interface.jpg|500px|thumb|интерфейсы]]


Эта функция, предоставляемая so библиотекой, должна вызываться по следующей схеме:
==Пример запроса к внутрипроцессному серверу==
 
1. Получение размера выходных данных:
<source lang=c>
uint output_size = 0;
entry_point(operation_id,  input_parameters, input_parameters_size, 0, address_of(output_size));
</source>


2. Выделение памяти для выходных параметров веб-сервером и вызов функции еще раз:
<source lang=cpp>
<source lang=c>
auto simulation = CAMaaS::make_package(CAMaaS::sequence_to_pack("Node name"), CAMaaS::sequence_to_pack(strModelName));
byte output[output_size];
char* pProcessName;
entry_point(operation_id, input_parameters, input_parameters_size, output, address_of(output_size));
std::uint32_t cchProcessName;
std::uint32_t nErr = entry_point(StartSimulationId, simulation.data(), simulation.size(), (void**) &pProcessName, &cchProcessName);
if (nErr != 0)
{
  std::cerr << "Error " << nErr << " was returned by the server: " << GetErrorDescription(err, nullptr) << ".\n";
  return "";
}else
{
  auto ret = std::string(pProcessName, cchProcessName);
  FreeData(pProcessName);
  return ret;
}
</source>
</source>
3. Передача выходных параметров клиенту, который их распоковывает и отображает пользователю.


[[Файл:Web-server-flow.png|thumb|500px|обращения]]
[[Файл:Web-server-flow.png|thumb|500px|обращения]]
Написал простенькую so и клиент этой so, демонстрирующую такой протокол на примере простых типов данных и трех простеньких операций. Пока залил на гугл диск:
https://drive.google.com/open?id=0B7qfTPtc54icQ3A2MWllbjhHaDQ.

Версия 15:43, 15 декабря 2015

Веб-сервер должен принимать HTTP запросы, формируемые JS-скриптом на стороне клиента и содержащие запакованные входные параметры вызова серверной функции и идентификатор этой функции. В зависимости от значения идентификатора функции сервер должен обрабатывать запрос самостоятельно[1] либо делегировать вызов внутрипроцессному серверу (DLL, SO) с известной точкой входа:

return_code entry_point( //возвращается код ошибки chsvlib (ноль в случае успешного завершения)
  uint ID, //идентификатор операции
  byte in_params[in_byte_count], //набор байт, содержащий упакованные входные параметры
  uint in_byte_count, //байтовый размер упакованных данных
  byte** out_params[out_byte_count], //буфер, который выделяется внутрипроцессным сервером и инициализируется ответом на запрос.
  uint*  out_byte_count //На выходе - размер выходных данных
);

Внутрипроцессный сервер, в свою очередь, выполняет функции управляющей подсистемы. Также задана функция освобождения памяти, выделенной внутрипроцессным сервером:

return_code_t FreeData( //возвращается код ошибки chsvlib (ноль в случае успешного завершения)
   void* pData // указатель на буфер, выделенный внутрипроцесным сервером,
               // т.е. возвращенный точкой входа entry_point через параметр out_params
);

Коды ошибок, возвращаемых функциями внутрипроцессного сервера, могут быть преобразованы в текстовое описание ошибки с помощью следующей функции:

const char* GetErrorDescription( // возвращается read-only utf-8 C-строка, содержащая текстовое описание ошибки
   uint code, // код ошибки, на основе которого формируется текстовое описание
   uint* pSize // опциональный указатель на 32-битовую переменную, которой функцией присваивается длина строки в байтах. Если длина не нужна, параметр может быть NULL.
);

Кроме этого, возможно ведение журнала ошибок, возникающих на стороне управляющей подсистемы (но не на стороне предметной области, если та не возвращает коды ошибок управляющей подсистеме). Следующая функция позволяет задать файл журнала ошибок в текстовом формате (utf-8) веб-сервером для записи туда событий об ошибок, возникающих на стороне внутрипроцессного сервера.

return_code_t SetErrorLogFile( // возвращается код ошибки chsvlib (ноль в случае успешного завершения)
   const char* pszFileName, //относительный или абсолютный путь к файлу журнала. Строка должна либо завершаться терминальным нулем (в этом случае cchFileName должен быть равен -1),
                            //либо должна быть длины, равной значению cchFileName.
   std::size_t cchFileName, //длина строки pszFileName, либо -1, если строка заканчивается терминальным символов
   bool fEraseContent //флаг удаления содержимого файла, если файл уже существует. Если файл существует, и флаг сброшен, сервер будет дополнять его новыми данными
);
интерфейсы

Пример запроса к внутрипроцессному серверу

auto simulation = CAMaaS::make_package(CAMaaS::sequence_to_pack("Node name"), CAMaaS::sequence_to_pack(strModelName));
char* pProcessName;
std::uint32_t cchProcessName;
std::uint32_t nErr = entry_point(StartSimulationId, simulation.data(), simulation.size(), (void**) &pProcessName, &cchProcessName);
if (nErr != 0)
{
   std::cerr << "Error " << nErr << " was returned by the server: " << GetErrorDescription(err, nullptr) << ".\n";
   return "";
}else
{
   auto ret = std::string(pProcessName, cchProcessName);
   FreeData(pProcessName);
   return ret;
}
обращения
  1. зачем?