-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to pass arguments to HTTP handler (httpz.Action
)
#89
Comments
I assume you're using the 0.13 branch. var server = try httpz.ServerApp(*Cache).init(allocator, .{}, &cache);
// same as before
...
fn getRepos(cache: *Cache, _: *httpz.Request, res: *httpz.Response) !void {
// same as before, use cache
} "Cache" is very specific. You might want to create a more generic wrapper, like an "App" or a "Context" which contains your cache, so that if/when you have more things you want your actions to have access to (like a DB connection pool)...but that's up to you. The API has changed a bit in 0.14/master. It's the same idea, but there's no longe a separate |
@karlseguin that's super helpful, thanks! I updated to use 0.14/master for both httpz and zig and changed to: var server = try httpz.Server(*Cache).init(allocator, .{ .port = 8080 }, &cache); Works great 👍
Great point—thank you! I appreciate the help and feedback |
One more note. In your example above, I don't know how your cache is implemented, but One solution is to call Even if you took the extreme option of clone the data using In cache.zig I use a ARC to protect entries, which is why the entry you get from a |
Calling my implementation a "cache" is likely not the most accurate term. It is simply a struct with a const std = @import("std");
const zdt = @import("zig-datetime");
const Datetime = zdt.datetime.Datetime;
pub const Cache = struct {
data: []const u8,
timestamp: []const u8,
allocator: std.mem.Allocator,
// response_body is used for the sole purpose of freeing memory in deinit().
response_body: []const u8,
pub fn init(allocator: std.mem.Allocator) Cache {
return Cache{
.data = &[_]u8{},
.timestamp = &[_]u8{},
.allocator = allocator,
.response_body = &[_]u8{},
};
}
pub fn deinit(self: *Cache) void {
self.allocator.free(self.response_body);
self.allocator.free(self.timestamp);
}
pub fn get(self: Cache) Cache {
return Cache{
.data = self.data,
.timestamp = self.timestamp,
.allocator = self.allocator,
.response_body = self.response_body,
};
}
pub fn set(self: *Cache, data: []const u8) !void {
self.data = data;
self.timestamp = try Datetime.now().shiftTimezone(&zdt.timezones.GMT).formatHttp(self.allocator);
}
pub fn fetchRepoData(self: *Cache) !void {
var client = std.http.Client{
.allocator = self.allocator,
};
defer client.deinit();
const uri = try std.Uri.parse("https://storage.googleapis.com/storage/v1/b/lucasrod16-github-data/o/data.json?alt=media");
const buf = try self.allocator.alloc(u8, 1024 * 1024 * 4);
defer self.allocator.free(buf);
var req = try client.open(.GET, uri, .{
.server_header_buffer = buf,
});
defer req.deinit();
try req.send();
try req.finish();
try req.wait();
std.debug.assert(req.response.status == std.http.Status.ok);
var rdr = req.reader();
const body = try rdr.readAllAlloc(self.allocator, 1024 * 1024 * 4);
// Don't free the response body immediately.
// Store it in the cache and cleanup in deinit().
self.response_body = body;
try self.set(body);
std.log.info("Successfully loaded GitHub data from GCS bucket into the in-memory cache.", .{});
}
}; I was experiencing an issue where I was freeing the response body in |
Not clear why you have both a Also, the code isn't thread safe. If it was just the memory leak, I'd say deal with that (i.e. release the previous response before setting it). Or, if it was just the thread-safety issue, I'd say deal with that (i.e. use a mutex). But you're dealing with an intersection of the two. You can't just release the previous This should be "correct". But the broad lock isn't great for performance/concurrency. You can reduce the lock in As an aside, I'm not sure it makes sense to |
First, I want to say thanks for creating this library. I'm new to Zig and this library has made it much easier to create an HTTP server in Zig.
I have an HTTP handler that needs an instance of a struct passed to it so that it can call a method on that struct.
In this particular code, I need to pass the
cache
instance to thegetRepos
handler:so that the handler can call
cache.get()
:I tried using a function closure approach:
but it's my understanding that Zig does not support closures.
If there are any recommendations on how to achieve this it would be much appreciated.
ziglang/zig#229
The text was updated successfully, but these errors were encountered: