This commit is contained in:
oupson 2022-01-19 21:35:59 +01:00
parent 558c157601
commit d5175d9f19
2 changed files with 52 additions and 19 deletions

View File

@ -35,6 +35,7 @@ pub const Client = struct {
} }
pub fn getJSON(self: *@This(), comptime T: type, url: [*:0]const u8, headers: ?*std.StringHashMap([]const u8)) anyerror!T { pub fn getJSON(self: *@This(), comptime T: type, url: [*:0]const u8, headers: ?*std.StringHashMap([]const u8)) anyerror!T {
var response_buffer = std.ArrayList(u8).init(self.allocator.*);
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_URL, url) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_URL, url) != cURL.CURLE_OK)
return error.CURLPerformFailed; return error.CURLPerformFailed;
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_HTTPGET, @as(c_long, 1)) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_HTTPGET, @as(c_long, 1)) != cURL.CURLE_OK)
@ -48,8 +49,8 @@ pub const Client = struct {
var header_slist: [*c]cURL.curl_slist = null; var header_slist: [*c]cURL.curl_slist = null;
if (headers) |h| { if (headers) |header| {
var iterator = h.iterator(); var iterator = header.iterator();
while (iterator.next()) |entry| { while (iterator.next()) |entry| {
var buf = try self.allocator.alloc(u8, entry.key_ptr.*.len + 3 + entry.value_ptr.*.len); var buf = try self.allocator.alloc(u8, entry.key_ptr.*.len + 3 + entry.value_ptr.*.len);
@ -68,7 +69,6 @@ pub const Client = struct {
return error.CURLSetOptFailed; return error.CURLSetOptFailed;
} }
var response_buffer = std.ArrayList(u8).init(self.allocator.*);
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_WRITEFUNCTION, writeToArrayListCallback) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_WRITEFUNCTION, writeToArrayListCallback) != cURL.CURLE_OK)
return error.CURLSetOptFailed; return error.CURLSetOptFailed;
@ -81,7 +81,7 @@ pub const Client = struct {
if (header_slist != null) if (header_slist != null)
cURL.curl_slist_free_all(header_slist); cURL.curl_slist_free_all(header_slist);
var stream = json.TokenStream.init(response_buffer.items); var stream = json.TokenStream.init(response_buffer.toOwnedSlice());
@setEvalBranchQuota(10_000); @setEvalBranchQuota(10_000);
const res = json.parse(T, &stream, .{ .allocator = self.allocator.*, .ignore_unknown_fields = true }); const res = json.parse(T, &stream, .{ .allocator = self.allocator.*, .ignore_unknown_fields = true });
@ -92,9 +92,13 @@ pub const Client = struct {
} }
pub fn postJSON(self: *@This(), url: []const u8, data: anytype, headers: ?std.StringHashMap([]const u8)) anyerror![]const u8 { pub fn postJSON(self: *@This(), url: []const u8, data: anytype, headers: ?std.StringHashMap([]const u8)) anyerror![]const u8 {
var post_buffer = std.ArrayList(u8).init(self.allocator.*);
var response_buffer = std.ArrayList(u8).init(self.allocator.*);
var rawUrl = try self.allocator.allocSentinel(u8, url.len, 0); var rawUrl = try self.allocator.allocSentinel(u8, url.len, 0);
std.mem.copy(u8, rawUrl, url); std.mem.copy(u8, rawUrl, url);
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_URL, url.ptr) != cURL.CURLE_OK)
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_URL, rawUrl.ptr) != cURL.CURLE_OK)
return error.CURLPerformFailed; return error.CURLPerformFailed;
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_NOPROGRESS, @as(c_long, 1)) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_NOPROGRESS, @as(c_long, 1)) != cURL.CURLE_OK)
return error.CURLPerformFailed; return error.CURLPerformFailed;
@ -121,8 +125,6 @@ pub const Client = struct {
header_slist = cURL.curl_slist_append(header_slist, "Content-Type: application/json"); header_slist = cURL.curl_slist_append(header_slist, "Content-Type: application/json");
var post_buffer = std.ArrayList(u8).init(self.allocator.*);
try json.stringify(data, .{}, post_buffer.writer()); try json.stringify(data, .{}, post_buffer.writer());
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_POST, @as(c_long, 1)) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_POST, @as(c_long, 1)) != cURL.CURLE_OK)
@ -145,7 +147,6 @@ pub const Client = struct {
return error.CURLSetOptFailed; return error.CURLSetOptFailed;
} }
var response_buffer = std.ArrayList(u8).init(self.allocator.*);
if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_WRITEFUNCTION, writeToArrayListCallback) != cURL.CURLE_OK) if (cURL.curl_easy_setopt(self.ptr, cURL.CURLOPT_WRITEFUNCTION, writeToArrayListCallback) != cURL.CURLE_OK)
return error.CURLSetOptFailed; return error.CURLSetOptFailed;
@ -159,9 +160,9 @@ pub const Client = struct {
cURL.curl_slist_free_all(header_slist); cURL.curl_slist_free_all(header_slist);
self.allocator.free(rawUrl); self.allocator.free(rawUrl);
post_buffer.deinit();
var res = response_buffer.toOwnedSlice(); var res = response_buffer.toOwnedSlice();
response_buffer.deinit(); response_buffer.deinit();
return res; return res;

View File

@ -94,15 +94,39 @@ const Config = struct {
var stat = try file.stat(); var stat = try file.stat();
const file_buffer = try allocator.alloc(u8, stat.size); const file_buffer = try allocator.alloc(u8, stat.size);
_ = try file.readAll(file_buffer); _ = try file.readAll(file_buffer);
file.close();
var stream = json.TokenStream.init(file_buffer); var stream = json.TokenStream.init(file_buffer);
return json.parse(@This(), &stream, .{ .allocator = allocator }); const res = json.parse(@This(), &stream, .{ .allocator = allocator });
allocator.free(file_buffer);
return res;
} }
}; };
const User = struct { user_login: []u8 }; const User = struct { user_login: []u8 };
var wait_event = std.Thread.StaticResetEvent{};
fn handler_fn(_: c_int) callconv(.C) void {
wait_event.set();
}
fn setupSigIntHandler() void {
const handler = std.os.Sigaction{
.handler = .{
.handler = handler_fn,
},
.mask = std.os.empty_sigset,
.flags = std.os.SA.RESETHAND,
};
if (std.os.linux.sigaction(std.os.SIG.INT, &handler, null) == -1) {
std.os.linux.perror("Failed to set signal");
}
}
pub fn main() anyerror!void { pub fn main() anyerror!void {
var db = try sqlite.Database.open("data.db"); var db = try sqlite.Database.open("data.db");
defer { defer {
@ -111,9 +135,10 @@ pub fn main() anyerror!void {
}; };
} }
setupSigIntHandler();
try createTables(&db); try createTables(&db);
//var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
var allocator = general_purpose_allocator.allocator(); var allocator = general_purpose_allocator.allocator();
@ -130,15 +155,20 @@ pub fn main() anyerror!void {
try insertOrReplaceStreamers(allocator, &db, &client, &config, &headers); try insertOrReplaceStreamers(allocator, &db, &client, &config, &headers);
while (true) { var loop = true;
while (loop) {
var alertAllocator = std.heap.ArenaAllocator.init(allocator); var alertAllocator = std.heap.ArenaAllocator.init(allocator);
try updateAlert(alertAllocator.allocator(), &client, &config, &db, &headers); try updateAlert(alertAllocator.allocator(), &client, &config, &db, &headers);
alertAllocator.deinit(); alertAllocator.deinit();
std.log.info("waiting for {} ns", .{config.refresh_rate * std.time.ns_per_ms}); std.log.info("sleeping for {} ns", .{config.refresh_rate * std.time.ns_per_ms});
std.time.sleep(config.refresh_rate * std.time.ns_per_ms); const res = wait_event.timedWait(config.refresh_rate * std.time.ns_per_ms);
loop = res == .timed_out;
} }
std.log.info("stopping ...", .{});
headers.deinit();
client.deinit(); client.deinit();
try Client.cleanup(); try Client.cleanup();
@ -210,22 +240,24 @@ pub fn updateAlert(
for (streams.data) |s| { for (streams.data) |s| {
if (try appendEmbed(allocator, &s, database)) |e| { if (try appendEmbed(allocator, &s, database)) |e| {
std.log.info("{s}", .{s.title});
try embeds.append(e); try embeds.append(e);
} }
} }
if (embeds.items.len > 0) { if (embeds.items.len > 0) {
_ = try client.postJSON(config.webhook_url, webhook.Webhook{ var res = try client.postJSON(config.webhook_url, webhook.Webhook{
.username = "Twitch", .username = "Twitch",
.content = "Live alert", .content = "Live alert",
.embeds = embeds.items, .embeds = embeds.items,
}, null); }, null);
embeds.deinit();
client.allocator.free(res);
} }
embeds.deinit();
} }
} }
const VIEWER_COUNT_NAME = "Viewer count";
fn appendEmbed(allocator: std.mem.Allocator, stream: *const twitch.Stream, db: *sqlite.Database) anyerror!?webhook.Embed { fn appendEmbed(allocator: std.mem.Allocator, stream: *const twitch.Stream, db: *sqlite.Database) anyerror!?webhook.Embed {
if (!try streamExist(db, stream.id)) { if (!try streamExist(db, stream.id)) {
@ -237,7 +269,7 @@ fn appendEmbed(allocator: std.mem.Allocator, stream: *const twitch.Stream, db: *
try std.fmt.format(viewer.writer(), "{}", .{stream.viewer_count}); try std.fmt.format(viewer.writer(), "{}", .{stream.viewer_count});
try fields.append(.{ try fields.append(.{
.name = VIEWER_COUNT_NAME, .name = "Viewer count",
.value = viewer.toOwnedSlice(), .value = viewer.toOwnedSlice(),
.@"inline" = true, .@"inline" = true,
}); });
@ -322,7 +354,7 @@ pub fn insertMetadatas(db: *sqlite.Database, stream: *const twitch.Stream) anyer
stm.finalize(); stm.finalize();
if (try mustInsertName(db, stream)) { if (try mustInsertName(db, stream)) {
std.log.debug("inserting name", .{}); std.log.debug("inserting name : {s} ({s})", .{stream.title, stream.id});
stm = try db.prepare( stm = try db.prepare(
"INSERT INTO NAME_STREAM(nameStream, dateNameStream, idStream) VALUES(?, datetime(\"now\"), ?)", "INSERT INTO NAME_STREAM(nameStream, dateNameStream, idStream) VALUES(?, datetime(\"now\"), ?)",
); );