1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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;
}
}
};
|