simplify structure

This commit is contained in:
Emil Lerch 2025-12-18 17:58:15 -08:00
parent 7d06d281e0
commit 60cede5a8b
Signed by: lobo
GPG key ID: A7B62D657EF764F8
3 changed files with 28 additions and 47 deletions

View file

@ -2,7 +2,6 @@ const std = @import("std");
const httpz = @import("httpz");
const handler = @import("handler.zig");
const RateLimiter = @import("RateLimiter.zig");
const middleware = @import("middleware.zig");
const Server = @This();
@ -36,8 +35,8 @@ pub fn init(
// We won't use actual middleware for rate limiting here because we only have
// a couple routes to protect with rate limiting
var router = try httpz_server.router(.{});
router.get("/", handleWeatherRoot, .{});
router.get("/:location", handleWeatherLocation, .{});
router.get("/", handleWeather, .{});
router.get("/:location", handleWeather, .{});
return Server{
.allocator = allocator,
@ -46,16 +45,20 @@ pub fn init(
};
}
fn handleWeatherRoot(ctx: *Context, req: *httpz.Request, res: *httpz.Response) !void {
try middleware.rateLimitMiddleware(ctx.rate_limiter, req, res);
fn handleWeather(ctx: *Context, req: *httpz.Request, res: *httpz.Response) !void {
try rateLimitMiddleware(ctx.rate_limiter, req, res);
if (res.status == 429) return;
try handler.handleWeather(&ctx.options, req, res);
}
fn handleWeatherLocation(ctx: *Context, req: *httpz.Request, res: *httpz.Response) !void {
try middleware.rateLimitMiddleware(ctx.rate_limiter, req, res);
if (res.status == 429) return;
try handler.handleWeatherLocation(&ctx.options, req, res);
fn rateLimitMiddleware(limiter: *RateLimiter, req: *httpz.Request, res: *httpz.Response) !void {
var ip_buf: [45]u8 = undefined;
const ip_str = try std.fmt.bufPrint(&ip_buf, "{f}", .{req.address});
if (!limiter.shouldAcceptRequest(ip_str)) {
res.status = 429;
res.body = "Too Many Requests";
}
}
pub fn listen(self: *Server) !void {

View file

@ -24,30 +24,25 @@ pub fn handleWeather(
req: *httpz.Request,
res: *httpz.Response,
) !void {
// Check for location query parameter first
const query_string = req.url.query;
const params = try QueryParams.parse(req.arena, query_string);
defer {
if (params.format) |f| req.arena.free(f);
if (params.lang) |l| req.arena.free(l);
}
// Get location from path parameter or query string
const location = req.param("location") orelse blk: {
// Check query string for location parameter
const query_string = req.url.query;
const params = try QueryParams.parse(req.arena, query_string);
defer {
if (params.format) |f| req.arena.free(f);
if (params.lang) |l| req.arena.free(l);
}
const location = if (params.location) |loc| loc else blk: {
// Fall back to IP-based detection
const client_ip = getClientIP(req);
break :blk client_ip;
if (params.location) |loc| {
break :blk loc;
} else {
// Fall back to IP-based detection
const client_ip = getClientIP(req);
break :blk client_ip;
}
};
try handleWeatherInternal(opts, req, res, location);
}
pub fn handleWeatherLocation(
opts: *HandleWeatherOptions,
req: *httpz.Request,
res: *httpz.Response,
) !void {
const location = req.param("location") orelse "London";
// Handle special endpoints
if (std.mem.startsWith(u8, location, ":")) {
if (std.mem.eql(u8, location, ":help")) {

View file

@ -1,17 +0,0 @@
const std = @import("std");
const httpz = @import("httpz");
const RateLimiter = @import("RateLimiter.zig");
pub fn rateLimitMiddleware(limiter: *RateLimiter, req: *httpz.Request, res: *httpz.Response) !void {
var ip_buf: [45]u8 = undefined; // https://stackoverflow.com/a/166157
const ip_str = try std.fmt.bufPrint(
&ip_buf,
"{f}",
.{req.address},
);
if (!limiter.shouldAcceptRequest(ip_str)) {
res.status = 429;
res.body = "Too Many Requests";
}
}