diff --git a/src/main.zig b/src/main.zig index 6da401e..e926c65 100644 --- a/src/main.zig +++ b/src/main.zig @@ -20,13 +20,11 @@ pub fn main() !void { var br = Bar.init(&bar); var arena = std.heap.ArenaAllocator.init(allocator); - var arenacator = &arena.allocator; - + defer arena.deinit(); const widgets = [_]*Widget{ &Widget.init(&textWidget.New("owo", "potato")), - &Widget.init(&weatherWidget.New(arenacator, &br, "London")), + &Widget.init(&weatherWidget.New(&arena.allocator, &br, "London")), }; bar.widgets = widgets[0..]; try br.start(); - arena.deinit(); } diff --git a/src/widgets/weather/weather.zig b/src/widgets/weather/weather.zig index e03e80c..a850fe1 100644 --- a/src/widgets/weather/weather.zig +++ b/src/widgets/weather/weather.zig @@ -7,6 +7,11 @@ const Bar = @import("../../types/bar.zig").Bar; const colour = @import("../../formatting/colour.zig").colour; const DebugAllocator = @import("../../debug_allocator.zig"); +const WeatherData = struct { + temp: u16, + main: []const u8, +}; + pub const WeatherWidget = struct { allocator: *std.mem.Allocator, bar: *Bar, @@ -35,100 +40,131 @@ pub const WeatherWidget = struct { } } + fn get_weather_info(self: *WeatherWidget) !WeatherData { + // this will allocate some memory but it will be freed by the time it is returned. + var file = try net.tcpConnectToHost(self.allocator, "api.openweathermap.org", 80); + std.debug.print("Connected to OpenWeatherMap.\n", .{}); + + var read_buffer: [512]u8 = undefined; + var client = hzzp.BaseClient.create(&read_buffer, &file.reader(), &file.writer()); + + try client.writeHead("GET", self.weather_api_url); + try client.writeHeader("Host", "api.openweathermap.org"); + try client.writeHeader("User-Agent", "uwu/1.2"); + try client.writeHeader("Connection", "close"); + try client.writeHeader("Accept", "*/*"); + try client.writeHeadComplete(); + + std.debug.print("Wrote Data, reading response.\n", .{}); + + var isNextTemp: bool = false; + var isNextMain: bool = false; + var foundMain: bool = false; + + var temp: u16 = undefined; + var main: []const u8 = undefined; + + while (try client.readEvent()) |event| { + switch (event) { + .chunk => |chunk| { + var tokens = std.json.TokenStream.init(chunk.data); + while (try tokens.next()) |token| { + switch (token) { + .String => |string| { + var str = string.slice(tokens.slice, tokens.i - 1); + if (std.mem.eql(u8, str, "temp")) { + isNextTemp = true; + continue; + } + if (!foundMain and std.mem.eql(u8, str, "main")) { + isNextMain = true; + continue; + } + if (isNextMain) { + main = str; + isNextMain = false; + foundMain = true; + } + }, + .Number => |num| { + if (isNextTemp) { + isNextTemp = false; + temp = @floatToInt(u16, std.math.round(try std.fmt.parseFloat(f32, num.slice(tokens.slice, tokens.i - 1)))); + } + }, + else => {}, + } + } + }, + .status, .header, .head_complete, .closed, .end, .invalid => continue, + } + } + return WeatherData{ .temp = temp, .main = main }; + } + + fn update_info(self: *WeatherWidget) anyerror!void { + var inf: WeatherData = undefined; + if (self.get_weather_info()) |i| { + inf = i; + } else |err| switch (err) { + error.TemporaryNameServerFailure => { + const lock = self.mutex.acquire(); + self.info = Info{ + .name = "weather", + .full_text = "weather DNS Error with a chance of WiFi", + .markup = "pango", + .color = "#ffffff", + }; + lock.release(); + }, + else => |e| { + return e; + }, + } + + var temp = inf.temp; + var main = inf.main; + + var tempColour: []const u8 = "green"; + if (temp >= 20) { + tempColour = "red"; + } else if (temp == 19) { + tempColour = "orange"; + } else if (temp == 18) { + tempColour = "yellow"; + } + var arena = std.heap.ArenaAllocator.init(self.allocator); + var arenacator = &arena.allocator; + + var i = Info{ + .name = "weather", + .full_text = try std.fmt.allocPrint(self.allocator, "{} {}{}{} {}", .{ + colour(arenacator, "accentlight", "weather"), + colour(arenacator, tempColour, try std.fmt.allocPrint(arenacator, "{}", .{temp})), + colour(arenacator, "accentlight", "°"), + colour(arenacator, "accentdark", "C"), + colour(arenacator, "green", main), + }), + .markup = "pango", + .color = "#ffffff", + }; + const lock = self.mutex.acquire(); + if (self.info != null) { + self.allocator.free(self.info.?.full_text); + } + self.info = i; + lock.release(); + arena.deinit(); + } + pub fn start(self: *WeatherWidget) anyerror!void { defer self.mutex.deinit(); while (self.bar.keep_running()) { - std.time.sleep(2000 * std.time.ns_per_ms); - - std.debug.print("Starting Weather Widget.\n", .{}); - var file = try net.tcpConnectToHost(self.allocator, "api.openweathermap.org", 80); - std.debug.print("Connected to OpenWeatherMap.\n", .{}); - - var read_buffer: [512]u8 = undefined; - var client = hzzp.BaseClient.create(&read_buffer, &file.reader(), &file.writer()); - - try client.writeHead("GET", self.weather_api_url); - try client.writeHeader("Host", "api.openweathermap.org"); - try client.writeHeader("User-Agent", "uwu/1.2"); - try client.writeHeader("Connection", "close"); - try client.writeHeader("Accept", "*/*"); - try client.writeHeadComplete(); - - std.debug.print("Wrote Data, reading response.\n", .{}); - - var isNextTemp: bool = false; - var isNextMain: bool = false; - var foundMain: bool = false; - - var temp: u16 = undefined; - var main: []const u8 = undefined; - - while (try client.readEvent()) |event| { - switch (event) { - .chunk => |chunk| { - var tokens = std.json.TokenStream.init(chunk.data); - while (try tokens.next()) |token| { - switch (token) { - .String => |string| { - var str = string.slice(tokens.slice, tokens.i - 1); - if (std.mem.eql(u8, str, "temp")) { - isNextTemp = true; - continue; - } - if (!foundMain and std.mem.eql(u8, str, "main")) { - isNextMain = true; - continue; - } - if (isNextMain) { - main = str; - isNextMain = false; - foundMain = true; - } - }, - .Number => |num| { - if (isNextTemp) { - isNextTemp = false; - temp = @floatToInt(u16, std.math.round(try std.fmt.parseFloat(f32, num.slice(tokens.slice, tokens.i - 1)))); - } - }, - else => {}, - } - } - }, - .status, .header, .head_complete, .closed, .end, .invalid => continue, - } - } - var tempColour: []const u8 = "green"; - if (temp >= 20) { - tempColour = "red"; - } else if (temp == 19) { - tempColour = "orange"; - } else if (temp == 18) { - tempColour = "yellow"; - } - var arena = std.heap.ArenaAllocator.init(self.allocator); - var arenacator = &arena.allocator; - if (self.info != null) { - self.allocator.free(self.info.?.full_text); - } - - var i = Info{ - .name = "weather", - .full_text = try std.fmt.allocPrint(self.allocator, "{} {}{}{} {}", .{ - colour(arenacator, "accentlight", "weather"), - colour(arenacator, tempColour, try std.fmt.allocPrint(arenacator, "{}", .{temp})), - colour(arenacator, "accentlight", "°"), - colour(arenacator, "accentdark", "C"), - colour(arenacator, "green", main), - }), - .markup = "pango", - .color = "#ffffff", - }; - const lock = self.mutex.acquire(); - self.info = i; - lock.release(); - - arena.deinit(); + try self.update_info(); + std.time.sleep(std.time.ns_per_min); + } + if (self.info != null) { + self.allocator.free(self.info.?.full_text); } } };