From 486c19079ad9bb281a3a4f8a98f1abbd40f977de Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Fri, 18 Oct 2024 16:06:23 +0200 Subject: [PATCH] Merge get and server binaires Signed-off-by: Francis Bouvier --- .github/workflows/build.yml | 8 +- build.zig | 22 ------ src/main.zig | 141 +++++++++++++++++++++++++++--------- src/main_get.zig | 99 ------------------------- 4 files changed, 111 insertions(+), 159 deletions(-) delete mode 100644 src/main_get.zig diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 33a847b6..4ee27521 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,13 +32,13 @@ jobs: run: zig build --release=safe -Doptimize=ReleaseSafe -Dengine=v8 -Dcpu=x86_64 - name: Rename binary - run: mv zig-out/bin/browsercore-get lightpanda-get-${{ env.ARCH }}-${{ env.OS }} + run: mv zig-out/bin/browsercore lightpanda-${{ env.ARCH }}-${{ env.OS }} - name: Upload the build uses: ncipollo/release-action@v1 with: allowUpdates: true - artifacts: lightpanda-get-${{ env.ARCH }}-${{ env.OS }} + artifacts: lightpanda-${{ env.ARCH }}-${{ env.OS }} tag: nightly build-macos-aarch64: @@ -65,11 +65,11 @@ jobs: run: zig build --release=safe -Doptimize=ReleaseSafe -Dengine=v8 - name: Rename binary - run: mv zig-out/bin/browsercore-get lightpanda-get-${{ env.ARCH }}-${{ env.OS }} + run: mv zig-out/bin/browsercore-get lightpanda-${{ env.ARCH }}-${{ env.OS }} - name: Upload the build uses: ncipollo/release-action@v1 with: allowUpdates: true - artifacts: lightpanda-get-${{ env.ARCH }}-${{ env.OS }} + artifacts: lightpanda-${{ env.ARCH }}-${{ env.OS }} tag: nightly diff --git a/build.zig b/build.zig index 75c6b396..d5638a1b 100644 --- a/build.zig +++ b/build.zig @@ -139,28 +139,6 @@ pub fn build(b: *std.Build) !void { // step const wpt_step = b.step("wpt", "WPT tests"); wpt_step.dependOn(&wpt_cmd.step); - - // get - // ----- - - // compile and install - const get = b.addExecutable(.{ - .name = "browsercore-get", - .root_source_file = b.path("src/main_get.zig"), - .target = target, - .optimize = mode, - }); - try common(b, get, options); - b.installArtifact(get); - - // run - const get_cmd = b.addRunArtifact(get); - if (b.args) |args| { - get_cmd.addArgs(args); - } - // step - const get_step = b.step("get", "request URL"); - get_step.dependOn(&get_cmd.step); } fn common( diff --git a/src/main.zig b/src/main.zig index f00fbbc0..91233b68 100644 --- a/src/main.zig +++ b/src/main.zig @@ -27,8 +27,6 @@ const server = @import("server.zig"); const parser = @import("netsurf"); const apiweb = @import("apiweb.zig"); -const log = std.log.scoped(.server); - pub const Types = jsruntime.reflect(apiweb.Interfaces); pub const UserContext = apiweb.UserContext; @@ -39,12 +37,17 @@ const Timeout = 3; // in seconds const usage = \\usage: {s} [options] - \\ start Lightpanda browser in CDP server mode + \\ + \\ start Lightpanda browser + \\ + \\ * if an url is provided the browser will fetch the page and exit + \\ * otherwhise the browser starts a CDP server \\ \\ -h, --help Print this help message and exit. - \\ --host Host of the server (default "127.0.0.1") - \\ --port Port of the server (default "3245") - \\ --timeout Timeout for incoming connections in seconds (default "3") + \\ --host Host of the CDP server (default "127.0.0.1") + \\ --port Port of the CDP server (default "3245") + \\ --timeout Timeout for incoming connections of the CDP server (in seconds, default "3") + \\ --dump Dump document in stdout (fetch mode only) \\ ; @@ -146,7 +149,7 @@ pub const StreamServer = struct { fn printUsageExit(execname: []const u8, res: u8) void { std.io.getStdErr().writer().print(usage, .{execname}) catch |err| { - log.err("Print usage error: {any}", .{err}); + std.log.err("Print usage error: {any}", .{err}); std.posix.exit(1); }; std.posix.exit(res); @@ -157,12 +160,20 @@ pub fn main() !void { // allocator var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); + const alloc = arena.allocator(); // args var args = try std.process.argsWithAllocator(arena.allocator()); defer args.deinit(); const execname = args.next().?; + var server_mode = true; + + // fetch mode variables + var url: []const u8 = ""; + var dump: bool = false; + + // server mode variables var host: []const u8 = Host; var port: u16 = Port; var addr: std.net.Address = undefined; @@ -172,64 +183,126 @@ pub fn main() !void { if (std.mem.eql(u8, "-h", opt) or std.mem.eql(u8, "--help", opt)) { printUsageExit(execname, 0); } + if (std.mem.eql(u8, "--dump", opt)) { + dump = true; + continue; + } if (std.mem.eql(u8, "--host", opt)) { if (args.next()) |arg| { host = arg; continue; } else { - log.err("--host not provided\n", .{}); + std.log.err("--host not provided\n", .{}); return printUsageExit(execname, 1); } } if (std.mem.eql(u8, "--port", opt)) { if (args.next()) |arg| { port = std.fmt.parseInt(u16, arg, 10) catch |err| { - log.err("--port {any}\n", .{err}); + std.log.err("--port {any}\n", .{err}); return printUsageExit(execname, 1); }; continue; } else { - log.err("--port not provided\n", .{}); + std.log.err("--port not provided\n", .{}); return printUsageExit(execname, 1); } } if (std.mem.eql(u8, "--timeout", opt)) { if (args.next()) |arg| { timeout = std.fmt.parseInt(u8, arg, 10) catch |err| { - log.err("--timeout {any}\n", .{err}); + std.log.err("--timeout {any}\n", .{err}); return printUsageExit(execname, 1); }; continue; } else { - log.err("--timeout not provided\n", .{}); + std.log.err("--timeout not provided\n", .{}); return printUsageExit(execname, 1); } } + + // unknown option + if (std.mem.startsWith(u8, opt, "--")) { + std.log.err("unknown option\n", .{}); + return printUsageExit(execname, 1); + } + + // other argument is considered to be an URL, ie. fetch mode + server_mode = false; + + // allow only one url + if (url.len != 0) { + std.log.err("more than 1 url provided\n", .{}); + return printUsageExit(execname, 1); + } + + url = opt; } - addr = std.net.Address.parseIp4(host, port) catch |err| { - log.err("address (host:port) {any}\n", .{err}); - return printUsageExit(execname, 1); - }; - // server - var srv = StreamServer.init(.{ - .reuse_address = true, - .reuse_port = true, - .nonblocking = true, - }); - defer srv.deinit(); + if (server_mode) { - srv.listen(addr) catch |err| { - log.err("address (host:port) {any}\n", .{err}); - return printUsageExit(execname, 1); - }; - defer srv.close(); - log.info("Listening on: {s}:{d}...", .{ host, port }); + // server mode + addr = std.net.Address.parseIp4(host, port) catch |err| { + std.log.err("address (host:port) {any}\n", .{err}); + return printUsageExit(execname, 1); + }; - // loop - var loop = try jsruntime.Loop.init(arena.allocator()); - defer loop.deinit(); + // server + var srv = StreamServer.init(.{ + .reuse_address = true, + .reuse_port = true, + .nonblocking = true, + }); + defer srv.deinit(); - // listen - try server.listen(arena.allocator(), &loop, srv.sockfd.?, std.time.ns_per_s * @as(u64, timeout)); + srv.listen(addr) catch |err| { + std.log.err("address (host:port) {any}\n", .{err}); + return printUsageExit(execname, 1); + }; + defer srv.close(); + std.log.info("Listening on: {s}:{d}...", .{ host, port }); + + // loop + var loop = try jsruntime.Loop.init(arena.allocator()); + defer loop.deinit(); + + // listen + try server.listen(alloc, &loop, srv.sockfd.?, std.time.ns_per_s * @as(u64, timeout)); + } else { + + // fetch mode + if (url.len == 0) { + try std.io.getStdErr().writer().print(usage, .{execname}); + std.posix.exit(1); + } + + const vm = jsruntime.VM.init(); + defer vm.deinit(); + + var loop = try jsruntime.Loop.init(arena.allocator()); + defer loop.deinit(); + + var browser = Browser{}; + try Browser.init(&browser, alloc, &loop, vm); + defer browser.deinit(); + + const page = try browser.session.createPage(); + + _ = page.navigate(url, null) catch |err| switch (err) { + error.UnsupportedUriScheme, error.UriMissingHost => { + std.log.err("'{s}' is not a valid URL ({any})\n", .{ url, err }); + return printUsageExit(execname, 1); + }, + else => { + std.log.err("'{s}' fetching error ({any})s\n", .{ url, err }); + return printUsageExit(execname, 1); + }, + }; + + try page.wait(); + + if (dump) { + try page.dump(std.io.getStdOut()); + } + } } diff --git a/src/main_get.zig b/src/main_get.zig deleted file mode 100644 index 1607b95a..00000000 --- a/src/main_get.zig +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2023-2024 Lightpanda (Selecy SAS) -// -// Francis Bouvier -// Pierre Tachoire -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -const std = @import("std"); -const Browser = @import("browser/browser.zig").Browser; - -const jsruntime = @import("jsruntime"); -const apiweb = @import("apiweb.zig"); - -pub const Types = jsruntime.reflect(apiweb.Interfaces); -pub const UserContext = apiweb.UserContext; - -pub const std_options = std.Options{ - .log_level = .debug, -}; - -const usage = - \\usage: {s} [options] - \\ request the url with the browser - \\ - \\ -h, --help Print this help message and exit. - \\ --dump Dump document in stdout - \\ -; - -pub fn main() !void { - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer { - const check = gpa.deinit(); - if (check == .leak) { - std.log.warn("leaks detected\n", .{}); - } - } - const allocator = gpa.allocator(); - - var args = try std.process.argsWithAllocator(allocator); - defer args.deinit(); - - const execname = args.next().?; - var url: []const u8 = ""; - var dump: bool = false; - - while (args.next()) |arg| { - if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) { - try std.io.getStdErr().writer().print(usage, .{execname}); - std.posix.exit(0); - } - if (std.mem.eql(u8, "--dump", arg)) { - dump = true; - continue; - } - // allow only one url - if (url.len != 0) { - try std.io.getStdErr().writer().print(usage, .{execname}); - std.posix.exit(1); - } - url = arg; - } - - if (url.len == 0) { - try std.io.getStdErr().writer().print(usage, .{execname}); - std.posix.exit(1); - } - - const vm = jsruntime.VM.init(); - defer vm.deinit(); - - var loop = try jsruntime.Loop.init(allocator); - defer loop.deinit(); - - var browser = Browser{}; - try Browser.init(&browser, allocator, &loop, vm); - defer browser.deinit(); - - const page = try browser.session.createPage(); - - try page.navigate(url, null); - - try page.wait(); - - if (dump) { - try page.dump(std.io.getStdOut()); - } -}