ops: Allow serving both cdp and bidi on the same port

--protocol can now be specified multiple times. This just makes ops/dev easier
by only requiring 1 instance.
This commit is contained in:
Karl Seguin committed 2026-08-31 22:45:15 +08:00
1 parent 766c0d05d6
commit 731774ab67
7 files changed
+30 -19

No files matched your search

+1 -2
View File
@@ -116,8 +116,7 @@ jobs:
echo "value=$args" >> "$GITHUB_OUTPUT"
- run: |
./lightpanda serve --port 9222 --protocol cdp ${{ steps.args.outputs.value }} &
./lightpanda serve --port 9223 --protocol webdriver ${{ steps.args.outputs.value }} &
./lightpanda serve --port 9222 --protocol cdp --protocol webdriver ${{ steps.args.outputs.value }} &
- run: |
go run runner/main.go
+5 -4
View File
@@ -386,7 +386,8 @@ const Commands = cli.Builder(.{
.{ .name = "host", .type = []const u8, .default = "127.0.0.1" },
.{ .name = "port", .type = u16, .default = 9222 },
.{ .name = "advertise_host", .type = ?[]const u8 },
.{ .name = "protocol", .type = Protocol, .default = Protocol.cdp },
// Repeatable; one server can speak several on the same port.
.{ .name = "protocol", .type = Protocol, .multiple = true },
.{ .name = "cdp_max_connections", .type = u16, .default = 16 },
.{ .name = "cdp_max_pending_connections", .type = u16, .default = 128 },
.{ .name = "cdp_max_message_size", .type = u32, .default = 1024 * 1024 },
@@ -827,10 +828,10 @@ pub const Protocol = enum {
webdriver,
};
pub fn protocol(self: *const Config) Protocol {
pub fn protocols(self: *const Config) []const Protocol {
return switch (self.mode) {
.serve => |opts| opts.protocol,
.mcp => .cdp,
.serve => |opts| if (opts.protocol.items.len == 0) &.{.cdp} else opts.protocol.items,
.mcp => &.{.cdp},
else => unreachable,
};
}
+1 -1
View File
@@ -18,7 +18,7 @@
// Synthetic user input driving the DOM: mouse, wheel, keyboard, focus
// navigation and text insertion. These are mostly fed by CDP's Input domain
// (src/cdp/domains/input.zig) and by EventManager's default activation
// (src/server/cdp/domains/input.zig) and by EventManager's default activation
// behavior. Form submission itself lives on the Frame (it's a navigation
// concern); the activation paths here call into it.
-1
View File
@@ -21,7 +21,6 @@ const lp = @import("lightpanda");
const zenai = @import("zenai");
const NodeRegistry = @import("../NodeRegistry.zig");
const LimitedWriter = @import("../LimitedWriter.zig");
const DOMNode = @import("webapi/Node.zig");
const Selector = @import("webapi/selector/Selector.zig");
+8
View File
@@ -48,6 +48,14 @@
\\ --port <INT>
\\ Port of the CDP server.
\\ Defaults to 9222.
\\ --protocol <PROTOCOL>
\\ Automation protocol to serve. Can be passed multiple times to
\\ serve several on the same port.
\\ Defaults to cdp.
\\ Allowed values:
\\ cdp Chrome DevTools Protocol (WebSocket on /).
\\ webdriver WebDriver BiDi (WebSocket on /session) plus the
\\ classic WebDriver session endpoints.
,
.fetch =
\\usage: {0s} fetch <url>... [OPTIONS] [COMMON_OPTIONS]
+8 -5
View File
@@ -160,6 +160,12 @@ pub fn init(app: *App, address: sys_net.IpAddress) !*Server {
const bidi_session_url = try std.fmt.allocPrint(allocator, "ws://{s}:{d}/session/", .{ app.config.advertiseHost(), port });
errdefer allocator.free(bidi_session_url);
var protocols: Handshake.Protocols = .{};
for (app.config.protocols()) |p| switch (p) {
.cdp => protocols.cdp = true,
.webdriver => protocols.webdriver = true,
};
self.* = .{
.app = app,
.cdp_pool = .empty,
@@ -170,10 +176,7 @@ pub fn init(app: *App, address: sys_net.IpAddress) !*Server {
.pollfds = pollfds,
.wakeup_pipe = pipe,
.poll_snapshot = poll_snapshot,
.protocols = switch (app.config.protocol()) {
.cdp => .{ .cdp = true },
.webdriver => .{ .webdriver = true },
},
.protocols = protocols,
};
return self;
}
@@ -1468,7 +1471,7 @@ test "server: classic session bootstrap errors" {
}
test "server: protocol gate" {
// The test server serves both; the CLI only ever enables one.
// The test server serves both; --protocol picks which a real server does.
const protocols = &testing.test_cdp_server.?.protocols;
defer protocols.* = .{ .cdp = true, .webdriver = true };
+7 -6
View File
@@ -484,12 +484,13 @@ pub const Serializer = struct {
defer self.unsee();
const next_depth = depth + 1;
var names = try object.nameIterator();
var list: std.ArrayList(Property) = try .initCapacity(self.arena, names.count);
while (try names.next()) |name| {
const owned = try self.arena.dupe(u8, name);
const value = try object.get(owned);
list.appendAssumeCapacity(.{ .name = owned, .value = try self.remote(value, next_depth, false) });
var it = try object.iterator();
var list: std.ArrayList(Property) = try .initCapacity(self.arena, it.count);
while (try it.next()) |entry| {
list.appendAssumeCapacity(.{
.name = try self.arena.dupe(u8, entry.name),
.value = try self.remote(entry.value, next_depth, false),
});
}
return list.items;
}