@@ -67,6 +67,7 @@ client: *Http.Client,
6767allocator : Allocator ,
6868buffer_pool : BufferPool ,
6969script_pool : std .heap .MemoryPool (PendingScript ),
70+ async_module_pool : std .heap .MemoryPool (AsyncModule ),
7071
7172const OrderList = std .DoublyLinkedList ;
7273
@@ -85,13 +86,15 @@ pub fn init(browser: *Browser, page: *Page) ScriptManager {
8586 .static_scripts_done = false ,
8687 .buffer_pool = BufferPool .init (allocator , 5 ),
8788 .script_pool = std .heap .MemoryPool (PendingScript ).init (allocator ),
89+ .async_module_pool = std .heap .MemoryPool (AsyncModule ).init (allocator ),
8890 };
8991}
9092
9193pub fn deinit (self : * ScriptManager ) void {
9294 self .reset ();
9395 self .buffer_pool .deinit ();
9496 self .script_pool .deinit ();
97+ self .async_module_pool .deinit ();
9598}
9699
97100pub fn reset (self : * ScriptManager ) void {
@@ -257,7 +260,7 @@ pub fn addFromElement(self: *ScriptManager, element: *parser.Element) !void {
257260// Unlike external modules which can only ever be executed after releasing an
258261// http handle, these are executed without there necessarily being a free handle.
259262// Thus, Http/Client.zig maintains a dedicated handle for these calls.
260- pub fn blockingGet (self : * ScriptManager , url : [:0 ]const u8 ) ! BlockingResult {
263+ pub fn blockingGet (self : * ScriptManager , url : [:0 ]const u8 ) ! GetResult {
261264 std .debug .assert (self .is_blocking == false );
262265
263266 self .is_blocking = true ;
@@ -303,6 +306,34 @@ pub fn blockingGet(self: *ScriptManager, url: [:0]const u8) !BlockingResult {
303306 }
304307}
305308
309+ pub fn getAsyncModule (self : * ScriptManager , url : [:0 ]const u8 , cb : AsyncModule.Callback , cb_data : * anyopaque ) ! void {
310+ const async = try self .async_module_pool .create ();
311+ errdefer self .async_module_pool .destroy (async );
312+
313+ async .* = .{
314+ .cb = cb ,
315+ .manager = self ,
316+ .cb_data = cb_data ,
317+ };
318+
319+ var headers = try self .client .newHeaders ();
320+ try self .page .requestCookie (.{}).headersForRequest (self .page .arena , url , & headers );
321+
322+ try self .client .request (.{
323+ .url = url ,
324+ .method = .GET ,
325+ .headers = headers ,
326+ .cookie_jar = self .page .cookie_jar ,
327+ .ctx = async ,
328+ .resource_type = .script ,
329+ .start_callback = if (log .enabled (.http , .debug )) AsyncModule .startCallback else null ,
330+ .header_callback = AsyncModule .headerCallback ,
331+ .data_callback = AsyncModule .dataCallback ,
332+ .done_callback = AsyncModule .doneCallback ,
333+ .error_callback = AsyncModule .errorCallback ,
334+ });
335+ }
336+
306337pub fn staticScriptsDone (self : * ScriptManager ) void {
307338 std .debug .assert (self .static_scripts_done == false );
308339 self .static_scripts_done = true ;
@@ -595,7 +626,7 @@ const Script = struct {
595626 .javascript = > _ = js_context .eval (content , url ) catch break :blk false ,
596627 .module = > {
597628 // We don't care about waiting for the evaluation here.
598- _ = js_context .module (content , url , cacheable ) catch break :blk false ;
629+ js_context .module (false , content , url , cacheable ) catch break :blk false ;
599630 },
600631 }
601632 break :blk true ;
@@ -761,7 +792,7 @@ const Blocking = struct {
761792 const State = union (enum ) {
762793 running : void ,
763794 err : anyerror ,
764- done : BlockingResult ,
795+ done : GetResult ,
765796 };
766797
767798 fn startCallback (transfer : * Http.Transfer ) ! void {
@@ -815,19 +846,93 @@ const Blocking = struct {
815846 fn errorCallback (ctx : * anyopaque , err : anyerror ) void {
816847 var self : * Blocking = @ptrCast (@alignCast (ctx ));
817848 self .state = .{ .err = err };
818- self .buffer_pool .release (self .buffer );
849+ if (self .buffer .items .len > 0 ) {
850+ self .buffer_pool .release (self .buffer );
851+ }
852+ }
853+ };
854+
855+ pub const AsyncModule = struct {
856+ cb : Callback ,
857+ cb_data : * anyopaque ,
858+ manager : * ScriptManager ,
859+ buffer : std .ArrayListUnmanaged (u8 ) = .{},
860+
861+ pub const Callback = * const fn (ptr : * anyopaque , result : anyerror ! GetResult ) void ;
862+
863+ fn startCallback (transfer : * Http.Transfer ) ! void {
864+ log .debug (.http , "script fetch start" , .{ .req = transfer , .async = true });
865+ }
866+
867+ fn headerCallback (transfer : * Http.Transfer ) ! void {
868+ const header = & transfer .response_header .? ;
869+ log .debug (.http , "script header" , .{
870+ .req = transfer ,
871+ .async = true ,
872+ .status = header .status ,
873+ .content_type = header .contentType (),
874+ });
875+
876+ if (header .status != 200 ) {
877+ return error .InvalidStatusCode ;
878+ }
879+
880+ var self : * AsyncModule = @ptrCast (@alignCast (transfer .ctx ));
881+ self .buffer = self .manager .buffer_pool .get ();
882+ }
883+
884+ fn dataCallback (transfer : * Http.Transfer , data : []const u8 ) ! void {
885+ // too verbose
886+ // log.debug(.http, "script data chunk", .{
887+ // .req = transfer,
888+ // .blocking = true,
889+ // });
890+
891+ var self : * AsyncModule = @ptrCast (@alignCast (transfer .ctx ));
892+ self .buffer .appendSlice (self .manager .allocator , data ) catch | err | {
893+ log .err (.http , "SM.dataCallback" , .{
894+ .err = err ,
895+ .len = data .len ,
896+ .ascyn = true ,
897+ .transfer = transfer ,
898+ });
899+ return err ;
900+ };
901+ }
902+
903+ fn doneCallback (ctx : * anyopaque ) ! void {
904+ var self : * AsyncModule = @ptrCast (@alignCast (ctx ));
905+ defer self .manager .async_module_pool .destroy (self );
906+ self .cb (self .cb_data , .{
907+ .buffer = self .buffer ,
908+ .buffer_pool = & self .manager .buffer_pool ,
909+ });
910+ }
911+
912+ fn errorCallback (ctx : * anyopaque , err : anyerror ) void {
913+ var self : * AsyncModule = @ptrCast (@alignCast (ctx ));
914+
915+ if (err != error .Abort ) {
916+ self .cb (self .cb_data , err );
917+ }
918+
919+ if (self .buffer .items .len > 0 ) {
920+ self .manager .buffer_pool .release (self .buffer );
921+ }
922+
923+ self .manager .async_module_pool .destroy (self );
819924 }
820925};
821926
822- pub const BlockingResult = struct {
927+ pub const GetResult = struct {
823928 buffer : std .ArrayListUnmanaged (u8 ),
824929 buffer_pool : * BufferPool ,
825930
826- pub fn deinit (self : * BlockingResult ) void {
931+ pub fn deinit (self : * GetResult ) void {
827932 self .buffer_pool .release (self .buffer );
828933 }
829934
830- pub fn src (self : * const BlockingResult ) []const u8 {
935+ pub fn src (self : * const GetResult ) []const u8 {
831936 return self .buffer .items ;
832937 }
833938};
0 commit comments