From d303b53f2ced75703bf022a5d337ee3ba530b288 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Mon, 25 Apr 2022 05:09:55 +0300 Subject: Initial commit --- libs/curl/curl.zig | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 libs/curl/curl.zig (limited to 'libs/curl') diff --git a/libs/curl/curl.zig b/libs/curl/curl.zig new file mode 100644 index 0000000..4a26eed --- /dev/null +++ b/libs/curl/curl.zig @@ -0,0 +1,103 @@ +pub const c = @cImport(@cInclude("curl/curl.h")); + +const std = @import("std"); + +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; +const File = std.fs.File; + +pub fn easyDownload(allocator: Allocator, url: [:0]const u8) ![]u8 { + var handle = try Easy.init(); + defer handle.deinit(); + + var buf = ArrayList(u8).init(allocator); + defer buf.deinit(); + + try handle.setopt(.url, url.ptr); + try handle.setopt(.follow_location, true); + try handle.setopt(.write_function, easyDownloadCb); + try handle.setopt(.write_data, &buf); + + try handle.perform(); + + return buf.toOwnedSlice(); +} + +fn easyDownloadCb(ptr: [*]const u8, size: usize, nmemb: usize, buf: *ArrayList(u8)) usize { + std.debug.assert(size == 1); + + const slice = ptr[0..nmemb]; + buf.appendSlice(slice) catch |err| { + std.log.err("in easyDownloadCb: {}", .{err}); + return 0; + }; + + return nmemb; +} + +pub fn easyDownloadToFile(file: *File, url: [:0]const u8) !void { + var handle = try Easy.init(); + defer handle.deinit(); + + const writer = file.writer(); + + try handle.setopt(.url, url.ptr); + try handle.setopt(.follow_location, true); + try handle.setopt(.write_function, easyDownloadToFileCb); + try handle.setopt(.write_data, &writer); + + try handle.perform(); +} + +fn easyDownloadToFileCb(ptr: [*]const u8, size: usize, nmemb: usize, writer: *const File.Writer) usize { + std.debug.assert(size == 1); + + const slice = ptr[0..nmemb]; + writer.writeAll(slice) catch |err| { + std.log.err("in easyDownloadToFileCb: {}", .{err}); + return 0; + }; + + return nmemb; +} + +pub const Easy = struct { + raw: *c.CURL, + + pub const Option = enum(c.CURLoption) { + follow_location = c.CURLOPT_FOLLOWLOCATION, + url = c.CURLOPT_URL, + write_data = c.CURLOPT_WRITEDATA, + write_function = c.CURLOPT_WRITEFUNCTION, + }; + + pub fn init() !Easy { + if (c.curl_easy_init()) |raw| { + return Easy{ .raw = raw }; + } else { + return error.CurlError; + } + } + + pub fn deinit(self: *Easy) void { + c.curl_easy_cleanup(self.raw); + self.* = undefined; + } + + pub fn perform(self: *Easy) !void { + const errc = c.curl_easy_perform(self.raw); + if (errc != c.CURLE_OK) { + std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)}); + return error.CurlError; + } + } + + pub fn setopt(self: *Easy, option: Option, param: anytype) !void { + const option_raw = @enumToInt(option); + const errc = c.curl_easy_setopt(self.raw, option_raw, param); + if (errc != c.CURLE_OK) { + std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)}); + return error.CurlError; + } + } +}; -- cgit v1.2.3