diff --git a/build.zig.zon b/build.zig.zon index 3fcf39a..de5eaae 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,7 +3,7 @@ .version = "0.4.0", .fingerprint = 0xdc70f8287a69c300, - .minimum_zig_version = "0.15.0", + .minimum_zig_version = "0.16.0-dev.2145+ec25b1384", .dependencies = .{}, diff --git a/demo/debug.zig b/demo/debug.zig index eeda369..b55e44c 100644 --- a/demo/debug.zig +++ b/demo/debug.zig @@ -9,7 +9,7 @@ pub fn main() void { } fn handler(ctx: lambda.Context, event: []const u8) ![]const u8 { - var str: std.io.Writer.Allocating = try .initCapacity(ctx.arena, 1024); + var str: std.Io.Writer.Allocating = try .initCapacity(ctx.arena, 1024); const cfg = ctx.config; try str.writer.print( diff --git a/demo/url_buffer.zig b/demo/url_buffer.zig index e338fc8..de41980 100644 --- a/demo/url_buffer.zig +++ b/demo/url_buffer.zig @@ -90,7 +90,7 @@ fn homePage(ctx: lambda.Context) ![]const u8 { /// The `url.Request` contains both the HTTP request and additional AWS metadata. fn ipAddrPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { // Generate dynamic HTML content, note the usage of an arena allocator. - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); if (req.request_context.http.source_ip) |addr| { @@ -110,7 +110,7 @@ fn ipAddrPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { /// Use a parsed query parameter provided by the decoded request to greet the user. fn greetPage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); @@ -165,7 +165,7 @@ fn storagePage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { } // Encode the cookie value - var new_cookie: std.io.Writer.Allocating = .init(ctx.arena); + var new_cookie: std.Io.Writer.Allocating = .init(ctx.arena); errdefer new_cookie.deinit(); try new_cookie.writer.writeAll("store="); try std.base64.standard.Encoder.encodeWriter(&new_cookie.writer, value); @@ -176,7 +176,7 @@ fn storagePage(ctx: lambda.Context, req: lambda.url.Request) ![]const u8 { } // Render a form to display and update the stored value. - var html: std.io.Writer.Allocating = .init(ctx.arena); + var html: std.Io.Writer.Allocating = .init(ctx.arena); try html.writer.writeAll(global_nav); try html.writer.print( \\
diff --git a/src/event/url.zig b/src/event/url.zig index eb0b7b7..36e5df5 100644 --- a/src/event/url.zig +++ b/src/event/url.zig @@ -46,7 +46,7 @@ pub const Response = struct { pub const internal_server_error = "{\"statusCode\":500,body:\"Internal Server Error\"}"; pub fn encode(self: Response, gpa: Allocator) ![]const u8 { - var buffer: std.io.Writer.Allocating = .init(gpa); + var buffer: std.Io.Writer.Allocating = .init(gpa); errdefer buffer.deinit(); try buffer.writer.writeByte('{'); @@ -156,7 +156,7 @@ test Response { /// .body = .{ .textual = "

Incoming...

" }, /// }); /// ``` -pub fn openStream(ctx: hdl.Context, stream: hdl.Stream, response: Response) !*std.io.Writer { +pub fn openStream(ctx: hdl.Context, stream: hdl.Stream, response: Response) !*std.Io.Writer { // https://github.com/awslabs/aws-lambda-rust-runtime/blob/main/lambda-runtime/src/requests.rs // https://aws.amazon.com/blogs/compute/using-response-streaming-with-aws-lambda-web-adapter-to-optimize-performance const writer = try stream.openPrint(INTEGRATION_CONTENT_TYPE, "{f}", .{StreamingResponse{ @@ -183,12 +183,12 @@ const StreamingResponse = struct { arena: Allocator, response: Response, - pub fn format(self: @This(), writer: *std.io.Writer) !void { + pub fn format(self: @This(), writer: *std.Io.Writer) !void { var response = self.response; response.body = .{ .textual = "" }; const prelude = response.encode(self.arena) catch { - return std.io.Writer.Error.WriteFailed; + return std.Io.Writer.Error.WriteFailed; }; try writer.writeAll(prelude); } diff --git a/src/runtime/api.zig b/src/runtime/api.zig index b12ea34..167e6a7 100644 --- a/src/runtime/api.zig +++ b/src/runtime/api.zig @@ -205,7 +205,7 @@ fn sendRequest(arena: Allocator, client: *Client, path: []const u8, payload: ?[] } fn formatError(arena: Allocator, err_category: []const u8, err: ErrorRequest) ![]const u8 { - var buffer: std.io.Writer.Allocating = .init(arena); + var buffer: std.Io.Writer.Allocating = .init(arena); try buffer.writer.print( \\{{"errorType":"{s}. diff --git a/src/runtime/context.zig b/src/runtime/context.zig index 1110c73..30fe7e5 100644 --- a/src/runtime/context.zig +++ b/src/runtime/context.zig @@ -19,7 +19,7 @@ pub const Context = struct { config: ConfigMeta = .{}, /// Request metadata of the invocation. request: RequestMeta = .{}, - + io: *const std.Io, _force_destroy: *bool, _kv: *const std.process.EnvMap = undefined, diff --git a/src/runtime/handle.zig b/src/runtime/handle.zig index 82a3318..34368f6 100644 --- a/src/runtime/handle.zig +++ b/src/runtime/handle.zig @@ -98,7 +98,7 @@ pub const Stream = struct { }; /// Start streaming a response of a specified content type. - pub fn open(self: @This(), content_type: []const u8) !*std.io.Writer { + pub fn open(self: @This(), content_type: []const u8) !*std.Io.Writer { return self.openPrint(content_type, "", {}); } @@ -111,7 +111,7 @@ pub const Stream = struct { content_type: []const u8, comptime prelude_fmt: []const u8, prelude_args: anytype, - ) !*std.io.Writer { + ) !*std.Io.Writer { if (self.state.* != .pending) return error.ReopeningStream; std.debug.assert(content_type.len > 0); diff --git a/src/runtime/serve.zig b/src/runtime/serve.zig index 76450e1..5bac1ff 100644 --- a/src/runtime/serve.zig +++ b/src/runtime/serve.zig @@ -20,6 +20,8 @@ pub const Options = struct {}; pub const Server = struct { gpa: std.heap.GeneralPurposeAllocator(.{}), arena: std.heap.ArenaAllocator, + threaded: std.Io.Threaded, + io: std.Io, http: HttpClient, env: std.process.EnvMap, request_id: []const u8 = "", @@ -48,7 +50,13 @@ pub const Server = struct { return initFailed(arena_alloc, null, error.MissingRuntimeOrigin, "Missing the runtime’s API origin URL"); }; - self.http = HttpClient.init(gpa_alloc, api_origin) catch |err| { + // Initialize threaded IO - owned by Server + self.threaded = std.Io.Threaded.init(gpa_alloc, .{}); + errdefer self.threaded.deinit(); + + self.io = self.threaded.io(); + + HttpClient.init(&self.http, gpa_alloc, api_origin, self.io) catch |err| { return initFailed(arena_alloc, null, err, "Creating a HTTP client failed"); }; } @@ -57,6 +65,7 @@ pub const Server = struct { self.http.deinit(); self.env.deinit(); self.arena.deinit(); + self.threaded.deinit(); switch (self.gpa.deinit()) { .ok => {}, @@ -98,6 +107,7 @@ pub const Server = struct { .gpa = self.gpa.allocator(), .arena = self.arena.allocator(), ._force_destroy = &force_terminate, + .io = &self.io, }; ctx.loadMeta(&context, &self.env); @@ -134,8 +144,8 @@ pub const Server = struct { } pub fn respondFailure(self: *Server, err: anyerror, trace: ?*std.builtin.StackTrace) !void { - if (trace) |t| { - log.err("The handler returned an error `{s}`.{f}", .{ @errorName(err), t }); + if (trace) |_| { + log.err("The handler returned an error `{s}`.", .{@errorName(err)}); } else { log.err("The handler returned an error `{s}`.", .{@errorName(err)}); } @@ -203,7 +213,7 @@ pub const Server = struct { body: std.http.BodyWriter, arena: std.mem.Allocator, - pub fn writer(self: *Stream) *std.io.Writer { + pub fn writer(self: *Stream) *std.Io.Writer { return &self.body.writer; } diff --git a/src/utils/Http.zig b/src/utils/Http.zig index f60e2b2..3895b07 100644 --- a/src/utils/Http.zig +++ b/src/utils/Http.zig @@ -2,6 +2,8 @@ const std = @import("std"); const testing = std.testing; const Client = std.http.Client; +const Io = std.Io; +const Threaded = std.Io.Threaded; const Allocator = std.mem.Allocator; const builtin = @import("builtin"); const package_version = @import("meta.zig").package_version; @@ -20,9 +22,9 @@ const USER_AGENT = std.fmt.comptimePrint( client: Client, uri: std.Uri, -pub fn init(gpa: Allocator, origin: []const u8) !Self { +pub fn init(self: *Self, gpa: Allocator, origin: []const u8, io: Io) !void { const idx = std.mem.indexOfScalar(u8, origin, ':'); - const uri = std.Uri{ + self.uri = std.Uri{ .path = .{ .percent_encoded = "" }, .scheme = "http", .host = .{ .raw = if (idx) |i| origin[0..i] else origin }, @@ -32,10 +34,7 @@ pub fn init(gpa: Allocator, origin: []const u8) !Self { null, }; - return .{ - .client = Client{ .allocator = gpa }, - .uri = uri, - }; + self.client = Client{ .allocator = gpa, .io = io }; } pub fn deinit(self: *Self) void { @@ -137,7 +136,7 @@ fn parseResponse(arena: Allocator, res: *Client.Response) !Result { var transfer_buffer: [64]u8 = undefined; const reader = res.reader(&transfer_buffer); - var buffer: std.io.Writer.Allocating = .init(arena); + var buffer: std.Io.Writer.Allocating = .init(arena); _ = reader.streamRemaining(&buffer.writer) catch |err| switch (err) { error.ReadFailed => return res.bodyErr().?, else => |e| return e, diff --git a/src/utils/environ.zig b/src/utils/environ.zig index 62769da..891299b 100644 --- a/src/utils/environ.zig +++ b/src/utils/environ.zig @@ -21,5 +21,5 @@ fn parseAndPutVar(map: *std.process.EnvMap, line: [*]u8) !void { while (line[end_i] != 0) : (end_i += 1) {} const value = line[line_i + 1 .. end_i]; - try map.putMove(key, value); + try map.put(key, value); }