summaryrefslogtreecommitdiff
path: root/libs/curl/curl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'libs/curl/curl.zig')
-rw-r--r--libs/curl/curl.zig103
1 files changed, 103 insertions, 0 deletions
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 @@
1pub const c = @cImport(@cInclude("curl/curl.h"));
2
3const std = @import("std");
4
5const Allocator = std.mem.Allocator;
6const ArrayList = std.ArrayList;
7const File = std.fs.File;
8
9pub fn easyDownload(allocator: Allocator, url: [:0]const u8) ![]u8 {
10 var handle = try Easy.init();
11 defer handle.deinit();
12
13 var buf = ArrayList(u8).init(allocator);
14 defer buf.deinit();
15
16 try handle.setopt(.url, url.ptr);
17 try handle.setopt(.follow_location, true);
18 try handle.setopt(.write_function, easyDownloadCb);
19 try handle.setopt(.write_data, &buf);
20
21 try handle.perform();
22
23 return buf.toOwnedSlice();
24}
25
26fn easyDownloadCb(ptr: [*]const u8, size: usize, nmemb: usize, buf: *ArrayList(u8)) usize {
27 std.debug.assert(size == 1);
28
29 const slice = ptr[0..nmemb];
30 buf.appendSlice(slice) catch |err| {
31 std.log.err("in easyDownloadCb: {}", .{err});
32 return 0;
33 };
34
35 return nmemb;
36}
37
38pub fn easyDownloadToFile(file: *File, url: [:0]const u8) !void {
39 var handle = try Easy.init();
40 defer handle.deinit();
41
42 const writer = file.writer();
43
44 try handle.setopt(.url, url.ptr);
45 try handle.setopt(.follow_location, true);
46 try handle.setopt(.write_function, easyDownloadToFileCb);
47 try handle.setopt(.write_data, &writer);
48
49 try handle.perform();
50}
51
52fn easyDownloadToFileCb(ptr: [*]const u8, size: usize, nmemb: usize, writer: *const File.Writer) usize {
53 std.debug.assert(size == 1);
54
55 const slice = ptr[0..nmemb];
56 writer.writeAll(slice) catch |err| {
57 std.log.err("in easyDownloadToFileCb: {}", .{err});
58 return 0;
59 };
60
61 return nmemb;
62}
63
64pub const Easy = struct {
65 raw: *c.CURL,
66
67 pub const Option = enum(c.CURLoption) {
68 follow_location = c.CURLOPT_FOLLOWLOCATION,
69 url = c.CURLOPT_URL,
70 write_data = c.CURLOPT_WRITEDATA,
71 write_function = c.CURLOPT_WRITEFUNCTION,
72 };
73
74 pub fn init() !Easy {
75 if (c.curl_easy_init()) |raw| {
76 return Easy{ .raw = raw };
77 } else {
78 return error.CurlError;
79 }
80 }
81
82 pub fn deinit(self: *Easy) void {
83 c.curl_easy_cleanup(self.raw);
84 self.* = undefined;
85 }
86
87 pub fn perform(self: *Easy) !void {
88 const errc = c.curl_easy_perform(self.raw);
89 if (errc != c.CURLE_OK) {
90 std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)});
91 return error.CurlError;
92 }
93 }
94
95 pub fn setopt(self: *Easy, option: Option, param: anytype) !void {
96 const option_raw = @enumToInt(option);
97 const errc = c.curl_easy_setopt(self.raw, option_raw, param);
98 if (errc != c.CURLE_OK) {
99 std.log.err("Curl: {s}", .{c.curl_easy_strerror(errc)});
100 return error.CurlError;
101 }
102 }
103};