Привет всем! В настоящее время существует множество приложений, написанных на Vala, которые выполняют HTTP-запросы, а также различные библиотеки, которые могут помочь в этом. В то же время, существует определенный недостаток информации о том, как делать запросы через curl. Эта статья призвана восполнить этот пробел.
Я столкнулся с этой нехваткой информации во время работы над приложением Whaler. Приложение вызывает методы Docker Engine API для управления контейнерами Docker под капотом.
В начале работы над проектом я столкнулся с вопросом: Какую библиотеку использовать для выполнения HTTP-запросов? Существовало важное требование – библиотека должна была поддерживать сокеты UNIX.
Было три варианта:
- GLib.Socket
- libsoup-2.4
- libcurl
GLib.Socket требовал реализации обертки для работы с протоколом HTTP. Libsoup-2.4 не поддерживал сокеты UNIX (они стали доступны начиная с версии 3.0). Поэтому я пропустил первые два варианта и выбрал libcurl. Она имела привязку к Vala и поддерживала сокеты UNIX.
Как добавить libcurl в проект
Прежде всего, проверьте, установлена ли libcurl в вашей системе. Если нет, обязательно установите ее.
Давайте посмотрим на небольшой демонстрационный проект.
Структура папок:
project/
meson.build
app.vala
vapi/
libcurl.vapi
libcurl.deps
Вы можете скачать libcurl.vapi и libcurl.deps на сайте List of Vala Bindings.
meson.build:
project('com.github.sdv43.vala-recipes.curl', 'vala', 'c', version: '1.0.0')
vapi_dir = meson.current_source_dir() / 'vapi'
add_project_arguments(['--vapidir', vapi_dir], language: 'vala')
executable(
meson.project_name(),
'app.vala',
dependencies: [
dependency('glib-2.0'),
meson.get_compiler('vala').find_library('posix'),
meson.get_compiler('vala').find_library('libcurl', dirs: vapi_dir),
meson.get_compiler('c').find_library('libcurl'),
],
)
Теперь мы можем использовать CURL в app.vala:
void main() {
var curl = new Curl.EasyHandle();
// set curl options
var code = curl.perform();
assert_true(code == Curl.Code.OK);
}
Простой интерфейс против многофункционального интерфейса
CURL предоставляет два различных интерфейса: Easy и Multi. Первый работает синхронно, а второй, если я правильно понял, может делать несколько запросов одновременно и работает асинхронно.
Я решил использовать интерфейс Easy, потому что нашел пример, написанный на языке Vala.
Последней проблемой, которую нужно было решить, была проблема с блокировкой потока при вызове curl_perform
.
Я решил выбрать первое решение, которое пришло мне в голову. Это вызов curl_perform
в отдельном потоке с помощью GLib.Task. Это предотвращает блокировку основного потока и позволяет приложению работать корректно. Вот пример:
app.vala:
void main() {
var curl = new Curl.EasyHandle();
// set curl options
var task = new Task (null, null, (source_obj, cl_task) => {
var curl_code = (Curl.Code)cl_task.propagate_int ();
assert_true(curl_code == Curl.Code.OK);
});
task.set_task_data (curl, null);
task.run_in_thread ((cl_task, source_obj, curl, cancellable) => {
unowned var cl_curl = (Curl.EasyHandle)curl;
var code = cl_curl.perform ();
cl_task.return_int (code);
});
}
Окончательное решение, использованное в Whaler, доступно на Github: HttpClient.vala
Ссылки
- Пример Curl от Richard-W
- Список привязок Vala
- Руководство по CURL
Вопросы и что дальше
Я считаю, что это всего лишь один из многих возможных способов выполнения HTTP запросов в Vala. Поэтому я был бы рад услышать ваши мысли:
- Существуют ли другие HTTP-библиотеки для Vala?
- Можно ли создать решение без использования GLib.Task? Может ли интерфейс Multi помочь в этом?