From c19af600f2c92a0848d150b9fc95398643a96d92 Mon Sep 17 00:00:00 2001 From: Nathan Anderson Date: Thu, 2 Nov 2023 14:22:20 -0600 Subject: [PATCH] Moved stuff --- .gitignore | 2 + build.zig | 120 +++++++++++------------- {lib => src/htzx}/index.html | 0 {lib => src/htzx}/routes.zig | 2 +- {lib => src/htzx}/users/user_routes.zig | 0 src/main.zig | 101 ++++++++++++++++++-- src/zx.zig | 32 +++++++ 7 files changed, 185 insertions(+), 72 deletions(-) rename {lib => src/htzx}/index.html (100%) rename {lib => src/htzx}/routes.zig (82%) rename {lib => src/htzx}/users/user_routes.zig (100%) create mode 100644 src/zx.zig diff --git a/.gitignore b/.gitignore index e69de29..e73c965 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +zig-cache/ +zig-out/ diff --git a/build.zig b/build.zig index b80f909..945523e 100644 --- a/build.zig +++ b/build.zig @@ -2,47 +2,29 @@ const std = @import("std"); pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); - - // Standard optimization options allow the person running `zig build` to select - // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not - // set a preferred release mode, allowing the user to decide how to optimize. const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "zx", - // In this case the main source file is merely a path, however, in more - // complicated build scripts, this could be a generated file. .root_source_file = .{ .path = "src/main.zig" }, .target = target, .optimize = optimize, }); - // This declares intent for the library to be installed into the standard - // location when the user invokes the "install" step (the default step when - // running `zig build`). b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); - // By making the run step depend on the install step, it will be run from the - // installation directory rather than directly from within the cache directory. - // This is not necessary, however, if the application depends on other installed - // files, this ensures they will be present and in the expected location. run_cmd.step.dependOn(b.getInstallStep()); - // This allows the user to pass arguments to the application in the build - // command itself, like this: `zig build run -- arg1 arg2 etc` if (b.args) |args| { run_cmd.addArgs(args); } - // This creates a build step. It will be visible in the `zig build --help` menu, - // and can be selected like this: `zig build run` - // This will evaluate the `run` step rather than the default, which is "install". const run_step = b.step("run", "Run the app"); run_step.dependOn(&run_cmd.step); - // Creates a step for unit testing. This only builds the test executable + // Creates a step for unit testing. This only builds the test executable // but does not run it. const main_tests = b.addTest(.{ .root_source_file = .{ .path = "src/main.zig" }, @@ -52,54 +34,66 @@ pub fn build(b: *std.Build) !void { const run_main_tests = b.addRunArtifact(main_tests); - // This creates a build step. It will be visible in the `zig build --help` menu, - // and can be selected like this: `zig build test` - // This will evaluate the `test` step rather than the default, which is "install". const test_step = b.step("test", "Run library tests"); test_step.dependOn(&run_main_tests.step); - // Setup comptime parsing for /lib files - var markup_files = std.ArrayList([]const u8).init(b.allocator); - var zig_files = std.ArrayList([]const u8).init(b.allocator); - defer markup_files.deinit(); - defer zig_files.deinit(); + // // Setup comptime parsing for /lib files + // var markup_files = std.ArrayList([]const u8).init(b.allocator); + // var zig_files = std.ArrayList([]const u8).init(b.allocator); + // defer markup_files.deinit(); + // defer zig_files.deinit(); - var options = b.addOptions(); + // var options = b.addOptions(); - // Add all files names in the src folder to `files` - var dir = try std.fs.cwd().openIterableDir("lib", .{}); - var lib_walker = try dir.walk(b.allocator); - var walking = true; - while (walking) blk: { - var file = lib_walker.next() catch { - walking = false; - break :blk; - }; - if (file == null) { - walking = false; - break :blk; - } - if (file.?.kind == .file) { - const path = file.?.path; - var split_iter = std.mem.splitBackwardsAny(u8, path, "."); - var extension = split_iter.first(); - if (std.mem.eql(u8, extension, "zig")) { - std.debug.print("Adding zig file {s}...\n", .{path}); - try zig_files.append(b.dupe(path)); - } - else if (std.mem.eql(u8, extension, "html")) { - std.debug.print("Adding markup file {s}...\n", .{path}); - try markup_files.append(b.dupe(path)); - } else { - std.debug.print("Unrecognized file extension {s}\t{s}\n", .{extension, path}); - } - } - // std.debug.print("Got entry in `versions:` base: {s}, path: {s}, kind: {any}\n", .{ ver.?.basename, ver.?.path, ver.?.kind }); - } + // // Add all files names in the src folder to `files` + // var iter_dir = try std.fs.cwd().openIterableDir("lib", .{}); + // var src_dir = try std.fs.cwd().openDir("src", .{}); + // var lib_walker = try iter_dir.walk(b.allocator); + // var walking = true; + // while (walking) blk: { + // var file = lib_walker.next() catch { + // walking = false; + // break :blk; + // }; + // if (file == null) { + // walking = false; + // break :blk; + // } + // if (file.?.kind == .file) { + // const path = file.?.path; + // var split_iter = std.mem.splitBackwardsAny(u8, path, "."); + // var extension = split_iter.first(); + // if (std.mem.eql(u8, extension, "zig")) { + // std.debug.print("Adding zig file {s}...\n", .{path}); + // try zig_files.append(b.dupe(path)); + // var arr: [50]u8 = undefined; + // var buf = arr[0..]; + // var z_file_path = try std.fmt.bufPrint(buf, "lib/{s}", .{path}); + // var z_file = try std.fs.cwd().openFile(z_file_path, .{}); + // const zig_contents = try z_file.readToEndAlloc(b.allocator, 64000); + // const index = std.mem.indexOf(u8, zig_contents, "pub fn post"); + // if (index) |i| { + // std.debug.print("Found post endpoint in {s}\n", .{z_file_path}); + // var routes_file = try src_dir.createFile("routes.zig", .{}); + // _ = try routes_file.write(zig_contents[i..]); + // std.debug.print("Wrote {s}... to routes.zig\n", .{zig_contents[0..10]}); + // } - // Add the file names as an option to the exe, making it available - // as a string array at comptime in main.zig - options.addOption([]const []const u8, "zig_files", zig_files.items); - options.addOption([]const []const u8, "markup_files", markup_files.items); - exe.addOptions("options", options); + // } + // else if (std.mem.eql(u8, extension, "html")) { + // std.debug.print("Adding markup file {s}...\n", .{path}); + // try markup_files.append(b.dupe(path)); + // } else { + // std.debug.print("Unrecognized file extension {s}\t{s}\n", .{extension, path}); + // } + // } + // // std.debug.print("Got entry in `versions:` base: {s}, path: {s}, kind: {any}\n", .{ ver.?.basename, ver.?.path, ver.?.kind }); + // } + + + // // Add the file names as an option to the exe, making it available + // // as a string array at comptime in main.zig + // options.addOption([]const []const u8, "zig_files", zig_files.items); + // options.addOption([]const []const u8, "markup_files", markup_files.items); + // exe.addOptions("options", options); } diff --git a/lib/index.html b/src/htzx/index.html similarity index 100% rename from lib/index.html rename to src/htzx/index.html diff --git a/lib/routes.zig b/src/htzx/routes.zig similarity index 82% rename from lib/routes.zig rename to src/htzx/routes.zig index b57220d..9be76f1 100644 --- a/lib/routes.zig +++ b/src/htzx/routes.zig @@ -1,6 +1,6 @@ const std = @import("std"); -pub fn get() i32 { +pub fn post() i32 { std.debug.print("Running route get!\n", .{}); return 13; } diff --git a/lib/users/user_routes.zig b/src/htzx/users/user_routes.zig similarity index 100% rename from lib/users/user_routes.zig rename to src/htzx/users/user_routes.zig diff --git a/src/main.zig b/src/main.zig index 8255398..b232957 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,12 +1,97 @@ const std = @import("std"); -const options = @import("options"); +const http = std.http; +const log = std.log.scoped(.server); -pub fn main() void { - std.debug.print("Ello there\n", .{}); - comptime { - const route = @import(options.zig_files[0]); - route.get(); - // @compileLog("Got option zig file " ++ options.zig_files[0] ++ "\n"); +const server_addr = "127.0.0.1"; +const server_port = 8000; + +// Run the server and handle incoming requests. +fn runServer(server: *http.Server, allocator: std.mem.Allocator) !void { + outer: while (true) { + // Accept incoming connection. + var response = try server.accept(.{ + .allocator = allocator, + }); + defer response.deinit(); + + while (response.reset() != .closing) { + // Handle errors during request processing. + response.wait() catch |err| switch (err) { + error.HttpHeadersInvalid => continue :outer, + error.EndOfStream => continue, + else => return err, + }; + + // Process the request. + try handleRequest(&response, allocator); + } } - return; +} + +// Handle an individual request. +fn handleRequest(response: *http.Server.Response, allocator: std.mem.Allocator) !void { + // Log the request details. + log.info("{s} {s} {s}", .{ @tagName(response.request.method), @tagName(response.request.version), response.request.target }); + + // Read the request body. + const body = try response.reader().readAllAlloc(allocator, 8192); + defer allocator.free(body); + + // Set "connection" header to "keep-alive" if present in request headers. + if (response.request.headers.contains("connection")) { + try response.headers.append("connection", "keep-alive"); + } + + // Check if the request target starts with "/get". + if (std.mem.startsWith(u8, response.request.target, "/get")) { + // Check if the request target contains "?chunked". + if (std.mem.indexOf(u8, response.request.target, "?chunked") != null) { + response.transfer_encoding = .chunked; + } else { + response.transfer_encoding = .{ .content_length = 10 }; + } + + // Set "content-type" header to "text/plain". + try response.headers.append("content-type", "text/plain"); + + // Write the response body. + try response.do(); + if (response.request.method != .HEAD) { + try response.writeAll("Zig "); + try response.writeAll("Bits!\n"); + try response.finish(); + } + } else { + // Set the response status to 404 (not found). + response.status = .not_found; + try response.do(); + } +} + +pub fn main() !void { + // Create an allocator. + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer std.debug.assert(gpa.deinit() == .ok); + const allocator = gpa.allocator(); + + // Initialize the server. + var server = http.Server.init(allocator, .{ .reuse_address = true }); + defer server.deinit(); + + // Log the server address and port. + log.info("Server is running at {s}:{d}", .{ server_addr, server_port }); + + // Parse the server address. + const address = try std.net.Address.parseIp(server_addr, server_port); + try server.listen(address); + + // Run the server. + runServer(&server, allocator) catch |err| { + // Handle server errors. + log.err("server error: {}\n", .{err}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + std.os.exit(1); + }; } diff --git a/src/zx.zig b/src/zx.zig new file mode 100644 index 0000000..1289be5 --- /dev/null +++ b/src/zx.zig @@ -0,0 +1,32 @@ +const std = @import("std"); +const http = std.http; +const log = std.log.scoped(.server); + +const server_addr = "127.0.0.1"; +const server_port = 8000; + +pub const Zx = struct { + + pub fn init( allocator: std.mem.Allocator,) Zx { + var server = http.Server.init(allocator, .{ .reuse_address = true }); + defer server.deinit(); + + // Log the server address and port. + log.info("Server is running at {s}:{d}", .{ server_addr, server_port }); + + // Parse the server address. + const address = try std.net.Address.parseIp(server_addr, server_port); + try server.listen(address); + + // Run the server. + runServer(&server, allocator) catch |err| { + // Handle server errors. + log.err("server error: {}\n", .{err}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + std.os.exit(1); + }; + + } +};