diff options
Diffstat (limited to 'src/weatherFetcher.zig')
-rw-r--r-- | src/weatherFetcher.zig | 101 |
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") ); +} |