From af20584ff23e48d8632c24f56682ea1d9e144573 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 31 Jan 2024 09:58:16 +0100 Subject: [PATCH] async: remove useless http.zig Replace it with a tested sample implementation --- src/async/http.zig | 74 ----------------------------------------- src/async/test.zig | 83 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 81 deletions(-) delete mode 100644 src/async/http.zig diff --git a/src/async/http.zig b/src/async/http.zig deleted file mode 100644 index 3cd095a7..00000000 --- a/src/async/http.zig +++ /dev/null @@ -1,74 +0,0 @@ -const std = @import("std"); -const http = std.http; -const stdcli = @import("Client.zig"); - -pub const Loop = @import("jsruntime").Loop; -const YieldImpl = Loop.Yield(Request); - -pub const Client = struct { - cli: stdcli, - - pub fn init(alloc: std.mem.Allocator, loop: *Loop) Client { - return .{ - .cli = .{ - .allocator = alloc, - .loop = loop, - }, - }; - } - - pub fn deinit(self: *Client) void { - self.cli.deinit(); - } - - pub fn create(self: *Client, uri: std.Uri) !*Request { - var req = try self.cli.allocator.create(Request); - req.* = Request{ - .impl = undefined, - .cli = &self.cli, - .uri = uri, - .headers = .{ .allocator = self.cli.allocator, .owned = false }, - }; - req.impl = YieldImpl.init(self.cli.loop, req); - return req; - } -}; - -pub const Request = struct { - cli: *stdcli, - uri: std.Uri, - headers: std.http.Headers, - - impl: YieldImpl, - done: bool = false, - err: ?anyerror = null, - - pub fn deinit(self: *Request) void { - self.headers.deinit(); - self.cli.allocator.destroy(self); - } - - pub fn fetch(self: *Request) void { - return self.impl.yield(); - } - - fn onerr(self: *Request, err: anyerror) void { - self.err = err; - } - - pub fn onYield(self: *Request, err: ?anyerror) void { - defer self.done = true; - if (err) |e| return self.onerr(e); - var req = self.cli.open(.GET, self.uri, self.headers, .{}) catch |e| return self.onerr(e); - defer req.deinit(); - - req.send(.{}) catch |e| return self.onerr(e); - req.finish() catch |e| return self.onerr(e); - req.wait() catch |e| return self.onerr(e); - } - - pub fn wait(self: *Request) !void { - while (!self.done) try self.impl.tick(); - if (self.err) |err| return err; - } -}; diff --git a/src/async/test.zig b/src/async/test.zig index de3446a2..6038e908 100644 --- a/src/async/test.zig +++ b/src/async/test.zig @@ -1,8 +1,7 @@ const std = @import("std"); const http = std.http; -const StdClient = @import("Client.zig"); -const AsyncClient = @import("http.zig").Client; -const AsyncRequest = @import("http.zig").Request; +const Client = @import("Client.zig"); +const Request = @import("Client.zig").Request; pub const Loop = @import("jsruntime").Loop; @@ -16,7 +15,7 @@ test "blocking mode fetch API" { var loop = try Loop.init(alloc); defer loop.deinit(); - var client: StdClient = .{ + var client: Client = .{ .allocator = alloc, .loop = &loop, }; @@ -40,7 +39,7 @@ test "blocking mode open/send/wait API" { var loop = try Loop.init(alloc); defer loop.deinit(); - var client: StdClient = .{ + var client: Client = .{ .allocator = alloc, .loop = &loop, }; @@ -62,7 +61,77 @@ test "blocking mode open/send/wait API" { try std.testing.expect(req.response.status == .ok); } -test "non blocking mode API" { +// Example how to write an async http client using the modified standard client. +const AsyncClient = struct { + cli: Client, + + const YieldImpl = Loop.Yield(AsyncRequest); + const AsyncRequest = struct { + cli: *Client, + uri: std.Uri, + headers: std.http.Headers, + + impl: YieldImpl, + done: bool = false, + err: ?anyerror = null, + + pub fn deinit(self: *AsyncRequest) void { + self.headers.deinit(); + self.cli.allocator.destroy(self); + } + + pub fn fetch(self: *AsyncRequest) void { + return self.impl.yield(); + } + + fn onerr(self: *AsyncRequest, err: anyerror) void { + self.err = err; + } + + pub fn onYield(self: *AsyncRequest, err: ?anyerror) void { + defer self.done = true; + if (err) |e| return self.onerr(e); + var req = self.cli.open(.GET, self.uri, self.headers, .{}) catch |e| return self.onerr(e); + defer req.deinit(); + + req.send(.{}) catch |e| return self.onerr(e); + req.finish() catch |e| return self.onerr(e); + req.wait() catch |e| return self.onerr(e); + } + + pub fn wait(self: *AsyncRequest) !void { + while (!self.done) try self.impl.tick(); + if (self.err) |err| return err; + } + }; + + pub fn init(alloc: std.mem.Allocator, loop: *Loop) AsyncClient { + return .{ + .cli = .{ + .allocator = alloc, + .loop = loop, + }, + }; + } + + pub fn deinit(self: *AsyncClient) void { + self.cli.deinit(); + } + + pub fn create(self: *AsyncClient, uri: std.Uri) !*AsyncRequest { + var req = try self.cli.allocator.create(AsyncRequest); + req.* = AsyncRequest{ + .impl = undefined, + .cli = &self.cli, + .uri = uri, + .headers = .{ .allocator = self.cli.allocator, .owned = false }, + }; + req.impl = YieldImpl.init(self.cli.loop, req); + return req; + } +}; + +test "non blocking client" { const alloc = std.testing.allocator; var loop = try Loop.init(alloc); @@ -71,7 +140,7 @@ test "non blocking mode API" { var client = AsyncClient.init(alloc, &loop); defer client.deinit(); - var reqs: [10]*AsyncRequest = undefined; + var reqs: [10]*AsyncClient.AsyncRequest = undefined; for (0..reqs.len) |i| { reqs[i] = try client.create(try std.Uri.parse(url)); reqs[i].fetch();