From 486c19079ad9bb281a3a4f8a98f1abbd40f977de Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Fri, 18 Oct 2024 16:06:23 +0200 Subject: [PATCH 1/3] 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()); - } -} From 46d0aa6f9e438e2c28e05c267de279c3e2201023 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Tue, 29 Oct 2024 22:16:56 +0100 Subject: [PATCH 2/3] Remove all references to the name 'browsercore' Signed-off-by: Francis Bouvier --- .github/workflows/build.yml | 4 ++-- Makefile | 2 +- build.zig | 6 +++--- src/main_shell.zig | 2 +- src/main_wpt.zig | 2 +- src/run_tests.zig | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ee27521..13c55252 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: run: zig build --release=safe -Doptimize=ReleaseSafe -Dengine=v8 -Dcpu=x86_64 - name: Rename binary - run: mv zig-out/bin/browsercore lightpanda-${{ env.ARCH }}-${{ env.OS }} + run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }} - name: Upload the build uses: ncipollo/release-action@v1 @@ -65,7 +65,7 @@ jobs: run: zig build --release=safe -Doptimize=ReleaseSafe -Dengine=v8 - name: Rename binary - run: mv zig-out/bin/browsercore-get lightpanda-${{ env.ARCH }}-${{ env.OS }} + run: mv zig-out/bin/lightpanda lightpanda-${{ env.ARCH }}-${{ env.OS }} - name: Upload the build uses: ncipollo/release-action@v1 diff --git a/Makefile b/Makefile index c14e5cdb..0ca915b9 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ build-dev: ## Run the server in debug mode run: build @printf "\e[36mRunning...\e[0m\n" - @./zig-out/bin/browsercore || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;) + @./zig-out/bin/lightpanda || (printf "\e[33mRun ERROR\e[0m\n"; exit 1;) ## Run a JS shell in debug mode shell: diff --git a/build.zig b/build.zig index d5638a1b..364c24cf 100644 --- a/build.zig +++ b/build.zig @@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void { // compile and install const exe = b.addExecutable(.{ - .name = "browsercore", + .name = "lightpanda", .root_source_file = b.path("src/main.zig"), .target = target, .optimize = mode, @@ -75,7 +75,7 @@ pub fn build(b: *std.Build) !void { // compile and install const shell = b.addExecutable(.{ - .name = "browsercore-shell", + .name = "lightpanda-shell", .root_source_file = b.path("src/main_shell.zig"), .target = target, .optimize = mode, @@ -124,7 +124,7 @@ pub fn build(b: *std.Build) !void { // compile and install const wpt = b.addExecutable(.{ - .name = "browsercore-wpt", + .name = "lightpanda-wpt", .root_source_file = b.path("src/main_wpt.zig"), .target = target, .optimize = mode, diff --git a/src/main_shell.zig b/src/main_shell.zig index 9e2510d9..fbb23660 100644 --- a/src/main_shell.zig +++ b/src/main_shell.zig @@ -87,5 +87,5 @@ pub fn main() !void { defer vm.deinit(); // launch shell - try jsruntime.shell(&arena, execJS, .{ .app_name = "browsercore" }); + try jsruntime.shell(&arena, execJS, .{ .app_name = "lightpanda-shell" }); } diff --git a/src/main_wpt.zig b/src/main_wpt.zig index 7a774fcc..49b7ba23 100644 --- a/src/main_wpt.zig +++ b/src/main_wpt.zig @@ -54,7 +54,7 @@ pub const UserContext = apiweb.UserContext; // TODO For now the WPT tests run is specific to WPT. // It manually load js framwork libs, and run the first script w/ js content in // the HTML page. -// Once browsercore will have the html loader, it would be useful to refacto +// Once lightpanda will have the html loader, it would be useful to refacto // this test to use it. pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; diff --git a/src/run_tests.zig b/src/run_tests.zig index d3f8fb99..a56d76dd 100644 --- a/src/run_tests.zig +++ b/src/run_tests.zig @@ -283,7 +283,7 @@ fn run_js(out: Out) !void { const row_shape = .{ []const u8, pretty.Measure, u64, u64, pretty.Measure }; const table = try pretty.GenerateTable(4, row_shape, pretty.TableConf{ .margin_left = " " }); const header = .{ "FUNCTION", "DURATION", "ALLOCATIONS (nb)", "RE-ALLOCATIONS (nb)", "HEAP SIZE" }; - var t = table.init("Benchmark browsercore 🚀", header); + var t = table.init("Benchmark lightpanda 🚀", header); try t.addRow(.{ "browser", dur, stats.alloc_nb, stats.realloc_nb, size }); try t.addRow(.{ "libdom", dur, 0, 0, zerosize }); // TODO get libdom bench info. try t.addRow(.{ "v8", dur, 0, 0, zerosize }); // TODO get v8 bench info. From cf0636ca635a32f4a6ac7cbad33ebdc4ea44ddc3 Mon Sep 17 00:00:00 2001 From: Francis Bouvier Date: Tue, 29 Oct 2024 22:19:44 +0100 Subject: [PATCH 3/3] Update src/main.zig usage Co-authored-by: Pierre Tachoire --- src/main.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index 91233b68..70ddb412 100644 --- a/src/main.zig +++ b/src/main.zig @@ -36,7 +36,7 @@ const Port = 3245; const Timeout = 3; // in seconds const usage = - \\usage: {s} [options] + \\usage: {s} [options] [URL] \\ \\ start Lightpanda browser \\