browser: refactor session and page

Now session owns the js env and the loader.
page start and stop the js session.
This commit is contained in:
Pierre Tachoire
2023-12-20 18:00:50 +01:00
parent 228f44a57d
commit 6ff121334f
2 changed files with 71 additions and 73 deletions

View File

@@ -15,9 +15,13 @@ const Window = @import("../nav/window.zig").Window;
const log = std.log.scoped(.lpd_browser); const log = std.log.scoped(.lpd_browser);
// Browser is an instance of the browser.
// You can create multiple browser instances.
// It contains only one session but initVM() and deinitVM() must be called only
// once per main.
pub const Browser = struct { pub const Browser = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
session: Session = undefined, session: *Session = undefined,
var vm: jsruntime.VM = undefined; var vm: jsruntime.VM = undefined;
pub fn initVM() void { pub fn initVM() void {
@@ -27,74 +31,93 @@ pub const Browser = struct {
vm.deinit(); vm.deinit();
} }
pub fn init(allocator: std.mem.Allocator) Browser { pub fn init(allocator: std.mem.Allocator) !Browser {
var b = Browser{ .allocator = allocator }; return Browser{
b.session = try b.createSession(null); .allocator = allocator,
.session = try Session.init(allocator, "about:blank"),
return b; };
} }
pub fn deinit(self: *Browser) void { pub fn deinit(self: *Browser) void {
var session = self.session; self.session.deinit();
session.deinit(); self.allocator.destroy(self.session);
} }
pub fn currentSession(self: *Browser) *Session { pub fn currentSession(self: *Browser) *Session {
return &self.session; return self.session;
}
fn createSession(self: *Browser, uri: ?[]const u8) !Session {
return Session.init(self.allocator, uri orelse "about:blank");
} }
}; };
// Session is like a browser's tab.
// It owns the js env and the loader and an allocator arena for all the pages
// of the session.
// You can create successively multiple pages for a session, but you must
// deinit a page before running another one.
pub const Session = struct { pub const Session = struct {
allocator: std.mem.Allocator, arena: std.heap.ArenaAllocator,
uri: []const u8, uri: []const u8,
// TODO handle proxy tpls: [apis.len]TPL = undefined,
loader: Loader,
fn init(allocator: std.mem.Allocator, uri: []const u8) Session { // TODO handle proxy
return Session{ loader: Loader = undefined,
.allocator = allocator, env: Env = undefined,
loop: Loop = undefined,
fn init(allocator: std.mem.Allocator, uri: []const u8) !*Session {
var self = try allocator.create(Session);
self.* = Session{
.uri = uri, .uri = uri,
.loader = Loader.init(allocator), .arena = std.heap.ArenaAllocator.init(allocator),
}; };
const aallocator = self.arena.allocator();
self.loader = Loader.init(aallocator);
self.loop = try Loop.init(aallocator);
self.env = try Env.init(aallocator, &self.loop);
try self.env.load(apis, &self.tpls);
return self;
} }
fn deinit(self: *Session) void { fn deinit(self: *Session) void {
self.loader.deinit(); self.loader.deinit();
} self.loop.deinit();
self.env.deinit();
pub fn createPage(self: *Session) !Page {
return Page.init(self);
}
};
pub const Page = struct {
arena: std.heap.ArenaAllocator,
session: *Session,
env: Env,
fn init(session: *Session) Page {
return Page{
.session = session,
.arena = std.heap.ArenaAllocator.init(session.allocator),
.env = undefined,
};
}
pub fn deinit(self: *Page) void {
self.arena.deinit(); self.arena.deinit();
} }
pub fn navigate(self: *Page, uri: []const u8) !void { pub fn createPage(self: *Session) !Page {
const allocator = self.arena.allocator(); return Page.init(self.arena.allocator(), &self.loader, &self.env);
}
};
// Page navigates to an url.
// You can navigates multiple urls with the same page, but you have to call
// end() to stop the previous navigation before starting a new one.
pub const Page = struct {
allocator: std.mem.Allocator,
loader: *Loader,
env: *Env,
fn init(allocator: std.mem.Allocator, loader: *Loader, env: *Env) Page {
return Page{
.allocator = allocator,
.loader = loader,
.env = env,
};
}
pub fn end(self: *Page) void {
self.env.stop();
}
pub fn navigate(self: *Page, uri: []const u8) !void {
log.debug("starting GET {s}", .{uri}); log.debug("starting GET {s}", .{uri});
// load the data // load the data
var result = try self.session.loader.fetch(allocator, uri); var result = try self.loader.fetch(self.allocator, uri);
defer result.deinit(); defer result.deinit();
log.info("GET {s} {d}", .{ uri, result.status }); log.info("GET {s} {d}", .{ uri, result.status });
@@ -110,27 +133,12 @@ pub const Page = struct {
// document // document
log.debug("parse html", .{}); log.debug("parse html", .{});
const html_doc = try parser.documentHTMLParseFromStrAlloc(allocator, result.body.?); const html_doc = try parser.documentHTMLParseFromStrAlloc(self.allocator, result.body.?);
const doc = parser.documentHTMLToDocument(html_doc); const doc = parser.documentHTMLToDocument(html_doc);
log.debug("init loop", .{});
var loop = try Loop.init(allocator);
defer loop.deinit();
// create JS env
log.debug("init js env", .{});
self.env = try Env.init(allocator, &loop);
defer self.env.deinit();
// load APIs in JS env
log.debug("load js apis", .{});
var tpls: [apis.len]TPL = undefined;
try self.env.load(apis, &tpls);
// start JS env // start JS env
log.debug("start js env", .{}); log.debug("start js env", .{});
try self.env.start(allocator, apis); try self.env.start(self.allocator, apis);
defer self.env.stop();
// add global objects // add global objects
log.debug("setup global env", .{}); log.debug("setup global env", .{});
@@ -142,12 +150,3 @@ pub const Page = struct {
try self.env.addObject(apis, doc, "document"); try self.env.addObject(apis, doc, "document");
} }
}; };
test "create page" {
const allocator = std.testing.allocator;
var browser = Browser.init(allocator);
defer browser.deinit();
var page = try browser.currentSession().createPage();
defer page.deinit();
}

View File

@@ -50,11 +50,10 @@ pub fn main() !void {
Browser.initVM(); Browser.initVM();
defer Browser.deinitVM(); defer Browser.deinitVM();
var browser = Browser.init(allocator); var browser = try Browser.init(allocator);
defer browser.deinit(); defer browser.deinit();
var page = try browser.currentSession().createPage(); var page = try browser.currentSession().createPage();
defer page.deinit(); defer page.end();
try page.navigate(url); try page.navigate(url);
} }