summaryrefslogtreecommitdiff
path: root/src/weatherFetcher.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/weatherFetcher.zig')
-rw-r--r--src/weatherFetcher.zig101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/weatherFetcher.zig b/src/weatherFetcher.zig
new file mode 100644
index 0000000..be99d5c
--- /dev/null
+++ b/src/weatherFetcher.zig
@@ -0,0 +1,101 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const net = std.net;
+
+const expect = std.testing.expect;
+
+const http = @import("./http.zig");
+
+
+pub const DailyDataSchema = struct {
+ latitude: f64,
+ longitude: f64,
+ generationtime_ms: f64,
+ utc_offset_seconds: i64,
+ timezone: []u8,
+ timezone_abbreviation: []u8,
+ elevation: f64,
+ hourly_units: struct{
+ time: []u8,
+ temperature_2m: []u8,
+ },
+ hourly: struct {
+ time: [][]u8,
+ temperature_2m: []f64,
+ },
+};
+
+pub const DailyData = struct{
+ data: DailyDataSchema,
+ allocator: std.mem.Allocator,
+
+ const Self = @This();
+ pub fn parse(allocator: Allocator, body: []u8) !Self{
+ var stream = std.json.TokenStream.init(body);
+ return Self{
+ .data = try std.json.parse(DailyDataSchema, &stream, .{
+ .allocator = allocator
+ }),
+ .allocator = allocator,
+ };
+ }
+ pub fn deinit(self: *Self) void{
+ std.json.parseFree(DailyDataSchema, self.data, .{
+ .allocator = self.allocator,
+ });
+ }
+};
+
+/// Gets Daily Data. Allocates and returns an DailyData struct that must be
+/// .deinit() later
+pub fn getDailyData(allocator: std.mem.Allocator) !DailyData {
+ const stream = try net.tcpConnectToHost(allocator, "api.open-meteo.com", 80);
+ defer stream.close();
+
+ const writer = stream.writer();
+ try writer.writeAll( "GET /v1/forecast" ++
+ "?latitude=52.52" ++
+ "&longitude=13.41" ++
+ "&hourly=temperature_2m" ++ " HTTP/1.1\r\n" ++
+ "Host: api.open-meteo.com\r\n" ++
+ "Connection: keep-alive\r\n" ++
+ "Accept-Encoding: identity\r\n" ++
+ "\r\n");
+ const reader = stream.reader();
+
+ var response = try http.HttpResponseParser.init(allocator);
+ defer response.deinit();
+
+ try response.parseReader(reader);
+ return try DailyData.parse(allocator, response.body());
+}
+
+test "Parse a daily data block correctly with DailyDataSchema" {
+ const allocator = std.testing.allocator;
+
+ const body =
+\\ {"latitude":52.52,"longitude":13.419998,"generationtime_ms":0.4259347915649414,
+\\ "utc_offset_seconds":0,"timezone":"GMT","timezone_abbreviation":"GMT",
+\\ "elevation":38.0,"hourly_units":
+\\ {"time":"iso8601","temperature_2m":"°C"},
+\\ "hourly":{"time":["2023-04-09T00:00","2023-04-09T01:00"],"temperature_2m":[4.3,3.6]}}
+;
+ var stream = std.json.TokenStream.init(body);
+ const parsedData = try std.json.parse(DailyDataSchema, &stream, .{
+ .allocator = allocator
+ });
+ defer std.json.parseFree(DailyDataSchema, parsedData, .{
+ .allocator = allocator
+ });
+
+ try expect( std.mem.eql(u8, parsedData.timezone_abbreviation, "GMT") );
+ try expect( std.mem.eql(u8, parsedData.hourly.time[0], "2023-04-09T00:00") );
+}
+
+test "Get data properly and parse it (requires access to open-meteo)" {
+ const allocator = std.testing.allocator;
+
+ var daily = try getDailyData(allocator);
+ defer daily.deinit();
+ try expect( std.mem.eql(u8, daily.data.hourly_units.time, "iso8601") );
+}