Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/lightpanda 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:
Expand All @@ -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/lightpanda 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
28 changes: 3 additions & 25 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down
145 changes: 109 additions & 36 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -38,13 +36,18 @@ const Port = 3245;
const Timeout = 3; // in seconds

const usage =
\\usage: {s} [options]
\\ start Lightpanda browser in CDP server mode
\\usage: {s} [options] [URL]
\\
\\ 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)
\\
;

Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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();

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 });
if (server_mode) {

// 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();

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();

// listen
try server.listen(arena.allocator(), &loop, srv.sockfd.?, std.time.ns_per_s * @as(u64, timeout));
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());
}
}
}
Loading